<commit_before>extern mod extra;

pub struct LinearPipe<T,U>{
  priv chan: Chan<T>,
  priv port: Port<U>
}

pub enum Message<T> {
    Exit,
    Value(T)
}
trait Wire<T: Send,U: Send, R: Send> {
  fn connect(&self, f: ~fn(T)->U,port: Port<Message<T>>) -> R;
}
trait Sender<T: Send>{
  fn send(&self, t: T);
  fn shutdown(&self);

}
trait Receiver<U: Send> {
  fn try_recv(&self) -> Option<U>;
  fn recv(&self) -> U;
}

impl <T: Send,U: Send> LinearPipe<Message<T>,Message<U>>{
  pub fn new(f: ~fn(Port<T>) -> Port<U>)-> LinearPipe<T,U> {
    let (in_port, chan): (Port<T>, Chan<T>) = stream();
    let out_port = f(in_port);
    LinearPipe { chan: chan,
           port: out_port}
  }
}
impl <T: Send,U: Send> Sender<T> for LinearPipe<Message<T>,Message<U>>{
  fn send(&self, t: T) {
      self.chan.send(Value(t));
  }

  fn shutdown(&self) {
     self.chan.send(Exit);
     loop {
       match self.port.recv() {
         Exit => return,
         _    => ()
       }
     }
  }
}
impl <T: Send,U: Send> Receiver<U> for LinearPipe<Message<T>,Message<U>> {
  fn try_recv(&self) -> Option<U>{
    match self.port.peek() {
      true  => Some(self.recv()),
      false => None
    }
  }

  fn recv(&self) -> U {
    match self.port.recv(){
      Exit => fail!(~"Tried to receive on 'Exit'"),
      Value(x) => x
    }
  }
}
pub fn one_to_many_wire<T: Send,U: Send + Clone>(count: uint, f: ~fn(T)->U,port: Port<Message<T>>) -> ~[Port<Message<U>>] {
  let mut pvec = ~[];
  let mut cvec = ~[];
  do count.times(){
    let (out_port, out_chan): (Port<Message<U>>, Chan<Message<U>>) = stream();
    pvec.push(out_port);
    cvec.push(out_chan);
  }
  let cvec = cvec;
  do ::std::task::spawn_unlinked {
    loop {
      let msg = port.recv();
      match msg {
        Exit => {
          for chan in cvec.iter() {
            chan.send(Exit);
          }
          fail!(~"Exit");
        }
        Value(x) => {
          let msg = f(x);
          for chan in cvec.iter() {
            chan.send(Value(msg.clone()));
          }
        }
      }
    }
  }
  pvec
}

fn single_wire<T: Send,U: Send>(f: ~fn(T)->U,port: Port<Message<T>>) -> Port<Message<U>> {
  let (out_port, out_chan): (Port<Message<U>>, Chan<Message<U>>) = stream();
  do ::std::task::spawn_unlinked {
    loop {
      let msg = port.recv();
      match msg {
        Exit => {
          out_chan.send(Exit);
          fail!(~"Exit");
        }
        Value(x) => out_chan.send(Value(f(x)))
      }
    }
  }
  out_port
}
fn many_to_one<T: Send,U: Send>(f: ~fn(T)->U,pvec: ~[Port<Message<T>>]) -> Port<Message<U>> {
  let (out_port, out_chan): (Port<Message<U>>, Chan<Message<U>>) = stream();
  do ::std::task::spawn_unlinked {
    loop {
      for port in pvec.iter(){
        if port.peek(){
          let msg = port.recv();
          match msg {
            Exit => {
              out_chan.send(Exit);
              fail!(~"Exit");
            }
            Value(x) => out_chan.send(Value(f(x)))
          }
        }
      }
    }
  }
  out_port
}

<commit_msg>formatting<commit_after>extern mod extra;

pub struct LinearPipe<T,U>{
  priv chan: Chan<T>,
  priv port: Port<U>
}

pub enum Message<T> {
    Exit,
    Value(T)
}
trait Wire<T: Send,
           U: Send,
           R: Send> {
  fn connect(&self,
             f: ~fn(T)->U,
             port: Port<Message<T>>)
             -> R;
}
trait Sender<T: Send>{
  fn send(&self, t: T);
  fn shutdown(&self);

}
trait Receiver<U: Send> {
  fn try_recv(&self) -> Option<U>;
  fn recv(&self) -> U;
}

impl <T: Send,
      U: Send>
      LinearPipe<Message<T>,Message<U>>{
  pub fn new(f: ~fn(Port<T>) -> Port<U>)-> LinearPipe<T,U> {
    let (in_port, chan): (Port<T>, Chan<T>) = stream();
    let out_port = f(in_port);
    LinearPipe { chan: chan,
           port: out_port}
  }
}
impl <T: Send,
      U: Send>
      Sender<T> for
      LinearPipe<Message<T>,Message<U>>{
  fn send(&self, t: T) {
      self.chan.send(Value(t));
  }

  fn shutdown(&self) {
     self.chan.send(Exit);
     loop {
       match self.port.recv() {
         Exit => return,
         _    => ()
       }
     }
  }
}
impl <T: Send,
      U: Send>
      Receiver<U> for
      LinearPipe<Message<T>,Message<U>> {
  fn try_recv(&self)
              -> Option<U>{
    match self.port.peek() {
      true  => Some(self.recv()),
      false => None
    }
  }

  fn recv(&self)
          -> U {
    match self.port.recv(){
      Exit => fail!(~"Tried to receive on 'Exit'"),
      Value(x) => x
    }
  }
}
pub fn one_to_many_wire<T: Send,
                        U: Send + Clone>(
                        count: uint,
                        f: ~fn(T)->U,
                        port: Port<Message<T>>)
                        -> ~[Port<Message<U>>] {
  let mut pvec = ~[];
  let mut cvec = ~[];
  do count.times(){
    let (out_port, out_chan): (Port<Message<U>>, Chan<Message<U>>) = stream();
    pvec.push(out_port);
    cvec.push(out_chan);
  }
  let cvec = cvec;
  do ::std::task::spawn_unlinked {
    loop {
      let msg = port.recv();
      match msg {
        Exit => {
          for chan in cvec.iter() {
            chan.send(Exit);
          }
          fail!(~"Exit");
        }
        Value(x) => {
          let msg = f(x);
          for chan in cvec.iter() {
            chan.send(Value(msg.clone()));
          }
        }
      }
    }
  }
  pvec
}

fn single_wire<T: Send,
               U: Send>(
               f: ~fn(T)->U,
               port: Port<Message<T>>)
               -> Port<Message<U>> {
  let (out_port, out_chan): (Port<Message<U>>, Chan<Message<U>>) = stream();
  do ::std::task::spawn_unlinked {
    loop {
      let msg = port.recv();
      match msg {
        Exit => {
          out_chan.send(Exit);
          fail!(~"Exit");
        }
        Value(x) => out_chan.send(Value(f(x)))
      }
    }
  }
  out_port
}
fn many_to_one<T: Send,
               U: Send>(
               f: ~fn(T)->U,
               pvec: ~[Port<Message<T>>])
               -> Port<Message<U>> {

  let (out_port, out_chan): (Port<Message<U>>, Chan<Message<U>>) = stream();
  do ::std::task::spawn_unlinked {
    loop {
      for port in pvec.iter(){
        if port.peek(){
          let msg = port.recv();
          match msg {
            Exit => {
              out_chan.send(Exit);
              fail!(~"Exit");
            }
            Value(x) => out_chan.send(Value(f(x)))
          }
        }
      }
    }
  }
  out_port
}

<|endoftext|>


<commit_before>use std::rc::Rc;
use std::io::{self, Read, Write};
use std::net::Shutdown;

use futures::prelude::*;
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::io::shutdown;
use bytes::{BytesMut, Bytes, BufMut, IntoBuf};
use h2::{self, server as h2s, client as h2c};
use tokio_core::net::TcpStream;

const BUF_SIZE: usize = 2048;

#[async]
pub fn copy_from_h2<
    W: AsyncWrite + 'static,
    B: Stream<Item = Bytes, Error = h2::Error> + 'static,
>(
    src: B,
    mut dst: W,
) -> Result<usize, h2::Error> {
    let mut counter = 0;
    #[async]
    for buf in src {
        let mut buf = buf.into_buf();
        let n = poll!(dst.write_buf(&mut buf))?;
        counter += n;
    }
    await!(shutdown(dst))?;
    Ok(counter)
}

pub trait H2Stream<B: IntoBuf> {
    fn reserve_capacity(&mut self, capacity: usize);
    fn capacity(&self) -> usize;
    fn poll_capacity(&mut self) -> Poll<Option<usize>, h2::Error>;
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error>;
}

impl<B: IntoBuf> H2Stream<B> for h2c::Stream<B> {
    fn reserve_capacity(&mut self, capacity: usize) {
        h2c::Stream::reserve_capacity(self, capacity)
    }
    fn capacity(&self) -> usize {
        h2c::Stream::capacity(self)
    }
    fn poll_capacity(&mut self) -> Poll<Option<usize>, h2::Error> {
        h2c::Stream::poll_capacity(self)
    }
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error> {
        h2c::Stream::send_data(self, data, end_of_stream)
    }
}
impl<B: IntoBuf> H2Stream<B> for h2s::Stream<B> {
    fn reserve_capacity(&mut self, capacity: usize) {
        h2s::Stream::reserve_capacity(self, capacity)
    }
    fn capacity(&self) -> usize {
        h2s::Stream::capacity(self)
    }
    fn poll_capacity(&mut self) -> Poll<Option<usize>, h2::Error> {
        h2s::Stream::poll_capacity(self)
    }
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error> {
        h2s::Stream::send_data(self, data, end_of_stream)
    }
}

#[async]
pub fn copy_to_h2<R: AsyncRead + 'static, H: H2Stream<Bytes> + 'static>(
    mut src: R,
    mut dst: H,
) -> Result<usize, h2::Error> {
    let mut counter = 0;
    let mut buf = BytesMut::with_capacity(BUF_SIZE);
    loop {
        let n = poll!(src.read_buf(&mut buf))?;
        if n == 0 {
            dst.send_data(buf.take().freeze(), true)?;
            break;
        } else {
            loop {
                let dst_cap = dst.capacity();
                let src_len = buf.len();
                if src_len > dst_cap {
                    dst.reserve_capacity(src_len);
                    if dst_cap == 0 {
                        poll!(dst.poll_capacity())?; // TODO: handle value
                        continue;
                    }
                    let chunk = buf.split_to(dst_cap).freeze();
                    dst.send_data(chunk, false)?;
                } else {
                    dst.send_data(buf.take().freeze(), false)?;
                }
                if buf.is_empty() {
                    break;
                }
            }
        }
        counter += n;
        let rem = buf.remaining_mut();
        if rem < BUF_SIZE {
            buf.reserve(BUF_SIZE - rem);
        }
    }
    Ok(counter)
}

// This is a custom type used to have a custom implementation of the
// `AsyncWrite::shutdown` method which actually calls `TcpStream::shutdown` to
// notify the remote end that we're done writing.
#[derive(Clone)]
pub struct Socket(Rc<TcpStream>);

impl Socket {
    pub fn new(s: TcpStream) -> Socket {
        Socket(Rc::new(s))
    }
}

impl Read for Socket {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (&*self.0).read(buf)
    }
}

impl Write for Socket {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        (&*self.0).write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl AsyncRead for Socket {}

impl AsyncWrite for Socket {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        try!(self.0.shutdown(Shutdown::Write));
        Ok(().into())
    }
}

#[cfg(test)]
mod test {
    use std::io::Cursor;
    use std::rc::Rc;
    use std::cell::RefCell;

    use futures::prelude::*;
    use futures::stream::iter_ok;

    use super::*;

