Fix build on latest rust.

This commit is contained in:
Paul Lietar 2015-09-01 13:20:37 +02:00
parent ab7b5ba69d
commit 267ccbe65e
14 changed files with 292 additions and 258 deletions

197
Cargo.lock generated
View file

@ -2,27 +2,51 @@
name = "librespot"
version = "0.1.0"
dependencies = [
"byteorder 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"bit-set 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy 0.0.12 (git+https://github.com/Manishearth/rust-clippy.git)",
"eventual 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
"librespot-protocol 0.1.0",
"mod_path 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
"portaudio 0.1.2 (git+https://github.com/mvdnes/portaudio-rs)",
"protobuf 1.0.1 (git+https://github.com/plietar/rust-protobuf.git)",
"protobuf_macros 0.1.0 (git+https://github.com/plietar/rust-protobuf-macros.git)",
"rand 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"readall 0.1.0 (git+https://github.com/plietar/rust-readall.git)",
"rand 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
"rpassword 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-crypto 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-gmp 0.2.0 (git+https://github.com/plietar/rust-gmp.git)",
"shannon 0.1.0 (git+https://github.com/plietar/rust-shannon.git)",
"tempfile 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
"vergen 0.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
"vorbis 0.0.11 (git+https://github.com/plietar/vorbis-rs)",
"tempfile 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"vergen 0.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
"vorbis 0.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "advapi32-sys"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bit-set"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bit-vec 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bit-vec"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
version = "0.1.1"
@ -35,39 +59,55 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "0.3.11"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "gcc"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
name = "clippy"
version = "0.0.12"
source = "git+https://github.com/Manishearth/rust-clippy.git#d3da9f6c81dd3e026bd679c09cea1d6b337ccd25"
[[package]]
name = "getopts"
version = "0.2.11"
name = "eventual"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syncbox 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "kernel32-sys"
version = "0.1.2"
name = "gcc"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "getopts"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "kernel32-sys"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "0.1.11"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.1.8"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -80,10 +120,10 @@ dependencies = [
[[package]]
name = "log"
version = "0.3.1"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -93,11 +133,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "num"
version = "0.1.25"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -105,8 +145,8 @@ name = "ogg-sys"
version = "0.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -121,7 +161,7 @@ version = "0.1.2"
source = "git+https://github.com/mvdnes/portaudio-rs#7c6d10f5edda0094cc33b682d88c3a6ea4919b9f"
dependencies = [
"bitflags 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"portaudio_sys 0.1.0 (git+https://github.com/mvdnes/portaudio-rs)",
]
@ -130,7 +170,7 @@ name = "portaudio_sys"
version = "0.1.0"
source = "git+https://github.com/mvdnes/portaudio-rs#7c6d10f5edda0094cc33b682d88c3a6ea4919b9f"
dependencies = [
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -142,14 +182,16 @@ source = "git+https://github.com/plietar/rust-protobuf.git#dae87e292a52a66da7f78
[[package]]
name = "protobuf_macros"
version = "0.1.0"
source = "git+https://github.com/plietar/rust-protobuf-macros.git#3b49de3937a34b7a21be1d13caea4348a93c6de4"
source = "git+https://github.com/plietar/rust-protobuf-macros.git#2b6a8129e015945300cb2bb7efae2ed78042ed48"
[[package]]
name = "rand"
version = "0.3.8"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"advapi32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -162,10 +204,10 @@ name = "rpassword"
version = "0.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"termios 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -173,24 +215,24 @@ name = "rust-crypto"
version = "0.2.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rust-gmp"
version = "0.2.0"
source = "git+https://github.com/plietar/rust-gmp.git#cc003c224559f6035cd34a7ed5c6284a49785816"
source = "git+https://github.com/plietar/rust-gmp.git#d1bb4448fdbfa2505edadb83b6aac6257fe08ba2"
dependencies = [
"num 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-serialize"
version = "0.3.15"
version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -198,7 +240,7 @@ name = "shannon"
version = "0.1.0"
source = "git+https://github.com/plietar/rust-shannon.git#c6be8a879a523a77d81c50df46faa891b76fea25"
dependencies = [
"byteorder 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
"readall 0.1.0 (git+https://github.com/plietar/rust-readall.git)",
"shannon-sys 0.1.0 (git+https://github.com/plietar/rust-shannon.git)",
]
@ -208,18 +250,27 @@ name = "shannon-sys"
version = "0.1.0"
source = "git+https://github.com/plietar/rust-shannon.git#c6be8a879a523a77d81c50df46faa891b76fea25"
dependencies = [
"gcc 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syncbox"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tempfile"
version = "1.0.0"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -227,34 +278,34 @@ name = "termios"
version = "0.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "time"
version = "0.1.30"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "vergen"
version = "0.0.13"
version = "0.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "vorbis"
version = "0.0.11"
source = "git+https://github.com/plietar/vorbis-rs#78058c3341832969030f49cbc4b8bc9deb376776"
version = "0.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"vorbis-sys 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"vorbisfile-sys 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -265,8 +316,8 @@ name = "vorbis-sys"
version = "0.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -276,8 +327,8 @@ name = "vorbisfile-sys"
version = "0.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"vorbis-sys 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -285,19 +336,11 @@ dependencies = [
[[package]]
name = "winapi"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-build"
version = "0.1.0"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"

View file

@ -16,17 +16,22 @@ path = "src/main.rs"
path = "protocol"
[dependencies]
mod_path = "*"
byteorder = "*"
num = "*"
rand = "*"
lazy_static = "0.1.*"
rust-crypto = "*"
time = "*"
tempfile = "*"
rpassword = "*"
getopts = "0.2.4"
bit-set = "~0.2.0"
byteorder = "~0.3.13"
eventual = "~0.1.4"
getopts = "~0.2.14"
lazy_static = "~0.1.14"
mod_path = "~0.1.5"
num = "~0.1.27"
rand = "~0.3.11"
rpassword = "~0.0.5"
rust-crypto = "~0.2.31"
time = "~0.1.32"
tempfile = "~1.1.1"
vorbis = "~0.0.12"
[dependencies.clippy]
git = "https://github.com/Manishearth/rust-clippy.git"
[dependencies.protobuf]
git = "https://github.com/plietar/rust-protobuf.git"
[dependencies.protobuf_macros]
@ -35,12 +40,9 @@ git = "https://github.com/plietar/rust-protobuf-macros.git"
git = "https://github.com/plietar/rust-gmp.git"
[dependencies.shannon]
git = "https://github.com/plietar/rust-shannon.git"
[dependencies.readall]
git = "https://github.com/plietar/rust-readall.git"
[dependencies.portaudio]
git = "https://github.com/mvdnes/portaudio-rs"
[dependencies.vorbis]
git = "https://github.com/plietar/vorbis-rs"
[build-dependencies]
vergen = "*"
vergen = "~0.0.16"

View file

@ -1,6 +1,6 @@
use bit_set::BitSet;
use byteorder::{ByteOrder, BigEndian};
use std::cmp::min;
use std::collections::BitSet;
use std::sync::{Arc, Condvar, Mutex};
use std::sync::mpsc::{self, TryRecvError};
use std::thread;
@ -9,27 +9,24 @@ use std::io::{self, Read, Write, Seek, SeekFrom};
use std::path::PathBuf;
use tempfile::TempFile;
use stream::StreamEvent;
use util::{FileId, IgnoreExt, ZeroFile, mkdir_existing};
use session::Session;
use stream::StreamEvent;
const CHUNK_SIZE : usize = 0x20000;
pub enum AudioFile<'s> {
pub enum AudioFile {
Direct(fs::File),
Loading(AudioFileLoading<'s>)
Loading(AudioFileLoading)
}
pub struct AudioFileLoading<'s> {
pub struct AudioFileLoading {
read_file: TempFile,
position: u64,
seek: mpsc::Sender<u64>,
shared: Arc<AudioFileShared>,
#[allow(dead_code)]
thread: thread::JoinGuard<'s, ()>,
}
struct AudioFileShared {
@ -40,7 +37,7 @@ struct AudioFileShared {
bitmap: Mutex<BitSet>,
}
impl <'s> AudioFileLoading<'s> {
impl AudioFileLoading {
fn new(session: &Session, file_id: FileId) -> AudioFileLoading {
let mut files_iter = TempFile::shared(2).unwrap().into_iter();
let read_file = files_iter.next().unwrap();
@ -70,17 +67,20 @@ impl <'s> AudioFileLoading<'s> {
let (seek_tx, seek_rx) = mpsc::channel();
let _shared = shared.clone();
let _session = session.clone();
thread::spawn(move || {
AudioFileLoading::fetch(&_session, _shared, write_file, seek_rx)
});
AudioFileLoading {
read_file: read_file,
position: 0,
seek: seek_tx,
shared: shared.clone(),
thread: thread::scoped(move || {
AudioFileLoading::fetch(session, shared, write_file, seek_rx)
})
shared: shared
}
}
@ -155,7 +155,7 @@ impl <'s> AudioFileLoading<'s> {
}
}
impl <'s> Read for AudioFileLoading<'s> {
impl Read for AudioFileLoading {
fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
let index = self.position as usize / CHUNK_SIZE;
let offset = self.position as usize % CHUNK_SIZE;
@ -167,15 +167,15 @@ impl <'s> Read for AudioFileLoading<'s> {
}
drop(bitmap);
let len = try!(self.read_file.read(&mut output[..len]));
let read_len = try!(self.read_file.read(&mut output[..len]));
self.position += len as u64;
self.position += read_len as u64;
Ok(len)
Ok(read_len)
}
}
impl <'s> Seek for AudioFileLoading<'s> {
impl Seek for AudioFileLoading {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
self.position = try!(self.read_file.seek(pos));
@ -189,7 +189,7 @@ impl <'s> Seek for AudioFileLoading<'s> {
}
}
impl <'s> Read for AudioFile<'s> {
impl Read for AudioFile {
fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
match *self {
AudioFile::Direct(ref mut file) => file.read(output),
@ -198,7 +198,7 @@ impl <'s> Read for AudioFile<'s> {
}
}
impl <'s> Seek for AudioFile<'s> {
impl Seek for AudioFile {
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
match *self {
AudioFile::Direct(ref mut file) => file.seek(pos),
@ -215,7 +215,7 @@ impl AudioFileManager {
pub fn cache_dir(session: &Session, file_id: FileId) -> PathBuf {
let name = file_id.to_base16();
session.config.cache_location.join(&name[0..2])
session.0.config.cache_location.join(&name[0..2])
}
pub fn cache_path(session: &Session, file_id: FileId) -> PathBuf {
@ -223,7 +223,7 @@ impl AudioFileManager {
AudioFileManager::cache_dir(session, file_id).join(&name[2..])
}
pub fn request<'a> (&mut self, session: &'a Session, file_id: FileId) -> AudioFile<'a> {
pub fn request (&mut self, session: &Session, file_id: FileId) -> AudioFile {
match fs::File::open(AudioFileManager::cache_path(session, file_id)) {
Ok(f) => AudioFile::Direct(f),
Err(..) => AudioFile::Loading(AudioFileLoading::new(session, file_id))

View file

@ -1,11 +1,10 @@
use std::collections::{HashMap, LinkedList};
use std::sync::{mpsc, Future};
use std::io::{Cursor, Write};
use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
use readall::ReadAllExt;
use eventual;
use std::collections::HashMap;
use std::io::{Cursor, Read, Write};
use std::mem;
use util::{SpotifyId, FileId, IgnoreExt};
use util::{SpotifyId, FileId};
use session::Session;
use connection::PacketHandler;
@ -15,7 +14,7 @@ pub type AudioKey = [u8; 16];
struct AudioKeyId(SpotifyId, FileId);
enum AudioKeyStatus {
Loading(LinkedList<mpsc::Sender<AudioKey>>),
Loading(Vec<eventual::Complete<AudioKey, ()>>),
Loaded(AudioKey)
}
@ -35,17 +34,17 @@ impl AudioKeyManager {
}
pub fn request(&mut self, session: &Session, track: SpotifyId, file: FileId)
-> Future<AudioKey> {
-> eventual::Future<AudioKey, ()> {
let id = AudioKeyId(track, file);
self.cache.get_mut(&id).map(|status| match status {
&mut AudioKeyStatus::Loaded(key) => {
Future::from_value(key.clone())
self.cache.get_mut(&id).map(|status| match *status {
AudioKeyStatus::Loaded(key) => {
eventual::Future::of(key.clone())
}
&mut AudioKeyStatus::Loading(ref mut req) => {
let (tx, rx) = mpsc::channel();
req.push_front(tx);
Future::from_receiver(rx)
AudioKeyStatus::Loading(ref mut req) => {
let (tx, rx) = eventual::Future::pair();
req.push(tx);
rx
}
}).unwrap_or_else(|| {
let seq = self.next_seq;
@ -61,11 +60,9 @@ impl AudioKeyManager {
self.pending.insert(seq, id.clone());
let (tx, rx) = mpsc::channel();
let mut req = LinkedList::new();
req.push_front(tx);
self.cache.insert(id, AudioKeyStatus::Loading(req));
Future::from_receiver(rx)
let (tx, rx) = eventual::Future::pair();
self.cache.insert(id, AudioKeyStatus::Loading(vec!{ tx }));
rx
})
}
}
@ -77,14 +74,14 @@ impl PacketHandler for AudioKeyManager {
let mut data = Cursor::new(data);
let seq = data.read_u32::<BigEndian>().unwrap();
let mut key = [0u8; 16];
data.read_all(&mut key).unwrap();
data.read_exact(&mut key).unwrap();
if let Some(status) = self.pending.remove(&seq).and_then(|id| { self.cache.get_mut(&id) }) {
let status = mem::replace(status, AudioKeyStatus::Loaded(key));
if let AudioKeyStatus::Loading(cbs) = status {
for cb in cbs {
cb.send(key).ignore();
cb.complete(key);
}
}
}

View file

@ -1,9 +1,8 @@
use byteorder::{self, BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
use readall::ReadAllExt;
use shannon::ShannonStream;
use std::convert;
use std::io;
use std::io::Write;
use std::io::{Read, Write};
use std::net::TcpStream;
use std::result;
@ -70,7 +69,7 @@ impl PlainConnection {
let mut buffer = vec![0u8; size];
BigEndian::write_u32(&mut buffer, size as u32);
try!(self.stream.read_all(&mut buffer[4..]));
try!(self.stream.read_exact(&mut buffer[4..]));
Ok(buffer)
}
@ -98,7 +97,7 @@ impl CipherConnection {
let size = try!(self.stream.read_u16::<BigEndian>()) as usize;
let mut data = vec![0; size];
try!(self.stream.read_all(&mut data));
try!(self.stream.read_exact(&mut data));
try!(self.stream.finish_recv());

View file

@ -1,25 +1,25 @@
#![crate_name = "librespot"]
#![feature(plugin,scoped,zero_one,iter_arith,slice_position_elem,slice_bytes,bitset,arc_weak,append,future,mpsc_select)]
#![allow(deprecated)]
//#![allow(unused_imports,dead_code)]
#![feature(plugin,read_exact,zero_one,iter_arith,slice_bytes,arc_weak,append,mpsc_select)]
#![allow(needless_return)]
#![plugin(clippy)]
#![plugin(protobuf_macros)]
#[macro_use] extern crate lazy_static;
extern crate bit_set;
extern crate byteorder;
extern crate crypto;
extern crate eventual;
extern crate gmp;
extern crate num;
extern crate portaudio;
extern crate protobuf;
extern crate shannon;
extern crate rand;
extern crate readall;
extern crate vorbis;
extern crate time;
extern crate tempfile;
extern crate vorbis;
extern crate librespot_protocol;

View file

@ -1,4 +1,3 @@
#![feature(scoped)]
#![feature(result_expect)]
#![allow(deprecated)]
@ -71,9 +70,10 @@ fn main() {
session.login(username.clone(), password);
session.poll();
let poll_thread = thread::scoped(|| {
let _session = session.clone();
thread::spawn(move || {
loop {
session.poll();
_session.poll();
}
});
@ -81,7 +81,5 @@ fn main() {
let mut spirc_manager = SpircManager::new(&session, player, username, name);
spirc_manager.run();
poll_thread.join();
}

View file

@ -1,11 +1,10 @@
use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
use eventual;
use protobuf::{self, Message};
use readall::ReadAllExt;
use std::collections::{HashMap, LinkedList};
use std::collections::HashMap;
use std::io::{Cursor, Read, Write};
use std::fmt;
use std::mem::replace;
use std::sync::{mpsc, Future};
use std::sync::mpsc;
use librespot_protocol as protocol;
use session::Session;
@ -30,13 +29,13 @@ pub struct MercuryRequest {
#[derive(Debug)]
pub struct MercuryResponse {
pub uri: String,
pub payload: LinkedList<Vec<u8>>
pub payload: Vec<Vec<u8>>
}
pub struct MercuryPending {
parts: LinkedList<Vec<u8>>,
parts: Vec<Vec<u8>>,
partial: Option<Vec<u8>>,
callback: Option<mpsc::Sender<MercuryResponse>>
callback: Option<eventual::Complete<MercuryResponse, ()>>
}
pub struct MercuryManager {
@ -45,14 +44,14 @@ pub struct MercuryManager {
subscriptions: HashMap<String, mpsc::Sender<MercuryResponse>>,
}
impl fmt::Display for MercuryMethod {
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
formatter.write_str(match *self {
impl ToString for MercuryMethod {
fn to_string(&self) -> String {
match *self {
MercuryMethod::GET => "GET",
MercuryMethod::SUB => "SUB",
MercuryMethod::UNSUB => "UNSUB",
MercuryMethod::SEND => "SEND"
})
}.to_owned()
}
}
@ -66,7 +65,7 @@ impl MercuryManager {
}
pub fn request(&mut self, session: &Session, req: MercuryRequest)
-> Future<MercuryResponse> {
-> eventual::Future<MercuryResponse, ()> {
let mut seq = [0u8; 4];
BigEndian::write_u32(&mut seq, self.next_seq);
@ -81,14 +80,14 @@ impl MercuryManager {
session.send_packet(cmd, &data).unwrap();
let (tx, rx) = mpsc::channel();
let (tx, rx) = eventual::Future::pair();
self.pending.insert(seq.to_vec(), MercuryPending{
parts: LinkedList::new(),
parts: Vec::new(),
partial: None,
callback: Some(tx),
});
Future::from_receiver(rx)
rx
}
pub fn subscribe(&mut self, session: &Session, uri: String)
@ -109,33 +108,25 @@ impl MercuryManager {
fn parse_part(mut s: &mut Read) -> Vec<u8> {
let size = s.read_u16::<BigEndian>().unwrap() as usize;
let mut buffer = vec![0; size];
s.read_all(&mut buffer).unwrap();
s.read_exact(&mut buffer).unwrap();
buffer
}
fn complete_request(&mut self, cmd: u8, mut pending: MercuryPending) {
let header_data = match pending.parts.pop_front() {
Some(data) => data,
None => panic!("No header part !")
};
let header_data = pending.parts.remove(0);
let header : protocol::mercury::Header =
protobuf::parse_from_bytes(&header_data).unwrap();
let callback = if cmd == 0xb5 {
self.subscriptions.get(header.get_uri())
} else {
pending.callback.as_ref()
let response = MercuryResponse {
uri: header.get_uri().to_owned(),
payload: pending.parts
};
if let Some(ref ch) = callback {
// Ignore send error.
// It simply means the receiver was closed
ch.send(MercuryResponse{
uri: header.get_uri().to_string(),
payload: pending.parts
}).ignore();
if cmd == 0xb5 {
self.subscriptions.get(header.get_uri()).map(|ch| ch.send(response).ignore());
} else {
pending.callback.map(|cb| cb.complete(response));
}
}
@ -173,7 +164,7 @@ impl PacketHandler for MercuryManager {
let seq = {
let seq_length = packet.read_u16::<BigEndian>().unwrap() as usize;
let mut seq = vec![0; seq_length];
packet.read_all(&mut seq).unwrap();
packet.read_exact(&mut seq).unwrap();
seq
};
let flags = packet.read_u8().unwrap();
@ -183,7 +174,7 @@ impl PacketHandler for MercuryManager {
pending
} else if cmd == 0xb5 {
MercuryPending {
parts: LinkedList::new(),
parts: Vec::new(),
partial: None,
callback: None,
}
@ -202,7 +193,7 @@ impl PacketHandler for MercuryManager {
if i == count - 1 && (flags == 2) {
pending.partial = Some(part)
} else {
pending.parts.push_back(part);
pending.parts.push(part);
}
}

View file

@ -1,3 +1,4 @@
use eventual::Async;
use protobuf::{self, Message};
use std::any::{Any, TypeId};
use std::collections::HashMap;
@ -11,7 +12,7 @@ use mercury::{MercuryRequest, MercuryMethod};
use util::{SpotifyId, FileId};
use session::Session;
pub trait MetadataTrait : Send + Any + 'static {
pub trait MetadataTrait : Send + Sized + Any + 'static {
type Message: protobuf::MessageStatic;
fn from_msg(msg: &Self::Message) -> Self;
fn base_url() -> &'static str;
@ -29,7 +30,7 @@ impl MetadataTrait for Track {
type Message = protocol::metadata::Track;
fn from_msg(msg: &Self::Message) -> Self {
Track {
name: msg.get_name().to_string(),
name: msg.get_name().to_owned(),
album: SpotifyId::from_raw(msg.get_album().get_gid()),
files: msg.get_file().iter()
.map(|file| {
@ -59,7 +60,7 @@ impl MetadataTrait for Album {
type Message = protocol::metadata::Album;
fn from_msg(msg: &Self::Message) -> Self {
Album {
name: msg.get_name().to_string(),
name: msg.get_name().to_owned(),
artists: msg.get_artist().iter()
.map(|a| SpotifyId::from_raw(a.get_gid()))
.collect(),
@ -89,7 +90,7 @@ impl MetadataTrait for Artist {
type Message = protocol::metadata::Artist;
fn from_msg(msg: &Self::Message) -> Self {
Artist {
name: msg.get_name().to_string(),
name: msg.get_name().to_owned(),
}
}
fn base_url() -> &'static str {
@ -164,7 +165,7 @@ impl <T: MetadataTrait> MetadataState<T> {
}
}
pub fn unwrap<'s>(&'s self) -> &'s T {
pub fn unwrap(&self) -> &T {
match *self {
MetadataState::Loaded(ref data) => data,
_ => panic!("Not loaded")
@ -180,7 +181,7 @@ pub enum MetadataRequest {
}
pub struct MetadataManager {
cache: HashMap<(SpotifyId, TypeId), Box<Any + Send>>
cache: HashMap<(SpotifyId, TypeId), Box<Any + Send + 'static>>
}
impl MetadataManager {
@ -204,7 +205,7 @@ impl MetadataManager {
cond: Condvar::new()
});
self.cache.insert(key, Box::new(x.downgrade()));
self.cache.insert(key, Box::new(Arc::downgrade(&x)));
self.load(session, x.clone());
x
})
@ -219,10 +220,10 @@ impl MetadataManager {
});
thread::spawn(move || {
let response = rx.into_inner();
let response = rx.await().unwrap();
let msg : T::Message = protobuf::parse_from_bytes(
response.payload.front().unwrap()).unwrap();
response.payload.first().unwrap()).unwrap();
object.set(MetadataState::Loaded(T::from_msg(&msg)));
});

View file

@ -1,7 +1,8 @@
use eventual::Async;
use portaudio;
use vorbis;
use std::sync::{mpsc, Mutex, Arc, Condvar, MutexGuard};
use std::thread;
use vorbis;
use metadata::TrackRef;
use session::Session;
@ -9,13 +10,10 @@ use audio_decrypt::AudioDecrypt;
use util::{self, SpotifyId, Subfile};
use spirc::{SpircState, SpircDelegate, PlayStatus};
pub struct Player<'s> {
pub struct Player {
state: Arc<(Mutex<PlayerState>, Condvar)>,
commands: mpsc::Sender<PlayerCommand>,
#[allow(dead_code)]
thread: thread::JoinGuard<'s, ()>,
}
pub struct PlayerState {
@ -27,10 +25,9 @@ pub struct PlayerState {
end_of_track: bool
}
struct PlayerInternal<'s> {
struct PlayerInternal {
state: Arc<(Mutex<PlayerState>, Condvar)>,
session: &'s Session,
session: Session,
commands: mpsc::Receiver<PlayerCommand>,
}
@ -42,7 +39,7 @@ enum PlayerCommand {
Seek(u32)
}
impl <'s> Player<'s> {
impl Player {
pub fn new(session: &Session) -> Player {
let (cmd_tx, cmd_rx) = mpsc::channel();
@ -55,17 +52,18 @@ impl <'s> Player<'s> {
}), Condvar::new()));
let internal = PlayerInternal {
session: session,
session: session.clone(),
commands: cmd_rx,
state: state.clone()
};
thread::spawn(move || {
internal.run()
});
Player {
commands: cmd_tx,
state: state,
thread: thread::scoped(move || {
internal.run()
})
}
}
@ -74,7 +72,7 @@ impl <'s> Player<'s> {
}
}
impl <'s> PlayerInternal<'s> {
impl PlayerInternal {
fn run(self) {
portaudio::initialize().unwrap();
@ -102,7 +100,8 @@ impl <'s> PlayerInternal<'s> {
let track : TrackRef = self.session.metadata(id);
let file_id = *track.wait().unwrap().files.first().unwrap();
let key = self.session.audio_key(track.id(), file_id).into_inner();
let key = self.session.audio_key(track.id(), file_id).await().unwrap();
decoder = Some(
vorbis::Decoder::new(
Subfile::new(
@ -217,7 +216,7 @@ impl <'s> PlayerInternal<'s> {
}
}
impl <'s> SpircDelegate for Player<'s> {
impl SpircDelegate for Player {
type State = PlayerState;
fn load(&self, track: SpotifyId,

View file

@ -1,8 +1,9 @@
use crypto::digest::Digest;
use crypto::sha1::Sha1;
use eventual::Future;
use protobuf::{self, Message};
use rand::thread_rng;
use std::sync::{Mutex, Arc, Future, mpsc};
use std::sync::{Mutex, Arc, mpsc};
use std::path::PathBuf;
use connection::{self, PlainConnection, CipherConnection};
@ -26,7 +27,7 @@ pub struct Config {
pub cache_location: PathBuf,
}
pub struct Session {
pub struct SessionData {
pub config: Config,
mercury: Mutex<MercuryManager>,
@ -38,7 +39,8 @@ pub struct Session {
tx_connection: Mutex<CipherConnection>,
}
type SessionRef = Arc<Session>;
#[derive(Clone)]
pub struct Session(pub Arc<SessionData>);
impl Session {
pub fn new(mut config: Config) -> Session {
@ -114,7 +116,7 @@ impl Session {
let cipher_connection = connection.setup_cipher(shared_keys);
Session {
Session(Arc::new(SessionData {
config: config,
rx_connection: Mutex::new(cipher_connection.clone()),
@ -125,7 +127,7 @@ impl Session {
stream: Mutex::new(StreamManager::new()),
audio_key: Mutex::new(AudioKeyManager::new()),
audio_file: Mutex::new(AudioFileManager::new()),
}
}))
}
pub fn login(&self, username: String, password: String) {
@ -138,15 +140,15 @@ impl Session {
system_info => {
cpu_family: protocol::authentication::CpuFamily::CPU_UNKNOWN,
os: protocol::authentication::Os::OS_UNKNOWN,
system_information_string: "librespot".to_string(),
device_id: self.config.device_id.clone()
system_information_string: "librespot".to_owned(),
device_id: self.0.config.device_id.clone()
},
version_string: util::version::version_string(),
appkey => {
version: self.config.application_key[0] as u32,
devkey: self.config.application_key[0x1..0x81].to_vec(),
signature: self.config.application_key[0x81..0x141].to_vec(),
useragent: self.config.user_agent.clone(),
version: self.0.config.application_key[0] as u32,
devkey: self.0.config.application_key[0x1..0x81].to_vec(),
signature: self.0.config.application_key[0x81..0x141].to_vec(),
useragent: self.0.config.user_agent.clone(),
callback_hash: vec![0; 20],
}
});
@ -156,14 +158,14 @@ impl Session {
pub fn poll(&self) {
let (cmd, data) =
self.rx_connection.lock().unwrap().recv_packet().unwrap();
self.0.rx_connection.lock().unwrap().recv_packet().unwrap();
match cmd {
0x4 => self.send_packet(0x49, &data).unwrap(),
0x4a => (),
0x9 => self.stream.lock().unwrap().handle(cmd, data),
0xd | 0xe => self.audio_key.lock().unwrap().handle(cmd, data),
0xb2...0xb6 => self.mercury.lock().unwrap().handle(cmd, data),
0x9 => self.0.stream.lock().unwrap().handle(cmd, data),
0xd | 0xe => self.0.audio_key.lock().unwrap().handle(cmd, data),
0xb2...0xb6 => self.0.mercury.lock().unwrap().handle(cmd, data),
0xac => eprintln!("Authentication succeedded"),
0xad => eprintln!("Authentication failed"),
_ => ()
@ -171,31 +173,31 @@ impl Session {
}
pub fn send_packet(&self, cmd: u8, data: &[u8]) -> connection::Result<()> {
self.tx_connection.lock().unwrap().send_packet(cmd, data)
self.0.tx_connection.lock().unwrap().send_packet(cmd, data)
}
pub fn audio_key(&self, track: SpotifyId, file: FileId) -> Future<AudioKey> {
self.audio_key.lock().unwrap().request(self, track, file)
pub fn audio_key(&self, track: SpotifyId, file: FileId) -> Future<AudioKey, ()> {
self.0.audio_key.lock().unwrap().request(self, track, file)
}
pub fn audio_file(&self, file: FileId) -> AudioFile {
self.audio_file.lock().unwrap().request(self, file)
self.0.audio_file.lock().unwrap().request(self, file)
}
pub fn stream(&self, file: FileId, offset: u32, size: u32) -> mpsc::Receiver<StreamEvent> {
self.stream.lock().unwrap().request(self, file, offset, size)
self.0.stream.lock().unwrap().request(self, file, offset, size)
}
pub fn metadata<T: MetadataTrait>(&self, id: SpotifyId) -> MetadataRef<T> {
self.metadata.lock().unwrap().get(self, id)
self.0.metadata.lock().unwrap().get(self, id)
}
pub fn mercury(&self, req: MercuryRequest) -> Future<MercuryResponse> {
self.mercury.lock().unwrap().request(self, req)
pub fn mercury(&self, req: MercuryRequest) -> Future<MercuryResponse, ()> {
self.0.mercury.lock().unwrap().request(self, req)
}
pub fn mercury_sub(&self, uri: String) -> mpsc::Receiver<MercuryResponse> {
self.mercury.lock().unwrap().subscribe(self, uri)
self.0.mercury.lock().unwrap().subscribe(self, uri)
}
}

View file

@ -1,3 +1,4 @@
use eventual::Async;
use protobuf::{self, Message};
use std::sync::{mpsc, MutexGuard};
@ -70,7 +71,7 @@ impl <'s, D: SpircDelegate> SpircManager<'s, D> {
seq_nr: 0,
name: name,
ident: session.config.device_id.clone(),
ident: session.0.config.device_id.clone(),
device_type: 5,
can_play: true,
@ -97,7 +98,8 @@ impl <'s, D: SpircDelegate> SpircManager<'s, D> {
select! {
pkt = rx.recv() => {
let frame = protobuf::parse_from_bytes::<protocol::spirc::Frame>(
pkt.unwrap().payload.front().unwrap()).unwrap();
pkt.unwrap().payload.first().unwrap()).unwrap();
println!("{:?} {} {} {} {}",
frame.get_typ(),
frame.get_device_state().get_name(),
@ -127,7 +129,7 @@ impl <'s, D: SpircDelegate> SpircManager<'s, D> {
fn handle(&mut self, frame: protocol::spirc::Frame) {
if frame.get_recipient().len() > 0 {
self.last_command_ident = frame.get_ident().to_string();
self.last_command_ident = frame.get_ident().to_owned();
self.last_command_msgid = frame.get_seq_nr();
}
match frame.get_typ() {
@ -174,12 +176,12 @@ impl <'s, D: SpircDelegate> SpircManager<'s, D> {
let mut pkt = protobuf_init!(protocol::spirc::Frame::new(), {
version: 1,
ident: self.ident.clone(),
protocol_version: "2.0.0".to_string(),
protocol_version: "2.0.0".to_owned(),
seq_nr: { self.seq_nr += 1; self.seq_nr },
typ: protocol::spirc::MessageType::kMessageTypeNotify,
device_state: self.device_state(),
recipient: protobuf::RepeatedField::from_vec(
recipient.map(|r| vec![r.to_string()] ).unwrap_or(vec![])
recipient.map(|r| vec![r.to_owned()] ).unwrap_or(vec![])
),
state_update_id: self.state_update_id as i64
});
@ -193,7 +195,7 @@ impl <'s, D: SpircDelegate> SpircManager<'s, D> {
uri: format!("hm://remote/user/{}", self.username),
content_type: None,
payload: vec![ pkt.write_to_bytes().unwrap() ]
});
}).await().unwrap();
}
fn spirc_state(&self) -> protocol::spirc::State {
@ -259,23 +261,23 @@ impl <'s, D: SpircDelegate> SpircManager<'s, D> {
@{
typ: protocol::spirc::CapabilityType::kSupportedContexts,
stringValue => [
"album".to_string(),
"playlist".to_string(),
"search".to_string(),
"inbox".to_string(),
"toplist".to_string(),
"starred".to_string(),
"publishedstarred".to_string(),
"track".to_string(),
"album".to_owned(),
"playlist".to_owned(),
"search".to_owned(),
"inbox".to_owned(),
"toplist".to_owned(),
"starred".to_owned(),
"publishedstarred".to_owned(),
"track".to_owned(),
]
},
@{
typ: protocol::spirc::CapabilityType::kSupportedTypes,
stringValue => [
"audio/local".to_string(),
"audio/track".to_string(),
"local".to_string(),
"track".to_string(),
"audio/local".to_owned(),
"audio/track".to_owned(),
"local".to_owned(),
"track".to_owned(),
]
}
],

View file

@ -19,7 +19,7 @@ impl SpotifyId {
let mut n : u128 = std::num::Zero::zero();
for c in data {
let d = BASE16_DIGITS.position_elem(c).unwrap() as u8;
let d = BASE16_DIGITS.iter().position(|e| e == c).unwrap() as u8;
n = n * u128::from(16);
n = n + u128::from(d);
}
@ -33,7 +33,7 @@ impl SpotifyId {
let mut n : u128 = std::num::Zero::zero();
for c in data {
let d = BASE62_DIGITS.position_elem(c).unwrap() as u8;
let d = BASE62_DIGITS.iter().position(|e| e == c).unwrap() as u8;
n = n * u128::from(62);
n = n + u128::from(d);
}
@ -62,7 +62,7 @@ impl SpotifyId {
data[15-i] = BASE16_DIGITS[(high.wrapping_shr(4 * i as u32) & 0xF) as usize];
}
std::str::from_utf8(&data).unwrap().to_string()
std::str::from_utf8(&data).unwrap().to_owned()
}
pub fn to_raw(&self) -> [u8; 16] {

View file

@ -33,8 +33,8 @@ impl io::Read for ZeroFile {
// TODO optimize with memset or similar
fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
let len = min(output.len(), (self.size - self.position) as usize);
for i in 0..len {
output[i] = 0;
for b in output {
*b = 0;
}
self.position += len as u64;