use associated types for Slice

This is more readable; in particular, it avoids the need for awkward the
PhantomData in the Slices struct.
This commit is contained in:
Scott Lamb 2017-02-25 18:54:52 -08:00
parent 2d0c78a6d8
commit 21212be18a
2 changed files with 18 additions and 16 deletions

View File

@ -421,7 +421,7 @@ pub struct FileBuilder {
/// This is separated out from the rest so that it can be borrowed in a loop over /// This is separated out from the rest so that it can be borrowed in a loop over
/// `FileBuilder::segments`; otherwise this would cause a double-self-borrow. /// `FileBuilder::segments`; otherwise this would cause a double-self-borrow.
struct BodyState { struct BodyState {
slices: Slices<Slice, File>, slices: Slices<Slice>,
/// `self.buf[unflushed_buf_pos .. self.buf.len()]` holds bytes that should be /// `self.buf[unflushed_buf_pos .. self.buf.len()]` holds bytes that should be
/// appended to `slices` before any other slice. See `flush_buf()`. /// appended to `slices` before any other slice. See `flush_buf()`.
@ -477,7 +477,9 @@ impl Slice {
fn p(&self) -> usize { (self.0 >> 44) as usize } fn p(&self) -> usize { (self.0 >> 44) as usize }
} }
impl slices::Slice<File> for Slice { impl slices::Slice for Slice {
type Ctx = File;
fn end(&self) -> u64 { return self.0 & 0xFF_FF_FF_FF_FF } fn end(&self) -> u64 { return self.0 & 0xFF_FF_FF_FF_FF }
fn write_to(&self, f: &File, r: Range<u64>, l: u64, out: &mut io::Write) fn write_to(&self, f: &File, r: Range<u64>, l: u64, out: &mut io::Write)
-> Result<(), Error> { -> Result<(), Error> {
@ -1114,7 +1116,7 @@ pub struct File {
db: Arc<db::Database>, db: Arc<db::Database>,
dir: Arc<dir::SampleFileDir>, dir: Arc<dir::SampleFileDir>,
segments: Vec<Segment>, segments: Vec<Segment>,
slices: Slices<Slice, File>, slices: Slices<Slice>,
buf: Vec<u8>, buf: Vec<u8>,
video_sample_entries: SmallVec<[Arc<db::VideoSampleEntry>; 1]>, video_sample_entries: SmallVec<[Arc<db::VideoSampleEntry>; 1]>,
initial_sample_byte_pos: u64, initial_sample_byte_pos: u64,

View File

@ -33,12 +33,13 @@
use error::{Error, Result}; use error::{Error, Result};
use std::fmt; use std::fmt;
use std::io; use std::io;
use std::marker::PhantomData;
use std::ops::Range; use std::ops::Range;
/// Writes a byte range to the given `io::Write` given a context argument; meant for use with /// Writes a byte range to the given `io::Write` given a context argument; meant for use with
/// `Slices`. /// `Slices`.
pub trait Slice<Ctx> { pub trait Slice {
type Ctx;
/// The byte position (relative to the start of the `Slices`) beyond the end of this slice. /// The byte position (relative to the start of the `Slices`) beyond the end of this slice.
/// Note the starting position (and thus length) are inferred from the previous slice. /// Note the starting position (and thus length) are inferred from the previous slice.
fn end(&self) -> u64; fn end(&self) -> u64;
@ -46,7 +47,7 @@ pub trait Slice<Ctx> {
/// Writes `r` to `out`, as in `http_entity::Entity::write_to`. /// Writes `r` to `out`, as in `http_entity::Entity::write_to`.
/// The additional argument `ctx` is as supplied to the `Slices`. /// The additional argument `ctx` is as supplied to the `Slices`.
/// The additional argument `l` is the length of this slice, as determined by the `Slices`. /// The additional argument `l` is the length of this slice, as determined by the `Slices`.
fn write_to(&self, ctx: &Ctx, r: Range<u64>, l: u64, out: &mut io::Write) -> Result<()>; fn write_to(&self, ctx: &Self::Ctx, r: Range<u64>, l: u64, out: &mut io::Write) -> Result<()>;
} }
/// Calls `f` with an `io::Write` which delegates to `inner` only for the section defined by `r`. /// Calls `f` with an `io::Write` which delegates to `inner` only for the section defined by `r`.
@ -66,7 +67,7 @@ where F: FnMut(&mut Vec<u8>) -> Result<()> {
/// Helper to serve byte ranges from a body which is broken down into many "slices". /// Helper to serve byte ranges from a body which is broken down into many "slices".
/// This is used to implement `.mp4` serving in `mp4::Mp4File` from `mp4::Slice` enums. /// This is used to implement `.mp4` serving in `mp4::Mp4File` from `mp4::Slice` enums.
pub struct Slices<S, C> where S: Slice<C> { pub struct Slices<S> where S: Slice {
/// The total byte length of the `Slices`. /// The total byte length of the `Slices`.
/// Equivalent to `self.slices.back().map(|s| s.end()).unwrap_or(0)`; kept for convenience and /// Equivalent to `self.slices.back().map(|s| s.end()).unwrap_or(0)`; kept for convenience and
/// to avoid a branch. /// to avoid a branch.
@ -74,12 +75,9 @@ pub struct Slices<S, C> where S: Slice<C> {
/// 0 or more slices of this file. /// 0 or more slices of this file.
slices: Vec<S>, slices: Vec<S>,
/// Marker so that `C` is part of the type.
phantom: PhantomData<C>,
} }
impl<S, C> fmt::Debug for Slices<S, C> where S: fmt::Debug + Slice<C> { impl<S> fmt::Debug for Slices<S> where S: fmt::Debug + Slice {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} slices with overall length {}:", self.slices.len(), self.len)?; write!(f, "{} slices with overall length {}:", self.slices.len(), self.len)?;
let mut start = 0; let mut start = 0;
@ -93,8 +91,8 @@ impl<S, C> fmt::Debug for Slices<S, C> where S: fmt::Debug + Slice<C> {
} }
} }
impl<S, C> Slices<S, C> where S: Slice<C> { impl<S> Slices<S> where S: Slice {
pub fn new() -> Self { Slices{len: 0, slices: Vec::new(), phantom: PhantomData} } pub fn new() -> Self { Slices{len: 0, slices: Vec::new()} }
/// Reserves space for at least `additional` more slices to be appended. /// Reserves space for at least `additional` more slices to be appended.
pub fn reserve(&mut self, additional: usize) { pub fn reserve(&mut self, additional: usize) {
@ -116,7 +114,7 @@ impl<S, C> Slices<S, C> where S: Slice<C> {
/// Writes `range` to `out`. /// Writes `range` to `out`.
/// This interface mirrors `http_entity::Entity::write_to`, with the additional `ctx` argument. /// This interface mirrors `http_entity::Entity::write_to`, with the additional `ctx` argument.
pub fn write_to(&self, ctx: &C, range: Range<u64>, out: &mut io::Write) -> Result<()> { pub fn write_to(&self, ctx: &S::Ctx, range: Range<u64>, out: &mut io::Write) -> Result<()> {
if range.start > range.end || range.end > self.len { if range.start > range.end || range.end > self.len {
return Err(Error{ return Err(Error{
description: format!("Bad range {:?} for slice of length {}", range, self.len), description: format!("Bad range {:?} for slice of length {}", range, self.len),
@ -174,7 +172,9 @@ mod tests {
name: &'static str, name: &'static str,
} }
impl Slice<RefCell<Vec<FakeWrite>>> for FakeSlice { impl Slice for FakeSlice {
type Ctx = RefCell<Vec<FakeWrite>>;
fn end(&self) -> u64 { self.end } fn end(&self) -> u64 { self.end }
fn write_to(&self, ctx: &RefCell<Vec<FakeWrite>>, r: Range<u64>, _l: u64, _out: &mut Write) fn write_to(&self, ctx: &RefCell<Vec<FakeWrite>>, r: Range<u64>, _l: u64, _out: &mut Write)
@ -184,7 +184,7 @@ mod tests {
} }
} }
pub fn new_slices() -> Slices<FakeSlice, RefCell<Vec<FakeWrite>>> { pub fn new_slices() -> Slices<FakeSlice> {
let mut s = Slices::new(); let mut s = Slices::new();
s.append(FakeSlice{end: 5, name: "a"}); s.append(FakeSlice{end: 5, name: "a"});
s.append(FakeSlice{end: 5+13, name: "b"}); s.append(FakeSlice{end: 5+13, name: "b"});