    #[derive(Clone)]
    struct Dst(Rc<RefCell<Cursor<Vec<u8>>>>);
    impl Write for Dst {
        fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
            self.0.borrow_mut().write(buf)
        }
        fn flush(&mut self) -> ::std::io::Result<()> {
            self.0.borrow_mut().flush()
        }
    }
    impl AsyncWrite for Dst {
        fn shutdown(&mut self) -> Poll<(), ::std::io::Error> {
            Ok(().into())
        }
    }
    impl H2Stream<Bytes> for Dst {
        fn reserve_capacity(&mut self, capacity: usize) {
            self.0.borrow_mut().get_mut().reserve(capacity)
        }
        fn capacity(&self) -> usize {
            self.0.borrow().get_ref().capacity()
        }
        fn poll_capacity(&mut self) -> Poll<Option<usize>, h2::Error> {
            Ok(Async::Ready(Some(self.capacity())))
        }
        fn send_data(&mut self, data: Bytes, _end_of_stream: bool) -> Result<(), h2::Error> {
            self.0.borrow_mut().get_mut().extend(data);
            Ok(())
        }
    }

    #[test]
    fn test_copy_from_h2() {
        let dst = Dst(Rc::new(RefCell::new(Cursor::new(Vec::new()))));
        let src = iter_ok(vec![
            Bytes::from("123"),
            Bytes::from("456"),
            Bytes::from("789"),
        ]);
        let r = copy_from_h2(src, dst.clone()).wait().unwrap();
        assert_eq!(r, 9);
        assert_eq!(dst.0.borrow().get_ref(), b"123456789");

        let data: &[u8] = &[0; BUF_SIZE * 2];
        let dst = Dst(Rc::new(RefCell::new(Cursor::new(Vec::new()))));
        let src = iter_ok(vec![Bytes::from(data)]);
        let r = copy_from_h2(src, dst.clone()).wait().unwrap();
        assert_eq!(r, data.len());
        assert_eq!(dst.0.borrow().get_ref().as_slice(), data);
    }

    #[test]
    fn test_copy_to_h2() {
        let dst = Dst(Rc::new(RefCell::new(Cursor::new(Vec::new()))));
        let src: &[u8] = b"123456789";
        let r = copy_to_h2(src, dst.clone()).wait().unwrap();
        assert_eq!(r, 9);
        assert_eq!(dst.0.borrow().get_ref(), b"123456789");

        let data: &[u8] = &[0; BUF_SIZE * 2];
        let dst = Dst(Rc::new(RefCell::new(Cursor::new(Vec::new()))));
        let src: &[u8] = data;
        let r = copy_to_h2(src, dst.clone()).wait().unwrap();
        assert_eq!(r, data.len());
        assert_eq!(dst.0.borrow().get_ref().as_slice(), data);
    }
}
<commit_msg>Add a FIXME note for a bug of `h2`<commit_after>use std::rc::Rc;
use std::io::{self, Read, Write};
use std::net::Shutdown;

use futures::prelude::*;
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::io::shutdown;
use bytes::{BytesMut, Bytes, BufMut, IntoBuf};
use h2::{self, server as h2s, client as h2c};
use tokio_core::net::TcpStream;

const BUF_SIZE: usize = 2048;

#[async]
pub fn copy_from_h2<
    W: AsyncWrite + 'static,
    B: Stream<Item = Bytes, Error = h2::Error> + 'static,
>(
    src: B,
    mut dst: W,
) -> Result<usize, h2::Error> {
    let mut counter = 0;
    #[async]
    for buf in src {
        let mut buf = buf.into_buf();
        let n = poll!(dst.write_buf(&mut buf))?;
        counter += n;
    }
    await!(shutdown(dst))?;
    Ok(counter)
}

pub trait H2Stream<B: IntoBuf> {
    fn reserve_capacity(&mut self, capacity: usize);
    fn capacity(&self) -> usize;
    fn poll_capacity(&mut self) -> Poll<Option<usize>, h2::Error>;
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error>;
}

impl<B: IntoBuf> H2Stream<B> for h2c::Stream<B> {
    fn reserve_capacity(&mut self, capacity: usize) {
        h2c::Stream::reserve_capacity(self, capacity)
    }
    fn capacity(&self) -> usize {
        h2c::Stream::capacity(self)
    }
    fn poll_capacity(&mut self) -> Poll<Option<usize>, h2::Error> {
        h2c::Stream::poll_capacity(self)
    }
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error> {
        h2c::Stream::send_data(self, data, end_of_stream)
    }
}
impl<B: IntoBuf> H2Stream<B> for h2s::Stream<B> {
    fn reserve_capacity(&mut self, capacity: usize) {
        h2s::Stream::reserve_capacity(self, capacity)
    }
    fn capacity(&self) -> usize {
        h2s::Stream::capacity(self)
    }
    fn poll_capacity(&mut self) -> Poll<Option<usize>, h2::Error> {
        h2s::Stream::poll_capacity(self)
    }
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error> {
        h2s::Stream::send_data(self, data, end_of_stream)
    }
}

#[async]
pub fn copy_to_h2<R: AsyncRead + 'static, H: H2Stream<Bytes> + 'static>(
    mut src: R,
    mut dst: H,
) -> Result<usize, h2::Error> {
    let mut counter = 0;
    let mut buf = BytesMut::with_capacity(BUF_SIZE);
    loop {
        let n = poll!(src.read_buf(&mut buf))?;
        if n == 0 {
            dst.send_data(buf.take().freeze(), true)?;
            break;
        } else {
            loop {
                let dst_cap = dst.capacity();
                let src_len = buf.len();
                if src_len > dst_cap {
                    dst.reserve_capacity(src_len);
                    if dst_cap == 0 {
                        let n = poll!(dst.poll_capacity())?;
                        if let Some(n) = n {
                            if n < src_len {
                                // FIXME:
                                // https://github.com/carllerche/h2/blob/4c7ecf15/src/server.rs#L358
                                eprintln!("BUG!");
                            }
                        }
                        continue;
                    }
                    let chunk = buf.split_to(dst_cap).freeze();
                    dst.send_data(chunk, false)?;
                } else {
                    dst.send_data(buf.take().freeze(), false)?;
                }
                if buf.is_empty() {
                    break;
                }
            }
        }
        counter += n;
        let rem = buf.remaining_mut();
        if rem < BUF_SIZE {
            buf.reserve(BUF_SIZE - rem);
        }
    }
    Ok(counter)
}

// This is a custom type used to have a custom implementation of the
// `AsyncWrite::shutdown` method which actually calls `TcpStream::shutdown` to
// notify the remote end that we're done writing.
#[derive(Clone)]
pub struct Socket(Rc<TcpStream>);

impl Socket {
    pub fn new(s: TcpStream) -> Socket {
        Socket(Rc::new(s))
    }
}

impl Read for Socket {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (&*self.0).read(buf)
    }
}

impl Write for Socket {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        (&*self.0).write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl AsyncRead for Socket {}

impl AsyncWrite for Socket {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        try!(self.0.shutdown(Shutdown::Write));
        Ok(().into())
    }
}

#[cfg(test)]
mod test {
    use std::io::Cursor;
    use std::rc::Rc;
    use std::cell::RefCell;

    use futures::prelude::*;
    use futures::stream::iter_ok;

    use super::*;

    #[derive(Clone)]
    struct Dst(Rc<RefCell<Cursor<Vec<u8>>>>);
    impl Write for Dst {
        fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
            self.0.borrow_mut().write(buf)
        }
        fn flush(&mut self) -> ::std::io::Result<()> {
            self.0.borrow_mut().flush()
        }
    }
    impl AsyncWrite for Dst {
        fn shutdown(&mut self) -> Poll<(), ::std::io::Error> {
            Ok(().into())
        }
    }
    impl H2Stream<Bytes> for Dst {
        fn reserve_capacity(&mut self, capacity: usize) {
            self.0.borrow_mut().get_mut().reserve(capacity)
        }
        fn capacity(&self) -> usize {
            self.0.borrow().get_ref().capacity()
        }
        fn poll_capacity(&mut self) -> Poll<Option<usize>, h2::Error> {
            Ok(Async::Ready(Some(self.capacity())))
        }
        fn send_data(&mut self, data: Bytes, _end_of_stream: bool) -> Result<(), h2::Error> {
            self.0.borrow_mut().get_mut().extend(data);
            Ok(())
        }
    }

    #[test]
    fn test_copy_from_h2() {
        let dst = Dst(Rc::new(RefCell::new(Cursor::new(Vec::new()))));
        let src = iter_ok(vec![
            Bytes::from("123"),
            Bytes::from("456"),
            Bytes::from("789"),
        ]);
        let r = copy_from_h2(src, dst.clone()).wait().unwrap();
        assert_eq!(r, 9);
        assert_eq!(dst.0.borrow().get_ref(), b"123456789");

        let data: &[u8] = &[0; BUF_SIZE * 2];
        let dst = Dst(Rc::new(RefCell::new(Cursor::new(Vec::new()))));
        let src = iter_ok(vec![Bytes::from(data)]);
        let r = copy_from_h2(src, dst.clone()).wait().unwrap();
        assert_eq!(r, data.len());
        assert_eq!(dst.0.borrow().get_ref().as_slice(), data);
    }

    #[test]
    fn test_copy_to_h2() {
        let dst = Dst(Rc::new(RefCell::new(Cursor::new(Vec::new()))));
        let src: &[u8] = b"123456789";
        let r = copy_to_h2(src, dst.clone()).wait().unwrap();
        assert_eq!(r, 9);
        assert_eq!(dst.0.borrow().get_ref(), b"123456789");

        let data: &[u8] = &[0; BUF_SIZE * 2];
        let dst = Dst(Rc::new(RefCell::new(Cursor::new(Vec::new()))));
        let src: &[u8] = data;
        let r = copy_to_h2(src, dst.clone()).wait().unwrap();
        assert_eq!(r, data.len());
        assert_eq!(dst.0.borrow().get_ref().as_slice(), data);
    }
}
<|endoftext|>


<commit_before>use libc::{c_void, c_char, c_int, c_uint, c_double};
use std::ffi::CString;
use std::ptr;

pub type POETApplyFn = unsafe extern fn(states: *mut c_void,
                                        num_states: c_uint,
                                        id: c_uint,
                                        last_id: c_uint);

pub type POETCurrentStateFn = unsafe extern fn(states: *const c_void,
                                               num_states: c_uint,
                                               curr_state_id: *mut c_uint) -> i32;

#[link(name = "poet")]
extern {
    /*
     * Core functions - poet.h
     */

    fn poet_init(perf_goal: c_double,
                 num_system_states: c_uint,
                 control_states: *mut POETControlState,
                 apply_states: *mut POETCpuState,
                 apply_func: POETApplyFn,
                 curr_state_func: POETCurrentStateFn,
                 period: c_uint,
                 buffer_depth: c_uint,
                 log_filename: *const c_char) -> *mut c_void;

    fn poet_apply_control(state: *mut c_void,
                          id: u64,
                          perf: c_double,
                          pwr: c_double);

    fn poet_destroy(state: *mut c_void);

    /*
     * Configuration/utility functions - poet_config.h
     */

    fn apply_cpu_config(states: *mut c_void,
                        num_states: c_uint,
                        id: c_uint,
                        last_id: c_uint);

    pub fn get_control_states(path: *const c_char,
                              states: *mut *mut POETControlState,
                              num_states: *mut c_uint) -> c_int;

    pub fn get_cpu_states(path: *const c_char,
                          states: *mut *mut POETCpuState,
                          num_states: *mut c_uint) -> c_int;

    fn get_current_cpu_state(states: *const c_void,
                             num_states: c_uint,
                             curr_state_id: *mut c_uint) -> c_int;

}

#[repr(C)]
pub struct POETControlState {
    pub id: c_uint,
    pub speedup: c_double,
    pub cost: c_double,
}

impl POETControlState {
    pub fn new() -> Result<(*mut POETControlState, u32), String> {
        let mut control_states = ptr::null_mut();
        let mut num_ctl_states : u32 = 0;
        let res = unsafe {
            get_control_states(ptr::null(),
                               &mut control_states,
                               &mut num_ctl_states)
        };
        if res != 0 {
            return Err("Failed to load control states".to_string());
        }
        Ok((control_states, num_ctl_states))
    }
}

impl Default for POETControlState {
    fn default() -> POETControlState {
        POETControlState {
            id: 0,
            speedup: 1.0,
            cost: 1.0,
        }
    }
}

#[repr(C)]
pub struct POETCpuState {
    id: c_uint,
    freq: c_uint,
    cores: c_uint,
}

impl POETCpuState {
    pub fn new() -> Result<(*mut POETCpuState, u32), String> {
        let mut cpu_states = ptr::null_mut();
        let mut num_cpu_states : u32 = 0;
        let res = unsafe {
            get_cpu_states(ptr::null(),
                           &mut cpu_states,
                           &mut num_cpu_states)
        };
        if res != 0 {
            return Err("Failed to load cpu states".to_string());
        }
        Ok((cpu_states, num_cpu_states))
    }
}

