From cdcff869aae691b809a2abf80a301e36db77db5b Mon Sep 17 00:00:00 2001 From: Tangent 128 <Tangent128@gmail.com> Date: Sun, 25 Mar 2018 21:33:38 -0400 Subject: [PATCH] Replace Schema types with a FromEbml trait on the Element type simplify lifetimes --- src/bin/dump.rs | 6 ++---- src/bin/loop_server.rs | 5 ++--- src/bin/resynth.rs | 3 +-- src/ebml.rs | 39 ++++++++++++++++++++------------------- src/iterator.rs | 27 ++++++++++++++------------- src/lib.rs | 2 +- src/webm.rs | 15 ++++++++------- 7 files changed, 48 insertions(+), 49 deletions(-) diff --git a/src/bin/dump.rs b/src/bin/dump.rs index 8e5d333..096b42d 100644 --- a/src/bin/dump.rs +++ b/src/bin/dump.rs @@ -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()), diff --git a/src/bin/loop_server.rs b/src/bin/loop_server.rs index 2d9a27e..d2f18e8 100644 --- a/src/bin/loop_server.rs +++ b/src/bin/loop_server.rs @@ -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), diff --git a/src/bin/resynth.rs b/src/bin/resynth.rs index acaef39..fe71fe5 100644 --- a/src/bin/resynth.rs +++ b/src/bin/resynth.rs @@ -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 diff --git a/src/ebml.rs b/src/ebml.rs index 8a5ab78..e0930e1 100644 --- a/src/ebml.rs +++ b/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)))); } } diff --git a/src/iterator.rs b/src/iterator.rs index 4283252..de7c961 100644 --- a/src/iterator.rs +++ b/src/iterator.rs @@ -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))) => { diff --git a/src/lib.rs b/src/lib.rs index 4f689c5..635ee82 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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 { diff --git a/src/webm.rs b/src/webm.rs index 3123977..39410ba 100644 --- a/src/webm.rs +++ b/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));