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));