impl Default for POETCpuState {
    fn default() -> POETCpuState {
        POETCpuState {
            id: 0,
            freq: 0,
            cores: 0,
        }
    }
}

pub struct POET {
    pub poet: *mut c_void,
}

impl POET {
    pub fn new(perf_goal: f64,
               control_states: *mut POETControlState,
               cpu_states: *mut POETCpuState,
               num_states: u32,
               apply_func: Option<POETApplyFn>,
               curr_state_func: Option<POETCurrentStateFn>,
               period: u32,
               buffer_depth: u32,
               log_filename: Option<&str>) -> Result<POET, String> {
        let apply_func = match apply_func {
            Some(p) => p,
            None => apply_cpu_config,
        };
        let curr_state_func = match curr_state_func {
            Some(p) => p,
            None => get_current_cpu_state,
        };
        let log_filename = match log_filename {
            Some(l) => CString::new(l).unwrap().as_ptr(),
            None => ptr::null(),
        };
        let poet = unsafe {
            poet_init(perf_goal,
                      num_states, control_states, cpu_states,
                      apply_func, curr_state_func,
                      period, buffer_depth, log_filename)
        };
        if poet.is_null() {
            return Err("Failed to instantiate POET object".to_string());
        }
        Ok(POET { poet: poet, })
    }

    pub fn apply_control(&mut self, tag: u64, window_rate: f64, window_power: f64) {
        unsafe {
            poet_apply_control(self.poet, tag, window_rate, window_power);
        }
    }
}

impl Drop for POET {
    fn drop(&mut self) {
        unsafe {
            poet_destroy(self.poet);
        }
        println!("Cleaned up POET");
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use libc::{c_void, c_uint};

    #[test]
    fn test_basic() {
        let mut control_states = vec![POETControlState::default()];
        let mut cpu_states = vec![POETCpuState::default()];
        let mut poet = POET::new(100.0,
                                 control_states.as_mut_ptr(), cpu_states.as_mut_ptr(), 1,
                                 None, None,
                                 20u32, 1u32, None).unwrap();
        poet.apply_control(0, 1.0, 1.0);
    }

    #[test]
    fn test_rust_callbacks() {
        let mut control_states = vec![POETControlState::default()];
        let mut cpu_states = vec![POETCpuState::default()];
        let mut poet = POET::new(100.0,
                                 control_states.as_mut_ptr(), cpu_states.as_mut_ptr(), 1,
                                 Some(dummy_apply), Some(dummy_curr_state),
                                 20u32, 1u32, None).unwrap();
        for i in 0..50 {
            poet.apply_control(i, 1.0, 1.0);
        }
    }

    unsafe extern fn dummy_apply(_states: *mut c_void,
                                 _num_states: c_uint,
                                 _id: c_uint,
                                 _last_id: c_uint) {
        // do nothing
        println!("Received apply call");
    }

    unsafe extern fn dummy_curr_state (_states: *const c_void,
                                       _num_states: c_uint,
                                       _curr_state_id: *mut c_uint) -> i32 {
        println!("Received curr state call");
        // this is actually an invalid value, but forces the apply function to be called
        *_curr_state_id = _num_states;
        0
    }

}
<commit_msg>Documentation. Allow filename to be passed to new functions for control and cpu states<commit_after>//! POET - the Performance with Optimal Energy Toolkit. Used to meet timing constraints while
//! minimizing energy consumption.

use libc::{c_void, c_char, c_int, c_uint, c_double};
use std::ffi::CString;
use std::ptr;

/// Typedef for an "apply" function - used to manipulate system or application settings.
pub type POETApplyFn = unsafe extern fn(states: *mut c_void,
                                        num_states: c_uint,
                                        id: c_uint,
                                        last_id: c_uint);

/// Typedef for "current state" function - used to try and determine the current system or
/// application state.
pub type POETCurrentStateFn = unsafe extern fn(states: *const c_void,
                                               num_states: c_uint,
                                               curr_state_id: *mut c_uint) -> i32;

#[link(name = "poet")]
extern {
    /*
     * Core functions - poet.h
     */

    fn poet_init(perf_goal: c_double,
                 num_system_states: c_uint,
                 control_states: *mut POETControlState,
                 apply_states: *mut POETCpuState,
                 apply_func: POETApplyFn,
                 curr_state_func: POETCurrentStateFn,
                 period: c_uint,
                 buffer_depth: c_uint,
                 log_filename: *const c_char) -> *mut c_void;

    fn poet_apply_control(state: *mut c_void,
                          id: u64,
                          perf: c_double,
                          pwr: c_double);

    fn poet_destroy(state: *mut c_void);

    /*
     * Configuration/utility functions - poet_config.h
     */

    fn apply_cpu_config(states: *mut c_void,
                        num_states: c_uint,
                        id: c_uint,
                        last_id: c_uint);

    fn get_control_states(path: *const c_char,
                          states: *mut *mut POETControlState,
                          num_states: *mut c_uint) -> c_int;

    fn get_cpu_states(path: *const c_char,
                      states: *mut *mut POETCpuState,
                      num_states: *mut c_uint) -> c_int;

    fn get_current_cpu_state(states: *const c_void,
                             num_states: c_uint,
                             curr_state_id: *mut c_uint) -> c_int;

}

#[repr(C)]
/// Representation of native struct `poet_control_state_t`.
pub struct POETControlState {
    pub id: c_uint,
    pub speedup: c_double,
    pub cost: c_double,
}

impl POETControlState {
    /// Attempt to load control states from a file.
    pub fn new(filename: Option<&str>) -> Result<(*mut POETControlState, u32), String> {
        let filename = match filename {
            Some(f) => CString::new(f).unwrap().as_ptr(),
            None => ptr::null(),
        };
        let mut control_states = ptr::null_mut();
        let mut num_ctl_states : u32 = 0;
        let res = unsafe {
            get_control_states(filename,
                               &mut control_states,
                               &mut num_ctl_states)
        };
        if res != 0 {
            return Err("Failed to load control states".to_string());
        }
        Ok((control_states, num_ctl_states))
    }
}

impl Default for POETControlState {
    fn default() -> POETControlState {
        POETControlState {
            id: 0,
            speedup: 1.0,
            cost: 1.0,
        }
    }
}

#[repr(C)]
/// Representation of native struct `poet_cpu_state_t`.
pub struct POETCpuState {
    id: c_uint,
    freq: c_uint,
    cores: c_uint,
}

impl POETCpuState {
    /// Attempt to load cpu states from a file.
    pub fn new(filename: Option<&str>) -> Result<(*mut POETCpuState, u32), String> {
        let filename = match filename {
            Some(f) => CString::new(f).unwrap().as_ptr(),
            None => ptr::null(),
        };
        let mut cpu_states = ptr::null_mut();
        let mut num_cpu_states : u32 = 0;
        let res = unsafe {
            get_cpu_states(filename,
                           &mut cpu_states,
                           &mut num_cpu_states)
        };
        if res != 0 {
            return Err("Failed to load cpu states".to_string());
        }
        Ok((cpu_states, num_cpu_states))
    }
}

impl Default for POETCpuState {
    fn default() -> POETCpuState {
        POETCpuState {
            id: 0,
            freq: 0,
            cores: 0,
        }
    }
}

/// The `POET` struct wraps an underyling C struct.
pub struct POET {
    /// The underlying C struct `poet_state`.
    pub poet: *mut c_void,
}

impl POET {
    /// Attempt to initialize POET and allocate resources in the underlying C struct.
    pub fn new(perf_goal: f64,
               control_states: *mut POETControlState,
               cpu_states: *mut POETCpuState,
               num_states: u32,
               apply_func: Option<POETApplyFn>,
               curr_state_func: Option<POETCurrentStateFn>,
               period: u32,
               buffer_depth: u32,
               log_filename: Option<&str>) -> Result<POET, String> {
        let apply_func = match apply_func {
            Some(p) => p,
            None => apply_cpu_config,
        };
        let curr_state_func = match curr_state_func {
            Some(p) => p,
            None => get_current_cpu_state,
        };
        let log_filename = match log_filename {
            Some(l) => CString::new(l).unwrap().as_ptr(),
            None => ptr::null(),
        };
        let poet = unsafe {
            poet_init(perf_goal,
                      num_states, control_states, cpu_states,
                      apply_func, curr_state_func,
                      period, buffer_depth, log_filename)
        };
        if poet.is_null() {
            return Err("Failed to instantiate POET object".to_string());
        }
        Ok(POET { poet: poet, })
    }

    /// Call at every iteration - at specified periods this function will (potentially) order
    /// changes to system or application state to try and meet timing constraints.
    pub fn apply_control(&mut self, tag: u64, window_rate: f64, window_power: f64) {
        unsafe {
            poet_apply_control(self.poet, tag, window_rate, window_power);
        }
    }
}

impl Drop for POET {
    /// Cleanup POET and deallocate resources in the underlying C struct.
    fn drop(&mut self) {
        unsafe {
            poet_destroy(self.poet);
        }
        println!("Cleaned up POET");
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use libc::{c_void, c_uint};

    #[test]
    fn test_basic() {
        let mut control_states = vec![POETControlState::default()];
        let mut cpu_states = vec![POETCpuState::default()];
        let mut poet = POET::new(100.0,
                                 control_states.as_mut_ptr(), cpu_states.as_mut_ptr(), 1,
                                 None, None,
                                 20u32, 1u32, None).unwrap();
        poet.apply_control(0, 1.0, 1.0);
    }

    #[test]
    fn test_rust_callbacks() {
        let mut control_states = vec![POETControlState::default()];
        let mut cpu_states = vec![POETCpuState::default()];
        let mut poet = POET::new(100.0,
                                 control_states.as_mut_ptr(), cpu_states.as_mut_ptr(), 1,
                                 Some(dummy_apply), Some(dummy_curr_state),
                                 20u32, 1u32, None).unwrap();
        for i in 0..50 {
            poet.apply_control(i, 1.0, 1.0);
        }
    }

    unsafe extern fn dummy_apply(_states: *mut c_void,
                                 _num_states: c_uint,
                                 _id: c_uint,
                                 _last_id: c_uint) {
        // do nothing
        println!("Received apply call");
    }

    unsafe extern fn dummy_curr_state (_states: *const c_void,
                                       _num_states: c_uint,
                                       _curr_state_id: *mut c_uint) -> i32 {
        println!("Received curr state call");
        // this is actually an invalid value, but forces the apply function to be called
        *_curr_state_id = _num_states;
        0
    }

}
<|endoftext|>


<commit_before>use std::net::SocketAddr;
use std::collections::VecDeque;
use std::rc::Rc;
use std::cell::RefCell;

use futures::prelude::*;
use tokio_core::net::TcpStream;
use tokio_core::reactor::Handle;
use bytes::Bytes;
use h2::{self, client as h2c};
use http::Request;

#[derive(Clone)]
pub struct PoolHandle {
    addr: SocketAddr,
    handle: Handle,
    pool: Rc<RefCell<VecDeque<h2c::Client<TcpStream, Bytes>>>>,
}

#[derive(Clone)]
pub struct H2ClientPool(PoolHandle);

impl H2ClientPool {
    pub fn new(handle: Handle, addr: SocketAddr) -> H2ClientPool {
        let h = PoolHandle {
            addr: addr,
            handle: handle,
            pool: Rc::new(RefCell::new(VecDeque::new())),
        };
        H2ClientPool(h)
    }

    pub fn handle(&self) -> PoolHandle {
        self.0.clone()
    }
}

impl Future for H2ClientPool {
    type Item = ();
    type Error = ();
    fn poll(&mut self) -> Poll<(), ()> {
        if Rc::strong_count(&self.0.pool) == 1 {
            let wired_strems: usize = self.0
                .pool
                .borrow()
                .iter()
                .map(h2c::Client::num_wired_streams)
                .sum();
            if wired_strems == 0 {
                // free memory
                return Ok(Async::Ready(()));
            }
        }

        for idx in 0..self.0.pool.borrow().len() {
            let mut pool = self.0.pool.borrow_mut();
            let remove = {
                let client = pool.get_mut(idx).unwrap();
                match client.poll() {
                    Ok(Async::Ready(())) => true,
                    Ok(Async::NotReady) => false,
                    Err(e) => {
                        eprintln!("{:?}", e);
                        true
                    }
                }
            };
            if remove {
                pool.remove(idx);
            }
        }
        Ok(Async::NotReady)
    }
}

impl PoolHandle {
    pub fn request<'a>(
        &self,
        request: Request<()>,
        end_of_stream: bool,
    ) -> impl Future<Item = h2c::Stream<Bytes>, Error = h2::Error> + 'a {
        let s = self.clone();
        async_block! {
            let mut client = await!(s.pop())?;
            let stream = client.request(request, end_of_stream)?;
            s.pool.borrow_mut().push_back(client);
            Ok(stream)
        }
    }

    fn new_client<'a>(
        &self,
    ) -> impl Future<Item = h2c::Client<TcpStream, Bytes>, Error = h2::Error> + 'a {
        TcpStream::connect(&self.addr, &self.handle)
            .map_err(Into::into)
            .and_then(|socket| h2c::Client::handshake(socket))
    }

    fn pop<'a>(&self) -> impl Future<Item = h2c::Client<TcpStream, Bytes>, Error = h2::Error> + 'a {
        let s = self.clone();
        async_block!{
            let client = s.pool.borrow_mut().pop_front();
            let mut client = match client {
                Some(x) => x,
                None => await!(s.new_client())?,
            };

            if client.poll_ready().unwrap().is_not_ready() {
                await!(s.pop())
            } else {
                Ok(client)
            }
        }
    }
}
<commit_msg>Fix `H2ClientPool` get stuck when empty<commit_after>use std::net::SocketAddr;
use std::collections::VecDeque;
use std::rc::Rc;
use std::cell::RefCell;

use futures::prelude::*;
use tokio_core::net::TcpStream;
use tokio_core::reactor::Handle;
use bytes::Bytes;
use h2::{self, client as h2c};
use http::Request;

#[derive(Clone)]
pub struct PoolHandle {
    addr: SocketAddr,
    handle: Handle,
    task: Rc<RefCell<Option<::futures::task::Task>>>,
    pool: Rc<RefCell<VecDeque<h2c::Client<TcpStream, Bytes>>>>,
}

#[derive(Clone)]
pub struct H2ClientPool(PoolHandle);

impl H2ClientPool {
    pub fn new(handle: Handle, addr: SocketAddr) -> H2ClientPool {
        let h = PoolHandle {
            addr: addr,
            handle: handle,
            task: Rc::new(RefCell::new(None)),
            pool: Rc::new(RefCell::new(VecDeque::new())),
        };
        H2ClientPool(h)
    }

    pub fn handle(&self) -> PoolHandle {
        self.0.clone()
    }
}

impl Future for H2ClientPool {
    type Item = ();
    type Error = ();
    fn poll(&mut self) -> Poll<(), ()> {
        if self.0.task.borrow().is_none() {
            *self.0.task.borrow_mut() = Some(::futures::task::current());
        }

        if Rc::strong_count(&self.0.pool) == 1 {
            let wired_strems: usize = self.0
                .pool
                .borrow()
                .iter()
                .map(h2c::Client::num_wired_streams)
                .sum();
            if wired_strems == 0 {
                // free memory
                return Ok(Async::Ready(()));
            }
        }

        for idx in 0..self.0.pool.borrow().len() {
            let mut pool = self.0.pool.borrow_mut();
            let remove = {
                let client = pool.get_mut(idx).unwrap();
                match client.poll() {
                    Ok(Async::Ready(())) => true,
                    Ok(Async::NotReady) => false,
                    Err(e) => {
                        eprintln!("{:?}", e);
                        true
                    }
                }
            };
            if remove {
                pool.remove(idx);
            }
        }
        Ok(Async::NotReady)
    }
}

impl PoolHandle {
    pub fn request<'a>(
        &self,
        request: Request<()>,
        end_of_stream: bool,
    ) -> impl Future<Item = h2c::Stream<Bytes>, Error = h2::Error> + 'a {
        let s = self.clone();
        async_block! {
            let mut client = await!(s.pop())?;
            let stream = client.request(request, end_of_stream)?;
            s.pool.borrow_mut().push_back(client);
            Ok(stream)
        }
    }

    fn new_client<'a>(
        &self,
    ) -> impl Future<Item = h2c::Client<TcpStream, Bytes>, Error = h2::Error> + 'a {
        let task = self.task.clone();
        TcpStream::connect(&self.addr, &self.handle)
            .map_err(Into::into)
            .and_then(move |socket| {
                if let Some(ref task) = *task.borrow() {
                    task.notify();
                }
                h2c::Client::handshake(socket)
            })
    }

    fn pop<'a>(&self) -> impl Future<Item = h2c::Client<TcpStream, Bytes>, Error = h2::Error> + 'a {
        let s = self.clone();
        async_block!{
            let client = s.pool.borrow_mut().pop_front();
            let mut client = match client {
                Some(x) => x,
                None => await!(s.new_client())?,
            };

            if client.poll_ready().unwrap().is_not_ready() {
                unimplemented!() //await!(s.pop())
            } else {
                Ok(client)
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::error::Error as StdError;

use chrono::{DateTime, Local, TimeZone};
use pulldown_cmark::{html, Parser, Options, OPTION_ENABLE_TABLES};
use serde_json::Map;

use error::{Error, Result};

/// blog post object
///
/// every blog post is composed of `head` part and `body` part.
/// the two part is separated by the first blank line.
///
/// the blog header part supported headers:
///
/// * date: the publish datetime, required, `date: 1970-01-01 00:00:00`
/// * tags: the tags of blog post, required, `tags: hello, world`
/// * hidden: whether hidden blog post or not, optional, default `true`, `hidden: false`
pub struct Post {
    /// root path of blog
    root: PathBuf,
    /// relative path of post from blog root directory
    pub path: PathBuf,
    /// post origin head part
    head: String,
    /// post origin body part
    body: String,
    /// headers from parsing the post origin head part
    metadata: HashMap<String, String>,
}

impl Post {
    pub fn new<P: AsRef<Path>>(root: P, path: P) -> Post {
        Post {
            root: root.as_ref().to_owned(),
            path: path.as_ref().to_owned(),
            head: String::new(),
            body: String::new(),

            metadata: HashMap::new(),
        }
    }

    /// the absolute path of blog post markdown file
    pub fn src(&self) -> PathBuf {
        self.root.join(&self.path)
    }

    /// the absolute path of blog post html file
    pub fn dest(&self) -> PathBuf {
        self.root.join("_builds/blog").join(self.path.with_extension("html"))
    }

    /// blog title
    pub fn title(&self) -> &str {
        self.path
            .file_stem()
            .and_then(|x| x.to_str())
            .expect(&format!("post filename format error: {}", self.path.display()))
    }

    /// blog publish time
    pub fn datetime(&self) -> DateTime<Local> {
        let date_value = self.metadata.get("date").expect(&format!("post({}) require date header", &self.path.display()));
        match Local.datetime_from_str(&date_value, "%Y-%m-%d %H:%M:%S") {
            Ok(datetime) => datetime,
            Err(why) => panic!("post({}) date header parse error: {}", &self.path.display(), why.description()),
        }
    }

    /// wether blog post is hidden or not
    pub fn is_hidden(&self) -> Result<bool> {
        let hidden_value = self.metadata.get("hidden").unwrap_or(&"false".to_string()).to_lowercase();
        match hidden_value.as_ref() {
            "false" | "f" => Ok(false),
            "true" | "t" => Ok(true),
            _ => Err(Error::PostHead),
        }
    }

    /// the post url
    pub fn url(&self) -> PathBuf {
        Path::new("/blog").join(&self.path).with_extension("html")
    }

    /// the rendered html content of post body port
    pub fn content(&self) -> String {
        let mut opts = Options::empty();
        opts.insert(OPTION_ENABLE_TABLES);
        let mut s = String::with_capacity(self.body.len() * 3 / 2);
        let p = Parser::new_ext(&self.body, opts);
        html::push_html(&mut s, p);
        s
    }

    /// the post tags
    pub fn tags(&self) -> Vec<&str> {
        if let Some(tag_str) = self.metadata.get("tags") {
            let mut res = tag_str.split(',')
                                 .map(|x| x.trim())
                                 .filter(|x| x.len() != 0)
                                 .collect::<Vec<&str>>();
            res.sort();
            res
        } else {
            Vec::new()
        }
    }

    /// post context for render
    pub fn map(&self) -> Map<&str, String> {
        let mut map = Map::new();
        map.insert("title", self.title().to_string());
        map.insert("url", format!("{}", self.url().display()));
        map.insert("datetime", self.datetime().format("%Y-%m-%d").to_string());

        map
    }

    /// load post head part and body part
    pub fn load(&mut self) -> Result<()> {
        debug!("loading post: {}", self.path.display());
        let mut pf = File::open(self.src())?;
        let mut content = String::new();
        pf.read_to_string(&mut content)?;
        let v: Vec<&str> = content.splitn(2, "\n\n").collect();
        if v.len() != 2 {
            return Err(Error::PostBody);
        }
        self.head = v[0].to_string();
        self.body = v[1].to_string();
        for line in self.head.lines() {
            let pair: Vec<&str> = line.splitn(2, ':').collect();
            if pair.len() != 2 {
                return Err(Error::PostHead);
            }
            self.metadata.insert(pair[0].trim().to_owned(), pair[1].trim().to_owned());
        }
        Ok(())
    }
}
<commit_msg>check post head and body empty<commit_after>use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use std::error::Error as StdError;

use chrono::{DateTime, Local, TimeZone};
use pulldown_cmark::{html, Parser, Options, OPTION_ENABLE_TABLES};
use serde_json::Map;

use error::{Error, Result};

/// blog post object
///
/// every blog post is composed of `head` part and `body` part.
/// the two part is separated by the first blank line.
///
/// the blog header part supported headers:
///
/// * date: the publish datetime, required, `date: 1970-01-01 00:00:00`
/// * tags: the tags of blog post, required, `tags: hello, world`
/// * hidden: whether hidden blog post or not, optional, default `true`, `hidden: false`
pub struct Post {
    /// root path of blog
    root: PathBuf,
    /// relative path of post from blog root directory
    pub path: PathBuf,
    /// post origin head part
    head: String,
    /// post origin body part
    body: String,
    /// headers from parsing the post origin head part
    metadata: HashMap<String, String>,
}

impl Post {
    pub fn new<P: AsRef<Path>>(root: P, path: P) -> Post {
        Post {
            root: root.as_ref().to_owned(),
            path: path.as_ref().to_owned(),
            head: String::new(),
            body: String::new(),

            metadata: HashMap::new(),
        }
    }

    /// the absolute path of blog post markdown file
    pub fn src(&self) -> PathBuf {
        self.root.join(&self.path)
    }

    /// the absolute path of blog post html file
    pub fn dest(&self) -> PathBuf {
        self.root.join("_builds/blog").join(self.path.with_extension("html"))
    }

    /// blog title
    pub fn title(&self) -> &str {
        self.path
            .file_stem()
            .and_then(|x| x.to_str())
            .expect(&format!("post filename format error: {}", self.path.display()))
    }

    /// blog publish time
    pub fn datetime(&self) -> DateTime<Local> {
        let date_value = self.metadata.get("date").expect(&format!("post({}) require date header", &self.path.display()));
        match Local.datetime_from_str(&date_value, "%Y-%m-%d %H:%M:%S") {
            Ok(datetime) => datetime,
            Err(why) => panic!("post({}) date header parse error: {}", &self.path.display(), why.description()),
        }
    }

    /// wether blog post is hidden or not
    pub fn is_hidden(&self) -> Result<bool> {
        let hidden_value = self.metadata.get("hidden").unwrap_or(&"false".to_string()).to_lowercase();
        match hidden_value.as_ref() {
            "false" | "f" => Ok(false),
            "true" | "t" => Ok(true),
            _ => Err(Error::PostHead),
        }
    }

    /// the post url
    pub fn url(&self) -> PathBuf {
        Path::new("/blog").join(&self.path).with_extension("html")
    }

    /// the rendered html content of post body port
    pub fn content(&self) -> String {
        let mut opts = Options::empty();
        opts.insert(OPTION_ENABLE_TABLES);
        let mut s = String::with_capacity(self.body.len() * 3 / 2);
        let p = Parser::new_ext(&self.body, opts);
        html::push_html(&mut s, p);
        s
    }

    /// the post tags
    pub fn tags(&self) -> Vec<&str> {
        if let Some(tag_str) = self.metadata.get("tags") {
            let mut res = tag_str.split(',')
                                 .map(|x| x.trim())
                                 .filter(|x| x.len() != 0)
                                 .collect::<Vec<&str>>();
            res.sort();
            res
        } else {
            Vec::new()
        }
    }

    /// post context for render
    pub fn map(&self) -> Map<&str, String> {
        let mut map = Map::new();
        map.insert("title", self.title().to_string());
        map.insert("url", format!("{}", self.url().display()));
        map.insert("datetime", self.datetime().format("%Y-%m-%d").to_string());

        map
    }

    /// load post head part and body part
    pub fn load(&mut self) -> Result<()> {
        debug!("loading post: {}", self.path.display());
        let mut pf = File::open(self.src())?;
        let mut content = String::new();
        pf.read_to_string(&mut content)?;
        let v: Vec<&str> = content.splitn(2, "\n\n").collect();
        if v.len() != 2 {
            return Err(Error::PostBody);
        }
        if v[0].trim().is_empty() {
            return Err(Error::PostHead);
        }
        if v[1].trim().is_empty() {
            return Err(Error::PostBody);
        }
        self.head = v[0].to_string();
        self.body = v[1].to_string();
        for line in self.head.lines() {
            let pair: Vec<&str> = line.splitn(2, ':').collect();
            if pair.len() != 2 {
                return Err(Error::PostHead);
            }
            self.metadata.insert(pair[0].trim().to_owned(), pair[1].trim().to_owned());
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>#![allow(non_snake_case)]
#![allow(non_camel_case_types)]

/* automatically generated by rust-bindgen */

pub type PaError = ::libc::c_int;
pub type Enum_PaErrorCode = ::libc::c_int;
pub static paNoError: ::libc::c_int = 0;
pub static paNotInitialized: ::libc::c_int = -10000;
pub static paUnanticipatedHostError: ::libc::c_int = -9999;
pub static paInvalidChannelCount: ::libc::c_int = -9998;
pub static paInvalidSampleRate: ::libc::c_int = -9997;
pub static paInvalidDevice: ::libc::c_int = -9996;
pub static paInvalidFlag: ::libc::c_int = -9995;
pub static paSampleFormatNotSupported: ::libc::c_int = -9994;
pub static paBadIODeviceCombination: ::libc::c_int = -9993;
pub static paInsufficientMemory: ::libc::c_int = -9992;
pub static paBufferTooBig: ::libc::c_int = -9991;
pub static paBufferTooSmall: ::libc::c_int = -9990;
pub static paNullCallback: ::libc::c_int = -9989;
pub static paBadStreamPtr: ::libc::c_int = -9988;
pub static paTimedOut: ::libc::c_int = -9987;
pub static paInternalError: ::libc::c_int = -9986;
pub static paDeviceUnavailable: ::libc::c_int = -9985;
pub static paIncompatibleHostApiSpecificStreamInfo: ::libc::c_int = -9984;
pub static paStreamIsStopped: ::libc::c_int = -9983;
pub static paStreamIsNotStopped: ::libc::c_int = -9982;
pub static paInputOverflowed: ::libc::c_int = -9981;
pub static paOutputUnderflowed: ::libc::c_int = -9980;
pub static paHostApiNotFound: ::libc::c_int = -9979;
pub static paInvalidHostApi: ::libc::c_int = -9978;
pub static paCanNotReadFromACallbackStream: ::libc::c_int = -9977;
pub static paCanNotWriteToACallbackStream: ::libc::c_int = -9976;
pub static paCanNotReadFromAnOutputOnlyStream: ::libc::c_int = -9975;
pub static paCanNotWriteToAnInputOnlyStream: ::libc::c_int = -9974;
pub static paIncompatibleStreamHostApi: ::libc::c_int = -9973;
pub static paBadBufferPtr: ::libc::c_int = -9972;
pub type PaErrorCode = Enum_PaErrorCode;
pub type PaDeviceIndex = ::libc::c_int;
pub type PaHostApiIndex = ::libc::c_int;
pub type Enum_PaHostApiTypeId = ::libc::c_uint;
pub static paInDevelopment: ::libc::c_uint = 0;
pub static paDirectSound: ::libc::c_uint = 1;
pub static paMME: ::libc::c_uint = 2;
pub static paASIO: ::libc::c_uint = 3;
pub static paSoundManager: ::libc::c_uint = 4;
pub static paCoreAudio: ::libc::c_uint = 5;
pub static paOSS: ::libc::c_uint = 7;
pub static paALSA: ::libc::c_uint = 8;
pub static paAL: ::libc::c_uint = 9;
pub static paBeOS: ::libc::c_uint = 10;
pub static paWDMKS: ::libc::c_uint = 11;
pub static paJACK: ::libc::c_uint = 12;
pub static paWASAPI: ::libc::c_uint = 13;
pub static paAudioScienceHPI: ::libc::c_uint = 14;
pub type PaHostApiTypeId = Enum_PaHostApiTypeId;
#[repr(C)]
pub struct Struct_PaHostApiInfo {
    pub structVersion: ::libc::c_int,
    pub _type: PaHostApiTypeId,
    pub name: *const ::libc::c_char,
    pub deviceCount: ::libc::c_int,
    pub defaultInputDevice: PaDeviceIndex,
    pub defaultOutputDevice: PaDeviceIndex,
}
pub type PaHostApiInfo = Struct_PaHostApiInfo;
#[repr(C)]
pub struct Struct_PaHostErrorInfo {
    pub hostApiType: PaHostApiTypeId,
    pub errorCode: ::libc::c_long,
    pub errorText: *const ::libc::c_char,
}
pub type PaHostErrorInfo = Struct_PaHostErrorInfo;
pub type PaTime = ::libc::c_double;
pub type PaSampleFormat = ::libc::c_ulong;
#[repr(C)]
pub struct Struct_PaDeviceInfo {
    pub structVersion: ::libc::c_int,
    pub name: *const ::libc::c_char,
    pub hostApi: PaHostApiIndex,
    pub maxInputChannels: ::libc::c_int,
    pub maxOutputChannels: ::libc::c_int,
    pub defaultLowInputLatency: PaTime,
    pub defaultLowOutputLatency: PaTime,
    pub defaultHighInputLatency: PaTime,
    pub defaultHighOutputLatency: PaTime,
    pub defaultSampleRate: ::libc::c_double,
}
pub type PaDeviceInfo = Struct_PaDeviceInfo;
#[repr(C)]
pub struct Struct_PaStreamParameters {
    pub device: PaDeviceIndex,
    pub channelCount: ::libc::c_int,
    pub sampleFormat: PaSampleFormat,
    pub suggestedLatency: PaTime,
    pub hostApiSpecificStreamInfo: *mut ::libc::c_void,
}
pub type PaStreamParameters = Struct_PaStreamParameters;
pub type PaStream = ::libc::c_void;
pub type PaStreamFlags = ::libc::c_ulong;
#[repr(C)]
pub struct Struct_PaStreamCallbackTimeInfo {
    pub inputBufferAdcTime: PaTime,
    pub currentTime: PaTime,
    pub outputBufferDacTime: PaTime,
}
pub type PaStreamCallbackTimeInfo = Struct_PaStreamCallbackTimeInfo;
pub type PaStreamCallbackFlags = ::libc::c_ulong;
pub type Enum_PaStreamCallbackResult = ::libc::c_uint;
pub static paContinue: ::libc::c_uint = 0;
pub static paComplete: ::libc::c_uint = 1;
pub static paAbort: ::libc::c_uint = 2;
pub type PaStreamCallbackResult = Enum_PaStreamCallbackResult;
pub type PaStreamCallback = ::libc::c_void;
pub type PaStreamFinishedCallback = ::libc::c_void;
#[repr(C)]
pub struct Struct_PaStreamInfo {
    pub structVersion: ::libc::c_int,
    pub inputLatency: PaTime,
    pub outputLatency: PaTime,
    pub sampleRate: ::libc::c_double,
}
pub type PaStreamInfo = Struct_PaStreamInfo;
#[link(name = "portaudio")]
extern "C" {
    pub fn Pa_GetVersion() -> ::libc::c_int;
    pub fn Pa_GetVersionText() -> *const ::libc::c_char;
    pub fn Pa_GetErrorText(errorCode: PaError) -> *const ::libc::c_char;
    pub fn Pa_Initialize() -> PaError;
    pub fn Pa_Terminate() -> PaError;
    pub fn Pa_GetHostApiCount() -> PaHostApiIndex;
    pub fn Pa_GetDefaultHostApi() -> PaHostApiIndex;
    pub fn Pa_GetHostApiInfo(hostApi: PaHostApiIndex) -> *const PaHostApiInfo;
    pub fn Pa_HostApiTypeIdToHostApiIndex(_type: PaHostApiTypeId) ->
     PaHostApiIndex;
    pub fn Pa_HostApiDeviceIndexToDeviceIndex(hostApi: PaHostApiIndex,
                                              hostApiDeviceIndex:
                                                  ::libc::c_int) ->
     PaDeviceIndex;
    pub fn Pa_GetLastHostErrorInfo() -> *const PaHostErrorInfo;
    pub fn Pa_GetDeviceCount() -> PaDeviceIndex;
    pub fn Pa_GetDefaultInputDevice() -> PaDeviceIndex;
    pub fn Pa_GetDefaultOutputDevice() -> PaDeviceIndex;
    pub fn Pa_GetDeviceInfo(device: PaDeviceIndex) -> *const PaDeviceInfo;
    pub fn Pa_IsFormatSupported(inputParameters: *const PaStreamParameters,
                                outputParameters: *const PaStreamParameters,
                                sampleRate: ::libc::c_double) -> PaError;
    pub fn Pa_OpenStream(stream: *mut *mut PaStream,
                         inputParameters: *const PaStreamParameters,
                         outputParameters: *const PaStreamParameters,
                         sampleRate: ::libc::c_double,
                         framesPerBuffer: ::libc::c_ulong,
                         streamFlags: PaStreamFlags,
                         streamCallback: Option<extern "C" fn(arg1: *const ::libc::c_void,
                                                       arg2: *mut ::libc::c_void,
                                                       arg3: ::libc::c_ulong,
                                                       arg4: *const PaStreamCallbackTimeInfo,
                                                       arg5: PaStreamCallbackFlags,
                                                       arg6: *mut ::libc::c_void)
                                                      -> ::libc::c_int>,
                         userData: *mut ::libc::c_void) -> PaError;
    pub fn Pa_OpenDefaultStream(stream: *mut *mut PaStream,
                                numInputChannels: ::libc::c_int,
                                numOutputChannels: ::libc::c_int,
                                sampleFormat: PaSampleFormat,
                                sampleRate: ::libc::c_double,
                                framesPerBuffer: ::libc::c_ulong,
                                streamCallback: Option<extern "C" fn(arg1: *const ::libc::c_void,
                                                              arg2: *mut ::libc::c_void,
                                                              arg3: ::libc::c_ulong,
                                                              arg4: *const PaStreamCallbackTimeInfo,
                                                              arg5: PaStreamCallbackFlags,
                                                              arg6: *mut ::libc::c_void)
                                                             -> ::libc::c_int>,
                                userData: *mut ::libc::c_void) -> PaError;
    pub fn Pa_CloseStream(stream: *mut PaStream) -> PaError;
    pub fn Pa_SetStreamFinishedCallback(stream: *mut PaStream,
                                        streamFinishedCallback: Option<extern "C" fn(arg1: *mut ::libc::c_void)>)
                                       -> PaError;
    pub fn Pa_StartStream(stream: *mut PaStream) -> PaError;
    pub fn Pa_StopStream(stream: *mut PaStream) -> PaError;
    pub fn Pa_AbortStream(stream: *mut PaStream) -> PaError;
    pub fn Pa_IsStreamStopped(stream: *mut PaStream) -> PaError;
    pub fn Pa_IsStreamActive(stream: *mut PaStream) -> PaError;
    pub fn Pa_GetStreamInfo(stream: *mut PaStream) -> *const PaStreamInfo;
    pub fn Pa_GetStreamTime(stream: *mut PaStream) -> PaTime;
    pub fn Pa_GetStreamCpuLoad(stream: *mut PaStream) -> ::libc::c_double;
    pub fn Pa_ReadStream(stream: *mut PaStream, buffer: *mut ::libc::c_void,
                         frames: ::libc::c_ulong) -> PaError;
    pub fn Pa_WriteStream(stream: *mut PaStream,
                          buffer: *const ::libc::c_void,
                          frames: ::libc::c_ulong) -> PaError;
    pub fn Pa_GetStreamReadAvailable(stream: *mut PaStream) -> ::libc::c_long;
    pub fn Pa_GetStreamWriteAvailable(stream: *mut PaStream) ->
     ::libc::c_long;
    pub fn Pa_GetSampleSize(format: PaSampleFormat) -> PaError;

    // Unused functions
    //pub fn Pa_Sleep(msec: ::libc::c_long);
}
<commit_msg>Allow non_uppercase_statics in ll.rs<commit_after>#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(non_uppercase_statics)]

/* automatically generated by rust-bindgen */

pub type PaError = ::libc::c_int;
pub type Enum_PaErrorCode = ::libc::c_int;
pub static paNoError: ::libc::c_int = 0;
pub static paNotInitialized: ::libc::c_int = -10000;
pub static paUnanticipatedHostError: ::libc::c_int = -9999;
pub static paInvalidChannelCount: ::libc::c_int = -9998;
pub static paInvalidSampleRate: ::libc::c_int = -9997;
pub static paInvalidDevice: ::libc::c_int = -9996;
pub static paInvalidFlag: ::libc::c_int = -9995;
pub static paSampleFormatNotSupported: ::libc::c_int = -9994;
pub static paBadIODeviceCombination: ::libc::c_int = -9993;
pub static paInsufficientMemory: ::libc::c_int = -9992;
pub static paBufferTooBig: ::libc::c_int = -9991;
pub static paBufferTooSmall: ::libc::c_int = -9990;
pub static paNullCallback: ::libc::c_int = -9989;
pub static paBadStreamPtr: ::libc::c_int = -9988;
pub static paTimedOut: ::libc::c_int = -9987;
pub static paInternalError: ::libc::c_int = -9986;
pub static paDeviceUnavailable: ::libc::c_int = -9985;
pub static paIncompatibleHostApiSpecificStreamInfo: ::libc::c_int = -9984;
pub static paStreamIsStopped: ::libc::c_int = -9983;
pub static paStreamIsNotStopped: ::libc::c_int = -9982;
pub static paInputOverflowed: ::libc::c_int = -9981;
pub static paOutputUnderflowed: ::libc::c_int = -9980;
pub static paHostApiNotFound: ::libc::c_int = -9979;
pub static paInvalidHostApi: ::libc::c_int = -9978;
pub static paCanNotReadFromACallbackStream: ::libc::c_int = -9977;
pub static paCanNotWriteToACallbackStream: ::libc::c_int = -9976;
pub static paCanNotReadFromAnOutputOnlyStream: ::libc::c_int = -9975;
pub static paCanNotWriteToAnInputOnlyStream: ::libc::c_int = -9974;
pub static paIncompatibleStreamHostApi: ::libc::c_int = -9973;
pub static paBadBufferPtr: ::libc::c_int = -9972;
pub type PaErrorCode = Enum_PaErrorCode;
pub type PaDeviceIndex = ::libc::c_int;
pub type PaHostApiIndex = ::libc::c_int;
pub type Enum_PaHostApiTypeId = ::libc::c_uint;
pub static paInDevelopment: ::libc::c_uint = 0;
pub static paDirectSound: ::libc::c_uint = 1;
pub static paMME: ::libc::c_uint = 2;
pub static paASIO: ::libc::c_uint = 3;
pub static paSoundManager: ::libc::c_uint = 4;
pub static paCoreAudio: ::libc::c_uint = 5;
pub static paOSS: ::libc::c_uint = 7;
pub static paALSA: ::libc::c_uint = 8;
pub static paAL: ::libc::c_uint = 9;
pub static paBeOS: ::libc::c_uint = 10;
pub static paWDMKS: ::libc::c_uint = 11;
pub static paJACK: ::libc::c_uint = 12;
pub static paWASAPI: ::libc::c_uint = 13;
pub static paAudioScienceHPI: ::libc::c_uint = 14;
pub type PaHostApiTypeId = Enum_PaHostApiTypeId;
#[repr(C)]
pub struct Struct_PaHostApiInfo {
    pub structVersion: ::libc::c_int,
    pub _type: PaHostApiTypeId,
    pub name: *const ::libc::c_char,
    pub deviceCount: ::libc::c_int,
    pub defaultInputDevice: PaDeviceIndex,
    pub defaultOutputDevice: PaDeviceIndex,
}
pub type PaHostApiInfo = Struct_PaHostApiInfo;
#[repr(C)]
pub struct Struct_PaHostErrorInfo {
    pub hostApiType: PaHostApiTypeId,
    pub errorCode: ::libc::c_long,
    pub errorText: *const ::libc::c_char,
}
pub type PaHostErrorInfo = Struct_PaHostErrorInfo;
pub type PaTime = ::libc::c_double;
pub type PaSampleFormat = ::libc::c_ulong;
#[repr(C)]
pub struct Struct_PaDeviceInfo {
    pub structVersion: ::libc::c_int,
    pub name: *const ::libc::c_char,
    pub hostApi: PaHostApiIndex,
    pub maxInputChannels: ::libc::c_int,
    pub maxOutputChannels: ::libc::c_int,
    pub defaultLowInputLatency: PaTime,
    pub defaultLowOutputLatency: PaTime,
    pub defaultHighInputLatency: PaTime,
    pub defaultHighOutputLatency: PaTime,
    pub defaultSampleRate: ::libc::c_double,
}
pub type PaDeviceInfo = Struct_PaDeviceInfo;
#[repr(C)]
pub struct Struct_PaStreamParameters {
    pub device: PaDeviceIndex,
    pub channelCount: ::libc::c_int,
    pub sampleFormat: PaSampleFormat,
    pub suggestedLatency: PaTime,
    pub hostApiSpecificStreamInfo: *mut ::libc::c_void,
}
pub type PaStreamParameters = Struct_PaStreamParameters;
pub type PaStream = ::libc::c_void;
pub type PaStreamFlags = ::libc::c_ulong;
#[repr(C)]
pub struct Struct_PaStreamCallbackTimeInfo {
    pub inputBufferAdcTime: PaTime,
    pub currentTime: PaTime,
    pub outputBufferDacTime: PaTime,
}
pub type PaStreamCallbackTimeInfo = Struct_PaStreamCallbackTimeInfo;
pub type PaStreamCallbackFlags = ::libc::c_ulong;
pub type Enum_PaStreamCallbackResult = ::libc::c_uint;
pub static paContinue: ::libc::c_uint = 0;
pub static paComplete: ::libc::c_uint = 1;
pub static paAbort: ::libc::c_uint = 2;
pub type PaStreamCallbackResult = Enum_PaStreamCallbackResult;
pub type PaStreamCallback = ::libc::c_void;
pub type PaStreamFinishedCallback = ::libc::c_void;
#[repr(C)]
pub struct Struct_PaStreamInfo {
    pub structVersion: ::libc::c_int,
    pub inputLatency: PaTime,
    pub outputLatency: PaTime,
    pub sampleRate: ::libc::c_double,
}
pub type PaStreamInfo = Struct_PaStreamInfo;
#[link(name = "portaudio")]
extern "C" {
    pub fn Pa_GetVersion() -> ::libc::c_int;
    pub fn Pa_GetVersionText() -> *const ::libc::c_char;
    pub fn Pa_GetErrorText(errorCode: PaError) -> *const ::libc::c_char;
    pub fn Pa_Initialize() -> PaError;
    pub fn Pa_Terminate() -> PaError;
    pub fn Pa_GetHostApiCount() -> PaHostApiIndex;
    pub fn Pa_GetDefaultHostApi() -> PaHostApiIndex;
    pub fn Pa_GetHostApiInfo(hostApi: PaHostApiIndex) -> *const PaHostApiInfo;
    pub fn Pa_HostApiTypeIdToHostApiIndex(_type: PaHostApiTypeId) ->
     PaHostApiIndex;
    pub fn Pa_HostApiDeviceIndexToDeviceIndex(hostApi: PaHostApiIndex,
                                              hostApiDeviceIndex:
                                                  ::libc::c_int) ->
     PaDeviceIndex;
    pub fn Pa_GetLastHostErrorInfo() -> *const PaHostErrorInfo;
    pub fn Pa_GetDeviceCount() -> PaDeviceIndex;
    pub fn Pa_GetDefaultInputDevice() -> PaDeviceIndex;
    pub fn Pa_GetDefaultOutputDevice() -> PaDeviceIndex;
    pub fn Pa_GetDeviceInfo(device: PaDeviceIndex) -> *const PaDeviceInfo;
    pub fn Pa_IsFormatSupported(inputParameters: *const PaStreamParameters,
                                outputParameters: *const PaStreamParameters,
                                sampleRate: ::libc::c_double) -> PaError;
    pub fn Pa_OpenStream(stream: *mut *mut PaStream,
                         inputParameters: *const PaStreamParameters,
                         outputParameters: *const PaStreamParameters,
                         sampleRate: ::libc::c_double,
                         framesPerBuffer: ::libc::c_ulong,
                         streamFlags: PaStreamFlags,
                         streamCallback: Option<extern "C" fn(arg1: *const ::libc::c_void,
                                                       arg2: *mut ::libc::c_void,
                                                       arg3: ::libc::c_ulong,
                                                       arg4: *const PaStreamCallbackTimeInfo,
                                                       arg5: PaStreamCallbackFlags,
                                                       arg6: *mut ::libc::c_void)
                                                      -> ::libc::c_int>,
                         userData: *mut ::libc::c_void) -> PaError;
    pub fn Pa_OpenDefaultStream(stream: *mut *mut PaStream,
                                numInputChannels: ::libc::c_int,
                                numOutputChannels: ::libc::c_int,
                                sampleFormat: PaSampleFormat,
                                sampleRate: ::libc::c_double,
                                framesPerBuffer: ::libc::c_ulong,
                                streamCallback: Option<extern "C" fn(arg1: *const ::libc::c_void,
                                                              arg2: *mut ::libc::c_void,
                                                              arg3: ::libc::c_ulong,
                                                              arg4: *const PaStreamCallbackTimeInfo,
                                                              arg5: PaStreamCallbackFlags,
                                                              arg6: *mut ::libc::c_void)
                                                             -> ::libc::c_int>,
                                userData: *mut ::libc::c_void) -> PaError;
    pub fn Pa_CloseStream(stream: *mut PaStream) -> PaError;
    pub fn Pa_SetStreamFinishedCallback(stream: *mut PaStream,
                                        streamFinishedCallback: Option<extern "C" fn(arg1: *mut ::libc::c_void)>)
                                       -> PaError;
    pub fn Pa_StartStream(stream: *mut PaStream) -> PaError;
    pub fn Pa_StopStream(stream: *mut PaStream) -> PaError;
    pub fn Pa_AbortStream(stream: *mut PaStream) -> PaError;
    pub fn Pa_IsStreamStopped(stream: *mut PaStream) -> PaError;
    pub fn Pa_IsStreamActive(stream: *mut PaStream) -> PaError;
    pub fn Pa_GetStreamInfo(stream: *mut PaStream) -> *const PaStreamInfo;
    pub fn Pa_GetStreamTime(stream: *mut PaStream) -> PaTime;
    pub fn Pa_GetStreamCpuLoad(stream: *mut PaStream) -> ::libc::c_double;
    pub fn Pa_ReadStream(stream: *mut PaStream, buffer: *mut ::libc::c_void,
                         frames: ::libc::c_ulong) -> PaError;
    pub fn Pa_WriteStream(stream: *mut PaStream,
                          buffer: *const ::libc::c_void,
                          frames: ::libc::c_ulong) -> PaError;
    pub fn Pa_GetStreamReadAvailable(stream: *mut PaStream) -> ::libc::c_long;
    pub fn Pa_GetStreamWriteAvailable(stream: *mut PaStream) ->
     ::libc::c_long;
    pub fn Pa_GetSampleSize(format: PaSampleFormat) -> PaError;

    // Unused functions
    //pub fn Pa_Sleep(msec: ::libc::c_long);
}
<|endoftext|>


<commit_before>//! Structs for reading a ZIP archive

use crc32::Crc32Reader;
use compression::CompressionMethod;
use spec;
use result::{ZipResult, ZipError};
use std::io;
use std::io::prelude::*;
use std::collections::HashMap;
use flate2;
use flate2::FlateReadExt;
use podio::{ReadPodExt, LittleEndian};
use types::{ZipFileData, System};
use cp437::FromCp437;
use msdos_time::{TmMsDosExt, MsDosDateTime};

#[cfg(feature = "bzip2")]
use bzip2::read::BzDecoder;

mod ffi {
    pub const S_IFDIR: u32 = 0o0040000;
    pub const S_IFREG: u32 = 0o0100000;
}

/// Wrapper for reading the contents of a ZIP file.
///
/// ```
/// fn doit() -> zip::result::ZipResult<()>
/// {
///     use std::io::prelude::*;
///
///     // For demonstration purposes we read from an empty buffer.
///     // Normally a File object would be used.
///     let buf: &[u8] = &[0u8; 128];
///     let mut reader = std::io::Cursor::new(buf);
///
///     let mut zip = try!(zip::ZipArchive::new(reader));
///
///     for i in 0..zip.len()
///     {
///         let mut file = zip.by_index(i).unwrap();
///         println!("Filename: {}", file.name());
///         let first_byte = try!(file.bytes().next().unwrap());
///         println!("{}", first_byte);
///     }
///     Ok(())
/// }
///
/// println!("Result: {:?}", doit());
/// ```
#[derive(Debug)]
pub struct ZipArchive<R: Read + io::Seek>
{
    reader: R,
    files: Vec<ZipFileData>,
    names_map: HashMap<String, usize>,
}

enum ZipFileReader<'a> {
    Stored(Crc32Reader<io::Take<&'a mut Read>>),
    Deflated(Crc32Reader<flate2::read::DeflateDecoder<io::Take<&'a mut Read>>>),
    #[cfg(feature = "bzip2")]
    Bzip2(Crc32Reader<BzDecoder<io::Take<&'a mut Read>>>),
}

/// A struct for reading a zip file
pub struct ZipFile<'a> {
    data: &'a ZipFileData,
    reader: ZipFileReader<'a>,
}

fn unsupported_zip_error<T>(detail: &'static str) -> ZipResult<T>
{
    Err(ZipError::UnsupportedArchive(detail))
}

impl<R: Read+io::Seek> ZipArchive<R>
{
    /// Opens a Zip archive and parses the central directory
    pub fn new(mut reader: R) -> ZipResult<ZipArchive<R>> {
        let footer = try!(spec::CentralDirectoryEnd::find_and_parse(&mut reader));

        if footer.disk_number != footer.disk_with_central_directory { return unsupported_zip_error("Support for multi-disk files is not implemented") }

        let directory_start = footer.central_directory_offset as u64;
        let number_of_files = footer.number_of_files_on_this_disk as usize;

        let mut files = Vec::with_capacity(number_of_files);
        let mut names_map = HashMap::new();

        try!(reader.seek(io::SeekFrom::Start(directory_start)));
        for _ in 0 .. number_of_files
        {
            let file = try!(central_header_to_zip_file(&mut reader));
            names_map.insert(file.file_name.clone(), files.len());
            files.push(file);
        }

        Ok(ZipArchive { reader: reader, files: files, names_map: names_map })
    }

    /// Number of files contained in this zip.
    ///
    /// ```
    /// fn iter() {
    ///     let mut zip = zip::ZipArchive::new(std::io::Cursor::new(vec![])).unwrap();
    ///
    ///     for i in 0..zip.len() {
    ///         let mut file = zip.by_index(i).unwrap();
    ///         // Do something with file i
    ///     }
    /// }
    /// ```
    pub fn len(&self) -> usize
    {
        self.files.len()
    }

    /// Search for a file entry by name
    pub fn by_name<'a>(&'a mut self, name: &str) -> ZipResult<ZipFile<'a>>
    {
        let index = match self.names_map.get(name) {
            Some(index) => *index,
            None => { return Err(ZipError::FileNotFound); },
        };
        self.by_index(index)
    }

    /// Get a contained file by index
    pub fn by_index<'a>(&'a mut self, file_number: usize) -> ZipResult<ZipFile<'a>>
    {
        if file_number >= self.files.len() { return Err(ZipError::FileNotFound); }
        let ref data = self.files[file_number];
        let pos = data.data_start;

        if data.encrypted
        {
            return unsupported_zip_error("Encrypted files are not supported")
        }

        try!(self.reader.seek(io::SeekFrom::Start(pos)));
        let limit_reader = (self.reader.by_ref() as &mut Read).take(data.compressed_size);

        let reader = match data.compression_method
        {
            CompressionMethod::Stored =>
            {
                ZipFileReader::Stored(Crc32Reader::new(
                    limit_reader,
                    data.crc32))
            },
            CompressionMethod::Deflated =>
            {
                let deflate_reader = limit_reader.deflate_decode();
                ZipFileReader::Deflated(Crc32Reader::new(
                    deflate_reader,
                    data.crc32))
            },
            #[cfg(feature = "bzip2")]
            CompressionMethod::Bzip2 =>
            {
                let bzip2_reader = BzDecoder::new(limit_reader);
                ZipFileReader::Bzip2(Crc32Reader::new(
                    bzip2_reader,
                    data.crc32))
            },
            _ => return unsupported_zip_error("Compression method not supported"),
        };
        Ok(ZipFile { reader: reader, data: data })
    }

    /// Unwrap and return the inner reader object
    ///
    /// The position of the reader is undefined.
    pub fn into_inner(self) -> R
    {
        self.reader
    }
}

fn central_header_to_zip_file<R: Read+io::Seek>(reader: &mut R) -> ZipResult<ZipFileData>
{
    // Parse central header
    let signature = try!(reader.read_u32::<LittleEndian>());
    if signature != spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE
    {
        return Err(ZipError::InvalidArchive("Invalid Central Directory header"))
    }

    let version_made_by = try!(reader.read_u16::<LittleEndian>());
    let _version_to_extract = try!(reader.read_u16::<LittleEndian>());
    let flags = try!(reader.read_u16::<LittleEndian>());
    let encrypted = flags & 1 == 1;
    let is_utf8 = flags & (1 << 11) != 0;
    let compression_method = try!(reader.read_u16::<LittleEndian>());
    let last_mod_time = try!(reader.read_u16::<LittleEndian>());
    let last_mod_date = try!(reader.read_u16::<LittleEndian>());
    let crc32 = try!(reader.read_u32::<LittleEndian>());
    let compressed_size = try!(reader.read_u32::<LittleEndian>());
    let uncompressed_size = try!(reader.read_u32::<LittleEndian>());
    let file_name_length = try!(reader.read_u16::<LittleEndian>()) as usize;
    let extra_field_length = try!(reader.read_u16::<LittleEndian>()) as usize;
    let file_comment_length = try!(reader.read_u16::<LittleEndian>()) as usize;
    let _disk_number = try!(reader.read_u16::<LittleEndian>());
    let _internal_file_attributes = try!(reader.read_u16::<LittleEndian>());
    let external_file_attributes = try!(reader.read_u32::<LittleEndian>());
    let offset = try!(reader.read_u32::<LittleEndian>()) as u64;
    let file_name_raw = try!(ReadPodExt::read_exact(reader, file_name_length));
    let extra_field = try!(ReadPodExt::read_exact(reader, extra_field_length));
    let file_comment_raw  = try!(ReadPodExt::read_exact(reader, file_comment_length));

    let file_name = match is_utf8
    {
        true => String::from_utf8_lossy(&*file_name_raw).into_owned(),
        false => file_name_raw.clone().from_cp437(),
    };
    let file_comment = match is_utf8
    {
        true => String::from_utf8_lossy(&*file_comment_raw).into_owned(),
        false => file_comment_raw.from_cp437(),
    };

    // Remember end of central header
    let return_position = try!(reader.seek(io::SeekFrom::Current(0)));

    // Parse local header
    try!(reader.seek(io::SeekFrom::Start(offset)));
    let signature = try!(reader.read_u32::<LittleEndian>());
    if signature != spec::LOCAL_FILE_HEADER_SIGNATURE
    {
        return Err(ZipError::InvalidArchive("Invalid local file header"))
    }

    try!(reader.seek(io::SeekFrom::Current(22)));
    let file_name_length = try!(reader.read_u16::<LittleEndian>()) as u64;
    let extra_field_length = try!(reader.read_u16::<LittleEndian>()) as u64;
    let magic_and_header = 4 + 22 + 2 + 2;
    let data_start = offset + magic_and_header + file_name_length + extra_field_length;

    // Construct the result
    let mut result = ZipFileData
    {
        system: System::from_u8((version_made_by >> 8) as u8),
        version_made_by: version_made_by as u8,
        encrypted: encrypted,
        compression_method: CompressionMethod::from_u16(compression_method),
        last_modified_time: try!(::time::Tm::from_msdos(MsDosDateTime::new(last_mod_time, last_mod_date))),
        crc32: crc32,
        compressed_size: compressed_size as u64,
        uncompressed_size: uncompressed_size as u64,
        file_name: file_name,
        file_name_raw: file_name_raw,
        file_comment: file_comment,
        header_start: offset,
        data_start: data_start,
        external_attributes: external_file_attributes,
    };

    try!(parse_extra_field(&mut result, &*extra_field));

    // Go back after the central header
    try!(reader.seek(io::SeekFrom::Start(return_position)));

    Ok(result)
}

fn parse_extra_field(_file: &mut ZipFileData, data: &[u8]) -> ZipResult<()>
{
    let mut reader = io::Cursor::new(data);

    while (reader.position() as usize) < data.len()
    {
        let kind = try!(reader.read_u16::<LittleEndian>());
        let len = try!(reader.read_u16::<LittleEndian>());
        match kind
        {
            _ => try!(reader.seek(io::SeekFrom::Current(len as i64))),
        };
    }
    Ok(())
}

/// Methods for retreiving information on zip files
impl<'a> ZipFile<'a> {
    fn get_reader(&mut self) -> &mut Read {
        match self.reader {
           ZipFileReader::Stored(ref mut r) => r as &mut Read,
           ZipFileReader::Deflated(ref mut r) => r as &mut Read,
           #[cfg(feature = "bzip2")]
           ZipFileReader::Bzip2(ref mut r) => r as &mut Read,
        }
    }
    /// Get the version of the file
    pub fn version_made_by(&self) -> (u8, u8) {
        (self.data.version_made_by / 10, self.data.version_made_by % 10)
    }
    /// Get the name of the file
    pub fn name(&self) -> &str {
        &*self.data.file_name
    }
    /// Get the name of the file, in the raw (internal) byte representation.
    pub fn name_raw(&self) -> &[u8] {
        &*self.data.file_name_raw
    }
    /// Get the comment of the file
    pub fn comment(&self) -> &str {
        &*self.data.file_comment
    }
    /// Get the compression method used to store the file
    pub fn compression(&self) -> CompressionMethod {
        self.data.compression_method
    }
    /// Get the size of the file in the archive
    pub fn compressed_size(&self) -> u64 {
        self.data.compressed_size
    }
    /// Get the size of the file when uncompressed
    pub fn size(&self) -> u64 {
        self.data.uncompressed_size
    }
    /// Get the time the file was last modified
    pub fn last_modified(&self) -> ::time::Tm {
        self.data.last_modified_time
    }
    /// Get unix mode for the file
    pub fn unix_mode(&self) -> Option<u32> {
        match self.data.system {
            System::Unix => {
                Some(self.data.external_attributes >> 16)
            },
            System::Dos => {
                // Interpret MSDOS directory bit
                let mut mode = if 0x10 == (self.data.external_attributes & 0x10) {
                    ffi::S_IFDIR | 0o0775
                } else {
                    ffi::S_IFREG | 0o0664
                };
                if 0x01 == (self.data.external_attributes & 0x01) {
                    // Read-only bit; strip write permissions
                    mode &= 0o0555;
                }
                Some(mode)
            },
            _ => None,
        }
    }
    /// Get the CRC32 hash of the original file
    pub fn crc32(&self) -> u32 {
        self.data.crc32
    }
}

impl<'a> Read for ZipFile<'a> {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         self.get_reader().read(buf)
     }
}
<commit_msg>Ignore Io errors in extra field<commit_after>//! Structs for reading a ZIP archive

use crc32::Crc32Reader;
use compression::CompressionMethod;
use spec;
use result::{ZipResult, ZipError};
use std::io;
use std::io::prelude::*;
use std::collections::HashMap;
use flate2;
use flate2::FlateReadExt;
use podio::{ReadPodExt, LittleEndian};
use types::{ZipFileData, System};
use cp437::FromCp437;
use msdos_time::{TmMsDosExt, MsDosDateTime};

#[cfg(feature = "bzip2")]
use bzip2::read::BzDecoder;

mod ffi {
    pub const S_IFDIR: u32 = 0o0040000;
    pub const S_IFREG: u32 = 0o0100000;
}

/// Wrapper for reading the contents of a ZIP file.
///
/// ```
/// fn doit() -> zip::result::ZipResult<()>
/// {
///     use std::io::prelude::*;
///
///     // For demonstration purposes we read from an empty buffer.
///     // Normally a File object would be used.
///     let buf: &[u8] = &[0u8; 128];
///     let mut reader = std::io::Cursor::new(buf);
///
///     let mut zip = try!(zip::ZipArchive::new(reader));
///
///     for i in 0..zip.len()
///     {
///         let mut file = zip.by_index(i).unwrap();
///         println!("Filename: {}", file.name());
///         let first_byte = try!(file.bytes().next().unwrap());
///         println!("{}", first_byte);
///     }
///     Ok(())
/// }
///
/// println!("Result: {:?}", doit());
/// ```
#[derive(Debug)]
pub struct ZipArchive<R: Read + io::Seek>
{
    reader: R,
    files: Vec<ZipFileData>,
    names_map: HashMap<String, usize>,
}

enum ZipFileReader<'a> {
    Stored(Crc32Reader<io::Take<&'a mut Read>>),
    Deflated(Crc32Reader<flate2::read::DeflateDecoder<io::Take<&'a mut Read>>>),
    #[cfg(feature = "bzip2")]
    Bzip2(Crc32Reader<BzDecoder<io::Take<&'a mut Read>>>),
}

/// A struct for reading a zip file
pub struct ZipFile<'a> {
    data: &'a ZipFileData,
    reader: ZipFileReader<'a>,
}

fn unsupported_zip_error<T>(detail: &'static str) -> ZipResult<T>
{
    Err(ZipError::UnsupportedArchive(detail))
}

impl<R: Read+io::Seek> ZipArchive<R>
{
    /// Opens a Zip archive and parses the central directory
    pub fn new(mut reader: R) -> ZipResult<ZipArchive<R>> {
        let footer = try!(spec::CentralDirectoryEnd::find_and_parse(&mut reader));

        if footer.disk_number != footer.disk_with_central_directory { return unsupported_zip_error("Support for multi-disk files is not implemented") }

        let directory_start = footer.central_directory_offset as u64;
        let number_of_files = footer.number_of_files_on_this_disk as usize;

        let mut files = Vec::with_capacity(number_of_files);
        let mut names_map = HashMap::new();

        try!(reader.seek(io::SeekFrom::Start(directory_start)));
        for _ in 0 .. number_of_files
        {
            let file = try!(central_header_to_zip_file(&mut reader));
            names_map.insert(file.file_name.clone(), files.len());
            files.push(file);
        }

        Ok(ZipArchive { reader: reader, files: files, names_map: names_map })
    }

    /// Number of files contained in this zip.
    ///
    /// ```
    /// fn iter() {
    ///     let mut zip = zip::ZipArchive::new(std::io::Cursor::new(vec![])).unwrap();
    ///
    ///     for i in 0..zip.len() {
    ///         let mut file = zip.by_index(i).unwrap();
    ///         // Do something with file i
    ///     }
    /// }
    /// ```
    pub fn len(&self) -> usize
    {
        self.files.len()
    }

    /// Search for a file entry by name
    pub fn by_name<'a>(&'a mut self, name: &str) -> ZipResult<ZipFile<'a>>
    {
        let index = match self.names_map.get(name) {
            Some(index) => *index,
            None => { return Err(ZipError::FileNotFound); },
        };
        self.by_index(index)
    }

    /// Get a contained file by index
    pub fn by_index<'a>(&'a mut self, file_number: usize) -> ZipResult<ZipFile<'a>>
    {
        if file_number >= self.files.len() { return Err(ZipError::FileNotFound); }
        let ref data = self.files[file_number];
        let pos = data.data_start;

        if data.encrypted
        {
            return unsupported_zip_error("Encrypted files are not supported")
        }

        try!(self.reader.seek(io::SeekFrom::Start(pos)));
        let limit_reader = (self.reader.by_ref() as &mut Read).take(data.compressed_size);

        let reader = match data.compression_method
        {
            CompressionMethod::Stored =>
            {
                ZipFileReader::Stored(Crc32Reader::new(
                    limit_reader,
                    data.crc32))
            },
            CompressionMethod::Deflated =>
            {
                let deflate_reader = limit_reader.deflate_decode();
                ZipFileReader::Deflated(Crc32Reader::new(
                    deflate_reader,
                    data.crc32))
            },
            #[cfg(feature = "bzip2")]
            CompressionMethod::Bzip2 =>
            {
                let bzip2_reader = BzDecoder::new(limit_reader);
                ZipFileReader::Bzip2(Crc32Reader::new(
                    bzip2_reader,
                    data.crc32))
            },
            _ => return unsupported_zip_error("Compression method not supported"),
        };
        Ok(ZipFile { reader: reader, data: data })
    }

    /// Unwrap and return the inner reader object
    ///
    /// The position of the reader is undefined.
    pub fn into_inner(self) -> R
    {
        self.reader
    }
}

fn central_header_to_zip_file<R: Read+io::Seek>(reader: &mut R) -> ZipResult<ZipFileData>
{
    // Parse central header
    let signature = try!(reader.read_u32::<LittleEndian>());
    if signature != spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE
    {
        return Err(ZipError::InvalidArchive("Invalid Central Directory header"))
    }

    let version_made_by = try!(reader.read_u16::<LittleEndian>());
    let _version_to_extract = try!(reader.read_u16::<LittleEndian>());
    let flags = try!(reader.read_u16::<LittleEndian>());
    let encrypted = flags & 1 == 1;
    let is_utf8 = flags & (1 << 11) != 0;
    let compression_method = try!(reader.read_u16::<LittleEndian>());
    let last_mod_time = try!(reader.read_u16::<LittleEndian>());
    let last_mod_date = try!(reader.read_u16::<LittleEndian>());
    let crc32 = try!(reader.read_u32::<LittleEndian>());
    let compressed_size = try!(reader.read_u32::<LittleEndian>());
    let uncompressed_size = try!(reader.read_u32::<LittleEndian>());
    let file_name_length = try!(reader.read_u16::<LittleEndian>()) as usize;
    let extra_field_length = try!(reader.read_u16::<LittleEndian>()) as usize;
    let file_comment_length = try!(reader.read_u16::<LittleEndian>()) as usize;
    let _disk_number = try!(reader.read_u16::<LittleEndian>());
    let _internal_file_attributes = try!(reader.read_u16::<LittleEndian>());
    let external_file_attributes = try!(reader.read_u32::<LittleEndian>());
    let offset = try!(reader.read_u32::<LittleEndian>()) as u64;
    let file_name_raw = try!(ReadPodExt::read_exact(reader, file_name_length));
    let extra_field = try!(ReadPodExt::read_exact(reader, extra_field_length));
    let file_comment_raw  = try!(ReadPodExt::read_exact(reader, file_comment_length));

    let file_name = match is_utf8
    {
        true => String::from_utf8_lossy(&*file_name_raw).into_owned(),
        false => file_name_raw.clone().from_cp437(),
    };
    let file_comment = match is_utf8
    {
        true => String::from_utf8_lossy(&*file_comment_raw).into_owned(),
        false => file_comment_raw.from_cp437(),
    };

    // Remember end of central header
    let return_position = try!(reader.seek(io::SeekFrom::Current(0)));

    // Parse local header
    try!(reader.seek(io::SeekFrom::Start(offset)));
    let signature = try!(reader.read_u32::<LittleEndian>());
    if signature != spec::LOCAL_FILE_HEADER_SIGNATURE
    {
        return Err(ZipError::InvalidArchive("Invalid local file header"))
    }

    try!(reader.seek(io::SeekFrom::Current(22)));
    let file_name_length = try!(reader.read_u16::<LittleEndian>()) as u64;
    let extra_field_length = try!(reader.read_u16::<LittleEndian>()) as u64;
    let magic_and_header = 4 + 22 + 2 + 2;
    let data_start = offset + magic_and_header + file_name_length + extra_field_length;

    // Construct the result
    let mut result = ZipFileData
    {
        system: System::from_u8((version_made_by >> 8) as u8),
        version_made_by: version_made_by as u8,
        encrypted: encrypted,
        compression_method: CompressionMethod::from_u16(compression_method),
        last_modified_time: try!(::time::Tm::from_msdos(MsDosDateTime::new(last_mod_time, last_mod_date))),
        crc32: crc32,
        compressed_size: compressed_size as u64,
        uncompressed_size: uncompressed_size as u64,
        file_name: file_name,
        file_name_raw: file_name_raw,
        file_comment: file_comment,
        header_start: offset,
        data_start: data_start,
        external_attributes: external_file_attributes,
    };

    match parse_extra_field(&mut result, &*extra_field) {
        Ok(..) | Err(ZipError::Io(..)) => {},
        Err(e) => try!(Err(e)),
    }

    // Go back after the central header
    try!(reader.seek(io::SeekFrom::Start(return_position)));

    Ok(result)
}

fn parse_extra_field(_file: &mut ZipFileData, data: &[u8]) -> ZipResult<()>
{
    let mut reader = io::Cursor::new(data);

    while (reader.position() as usize) < data.len()
    {
        let kind = try!(reader.read_u16::<LittleEndian>());
        let len = try!(reader.read_u16::<LittleEndian>());
        match kind
        {
            _ => try!(reader.seek(io::SeekFrom::Current(len as i64))),
        };
    }
    Ok(())
}

/// Methods for retreiving information on zip files
impl<'a> ZipFile<'a> {
    fn get_reader(&mut self) -> &mut Read {
        match self.reader {
           ZipFileReader::Stored(ref mut r) => r as &mut Read,
           ZipFileReader::Deflated(ref mut r) => r as &mut Read,
           #[cfg(feature = "bzip2")]
           ZipFileReader::Bzip2(ref mut r) => r as &mut Read,
        }
    }
    /// Get the version of the file
    pub fn version_made_by(&self) -> (u8, u8) {
        (self.data.version_made_by / 10, self.data.version_made_by % 10)
    }
    /// Get the name of the file
    pub fn name(&self) -> &str {
        &*self.data.file_name
    }
    /// Get the name of the file, in the raw (internal) byte representation.
    pub fn name_raw(&self) -> &[u8] {
        &*self.data.file_name_raw
    }
    /// Get the comment of the file
    pub fn comment(&self) -> &str {
        &*self.data.file_comment
    }
    /// Get the compression method used to store the file
    pub fn compression(&self) -> CompressionMethod {
        self.data.compression_method
    }
    /// Get the size of the file in the archive
    pub fn compressed_size(&self) -> u64 {
        self.data.compressed_size
    }
    /// Get the size of the file when uncompressed
    pub fn size(&self) -> u64 {
        self.data.uncompressed_size
    }
    /// Get the time the file was last modified
    pub fn last_modified(&self) -> ::time::Tm {
        self.data.last_modified_time
    }
    /// Get unix mode for the file
    pub fn unix_mode(&self) -> Option<u32> {
        match self.data.system {
            System::Unix => {
                Some(self.data.external_attributes >> 16)
            },
            System::Dos => {
                // Interpret MSDOS directory bit
                let mut mode = if 0x10 == (self.data.external_attributes & 0x10) {
                    ffi::S_IFDIR | 0o0775
                } else {
                    ffi::S_IFREG | 0o0664
                };
                if 0x01 == (self.data.external_attributes & 0x01) {
                    // Read-only bit; strip write permissions
                    mode &= 0o0555;
                }
                Some(mode)
            },
            _ => None,
        }
    }
    /// Get the CRC32 hash of the original file
    pub fn crc32(&self) -> u32 {
        self.data.crc32
    }
}

impl<'a> Read for ZipFile<'a> {
     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
         self.get_reader().read(buf)
     }
}
<|endoftext|>