<commit_before>//! EventFD binding
//!
//! This crate implements a simple binding for Linux eventfd(). See
//! eventfd(2) for specific details of behaviour.

extern crate libc;

use libc::{c_int, c_uint, c_void};
use std::io::{IoResult, IoError};
use std::os::unix::{AsRawFd,Fd};

pub struct EventFD {
    fd: uint,
    flags: uint,
}

unsafe impl Send for EventFD {}
unsafe impl Sync for EventFD {}

/// Construct a semaphore-style EventFD.
pub const EFD_SEMAPHORE: uint = 0x00001; // 00000001

/// In non-blocking mode, reads and writes will return IoError
/// containing EAGAIN rather than blocking.
pub const EFD_NONBLOCK: uint  = 0x00800; // 00004000

/// Set the close-on-exec flag on the eventfd.
pub const EFD_CLOEXEC: uint   = 0x80000; // 02000000

impl EventFD {
    /// Create a new EventFD. Flags is the bitwise OR of EFD_* constants, or 0 for no flags.
    /// The underlying file descriptor is closed when the EventFD instance's lifetime ends.
    ///
    /// TODO: work out how to integrate this FD into the wider world
    /// of fds. There's currently no way to poll/select on the fd.
    pub fn new(initval: uint, flags: uint) -> IoResult<EventFD> {
        let r = unsafe { eventfd(initval as u32, flags as u32) };

        if r < 0 {
            Err(IoError::last_error())
        } else {
            Ok(EventFD { fd: r as uint, flags: flags })
        }
    }

    /// Read the current value of the eventfd. This will block until
    /// the value is non-zero. In semaphore mode this will only ever
    /// decrement the count by 1 and return 1; otherwise it atomically
    /// returns the current value and sets it to zero.
    pub fn read(&self) -> IoResult<u64> {
        let mut ret : u64 = 0;
        let r = unsafe {
            let ptr : *mut u64 = &mut ret;
            ::libc::read(self.fd as c_int, ptr as *mut c_void, std::mem::size_of_val(&ret) as u64)
        };

        if r < 0 {
            Err(IoError::last_error())
        } else {
            Ok(ret)
        }
    }

    /// Add to the current value. Blocks if the value would wrap u64.
    pub fn write(&self, val: u64) -> IoResult<()> {
        let r = unsafe {
            let ptr : *const u64 = &val;
            ::libc::write(self.fd as c_int, ptr as *const c_void, std::mem::size_of_val(&val) as u64)
        };

        if r < 0 {
            Err(IoError::last_error())
        } else {
            Ok(())
        }
    }

    /// Return a stream of events. The channel has a synchronous
    /// sender because there's no point in building up a queue of
    /// events; if this task blocks on send, the event state will
    /// still update.
    ///
    /// The task will exit if the receiver end is shut down.
    ///
    /// This will be a CPU-spin loop if the EventFD is created
    /// non-blocking.
    ///
    /// XXX FIXME This has no way of terminating except if the other
    /// end closes the connection, and only then if we're not blocked
    /// in the read()...
    pub fn events(&self) -> std::comm::Receiver<u64> {
        let (tx, rx) = std::comm::sync_channel(1);
        let c = self.clone();

        std::thread::Thread::spawn(move || {
            loop {
                match c.read() {
                    Ok(v) => match tx.send_opt(v) {
                        Ok(_) => (),
                        Err(_) => break,
                    },
                    Err(e) => panic!("read failed: {}", e),
                }
            }
        }).detach();

        rx
    }
}

impl AsRawFd for EventFD {
    /// Return the raw underlying fd. The caller must make sure self's
    /// lifetime is longer than any users of the fd.
    fn as_raw_fd(&self) -> Fd {
        self.fd as Fd
    }
}

impl Drop for EventFD {
    fn drop(&mut self) {
        let r = unsafe { ::libc::close(self.fd as c_int) };
        if r < 0 {
            panic!("eventfd close {} failed", self.fd)
        }
    }
}

/// Construct a linked clone of an existing EventFD. Once created, the
/// new instance interacts with the original in a way that's
/// indistinguishable from the original.
impl Clone for EventFD {
    fn clone(&self) -> EventFD {
        let r = unsafe { ::libc::dup(self.fd as c_int) };
        if r < 0 {
            panic!("EventFD clone dup failed: {}", IoError::last_error())
        }

        EventFD { fd: r as uint, flags: self.flags }
    }
}

#[link(name = "c")]
extern "C" {
    fn eventfd(initval: c_uint, flags: c_uint) -> c_int;
}

#[test]
fn test_basic() {
    let (tx,rx) = std::comm::channel();
    let efd = match EventFD::new(10, 0) {
        Err(e) => panic!("new failed {}", e),
        Ok(fd) => fd,
    };
    let cefd = efd.clone();

    assert!(efd.read() == Ok(10));

    std::thread::Thread::spawn(move || {
        assert!(cefd.read() == Ok(7));
        assert!(cefd.write(1) == Ok(()));
        assert!(cefd.write(2) == Ok(()));
        tx.send(());
    }).detach();

    assert!(efd.write(7) == Ok(()));
    rx.recv();
    assert!(efd.read() == Ok(3));
}

#[test]
fn test_sema() {
    let efd = match EventFD::new(0, EFD_SEMAPHORE | EFD_NONBLOCK) {
        Err(e) => panic!("new failed {}", e),
        Ok(fd) => fd,
    };

    match efd.read() {
        Err(ref e) if e.kind == std::io::ResourceUnavailable => (), // ok
        Err(e) => panic!("unexpected error {}", e),
        Ok(v) => panic!("unexpected success {}", v),
    }

    assert!(efd.write(5) == Ok(()));

    assert!(efd.read() == Ok(1));
    assert!(efd.read() == Ok(1));
    assert!(efd.read() == Ok(1));
    assert!(efd.read() == Ok(1));
    assert!(efd.read() == Ok(1));
    match efd.read() {
        Err(ref e) if e.kind == std::io::ResourceUnavailable => (), // ok
        Err(e) => panic!("unexpected error {}", e),
        Ok(v) => panic!("unexpected success {}", v),
    }
}

#[test]
fn test_stream() {
    let efd = match EventFD::new(11, EFD_SEMAPHORE) {
        Err(e) => panic!("new failed {}", e),
        Ok(fd) => fd,
    };
    let mut count = 0;

    // only take 10 of 11 so the stream task doesn't block in read and hang the test
    for v in efd.events().iter().take(10) {
        assert!(v == 1);
        count += v;
    }

    assert!(count == 10)
}

#[test]
fn test_chan() {
    let (tx,rx) = std::comm::channel();
    let efd = match EventFD::new(10, 0) {
        Err(e) => panic!("new failed {}", e),
        Ok(fd) => fd,
    };

    assert!(efd.write(1) == Ok(()));
    tx.send(efd);

    let t = std::thread::Thread::spawn(move || {
        let efd = rx.recv();
        assert!(efd.read() == Ok(11))
    }).join();

    match t {
        Ok(_) => println!("ok"),
        Err(_) => panic!("failed"),
    }
}
<commit_msg>import Thread in file to clean up spawn points<commit_after>//! EventFD binding
//!
//! This crate implements a simple binding for Linux eventfd(). See
//! eventfd(2) for specific details of behaviour.

extern crate libc;

use libc::{c_int, c_uint, c_void};
use std::io::{IoResult, IoError};
use std::os::unix::{AsRawFd,Fd};
use std::thread::Thread;

pub struct EventFD {
    fd: uint,
    flags: uint,
}

unsafe impl Send for EventFD {}
unsafe impl Sync for EventFD {}

/// Construct a semaphore-style EventFD.
pub const EFD_SEMAPHORE: uint = 0x00001; // 00000001

/// In non-blocking mode, reads and writes will return IoError
/// containing EAGAIN rather than blocking.
pub const EFD_NONBLOCK: uint  = 0x00800; // 00004000

/// Set the close-on-exec flag on the eventfd.
pub const EFD_CLOEXEC: uint   = 0x80000; // 02000000

impl EventFD {
    /// Create a new EventFD. Flags is the bitwise OR of EFD_* constants, or 0 for no flags.
    /// The underlying file descriptor is closed when the EventFD instance's lifetime ends.
    ///
    /// TODO: work out how to integrate this FD into the wider world
    /// of fds. There's currently no way to poll/select on the fd.
    pub fn new(initval: uint, flags: uint) -> IoResult<EventFD> {
        let r = unsafe { eventfd(initval as u32, flags as u32) };

        if r < 0 {
            Err(IoError::last_error())
        } else {
            Ok(EventFD { fd: r as uint, flags: flags })
        }
    }

    /// Read the current value of the eventfd. This will block until
    /// the value is non-zero. In semaphore mode this will only ever
    /// decrement the count by 1 and return 1; otherwise it atomically
    /// returns the current value and sets it to zero.
    pub fn read(&self) -> IoResult<u64> {
        let mut ret : u64 = 0;
        let r = unsafe {
            let ptr : *mut u64 = &mut ret;
            ::libc::read(self.fd as c_int, ptr as *mut c_void, std::mem::size_of_val(&ret) as u64)
        };

        if r < 0 {
            Err(IoError::last_error())
        } else {
            Ok(ret)
        }
    }

    /// Add to the current value. Blocks if the value would wrap u64.
    pub fn write(&self, val: u64) -> IoResult<()> {
        let r = unsafe {
            let ptr : *const u64 = &val;
            ::libc::write(self.fd as c_int, ptr as *const c_void, std::mem::size_of_val(&val) as u64)
        };

        if r < 0 {
            Err(IoError::last_error())
        } else {
            Ok(())
        }
    }

    /// Return a stream of events. The channel has a synchronous
    /// sender because there's no point in building up a queue of
    /// events; if this task blocks on send, the event state will
    /// still update.
    ///
    /// The task will exit if the receiver end is shut down.
    ///
    /// This will be a CPU-spin loop if the EventFD is created
    /// non-blocking.
    ///
    /// XXX FIXME This has no way of terminating except if the other
    /// end closes the connection, and only then if we're not blocked
    /// in the read()...
    pub fn events(&self) -> std::comm::Receiver<u64> {
        let (tx, rx) = std::comm::sync_channel(1);
        let c = self.clone();

        Thread::spawn(move || {
            loop {
                match c.read() {
                    Ok(v) => match tx.send_opt(v) {
                        Ok(_) => (),
                        Err(_) => break,
                    },
                    Err(e) => panic!("read failed: {}", e),
                }
            }
        }).detach();

        rx
    }
}

impl AsRawFd for EventFD {
    /// Return the raw underlying fd. The caller must make sure self's
    /// lifetime is longer than any users of the fd.
    fn as_raw_fd(&self) -> Fd {
        self.fd as Fd
    }
}

impl Drop for EventFD {
    fn drop(&mut self) {
        let r = unsafe { ::libc::close(self.fd as c_int) };
        if r < 0 {
            panic!("eventfd close {} failed", self.fd)
        }
    }
}

/// Construct a linked clone of an existing EventFD. Once created, the
/// new instance interacts with the original in a way that's
/// indistinguishable from the original.
impl Clone for EventFD {
    fn clone(&self) -> EventFD {
        let r = unsafe { ::libc::dup(self.fd as c_int) };
        if r < 0 {
            panic!("EventFD clone dup failed: {}", IoError::last_error())
        }

        EventFD { fd: r as uint, flags: self.flags }
    }
}

#[link(name = "c")]
extern "C" {
    fn eventfd(initval: c_uint, flags: c_uint) -> c_int;
}

#[test]
fn test_basic() {
    let (tx,rx) = std::comm::channel();
    let efd = match EventFD::new(10, 0) {
        Err(e) => panic!("new failed {}", e),
        Ok(fd) => fd,
    };
    let cefd = efd.clone();

    assert!(efd.read() == Ok(10));

    Thread::spawn(move || {
        assert!(cefd.read() == Ok(7));
        assert!(cefd.write(1) == Ok(()));
        assert!(cefd.write(2) == Ok(()));
        tx.send(());
    }).detach();

    assert!(efd.write(7) == Ok(()));
    rx.recv();
    assert!(efd.read() == Ok(3));
}

#[test]
fn test_sema() {
    let efd = match EventFD::new(0, EFD_SEMAPHORE | EFD_NONBLOCK) {
        Err(e) => panic!("new failed {}", e),
        Ok(fd) => fd,
    };

    match efd.read() {
        Err(ref e) if e.kind == std::io::ResourceUnavailable => (), // ok
        Err(e) => panic!("unexpected error {}", e),
        Ok(v) => panic!("unexpected success {}", v),
    }

    assert!(efd.write(5) == Ok(()));

    assert!(efd.read() == Ok(1));
    assert!(efd.read() == Ok(1));
    assert!(efd.read() == Ok(1));
    assert!(efd.read() == Ok(1));
    assert!(efd.read() == Ok(1));
    match efd.read() {
        Err(ref e) if e.kind == std::io::ResourceUnavailable => (), // ok
        Err(e) => panic!("unexpected error {}", e),
        Ok(v) => panic!("unexpected success {}", v),
    }
}

#[test]
fn test_stream() {
    let efd = match EventFD::new(11, EFD_SEMAPHORE) {
        Err(e) => panic!("new failed {}", e),
        Ok(fd) => fd,
    };
    let mut count = 0;

    // only take 10 of 11 so the stream task doesn't block in read and hang the test
    for v in efd.events().iter().take(10) {
        assert!(v == 1);
        count += v;
    }

    assert!(count == 10)
}

#[test]
fn test_chan() {
    let (tx,rx) = std::comm::channel();
    let efd = match EventFD::new(10, 0) {
        Err(e) => panic!("new failed {}", e),
        Ok(fd) => fd,
    };

    assert!(efd.write(1) == Ok(()));
    tx.send(efd);

    let t = Thread::spawn(move || {
        let efd = rx.recv();
        assert!(efd.read() == Ok(11))
    }).join();

    match t {
        Ok(_) => println!("ok"),
        Err(_) => panic!("failed"),
    }
}
<|endoftext|>


<commit_before>//! lzf-rs is a small wrapper around [LibLZF](http://software.schmorp.de/pkg/liblzf.html),
//! a very small data compression library.
//!
//! The compression algorithm is very, very fast, yet still written in portable C.
//!
//! This Rust library is a wrapper around the library from Marc Lehmann.
//!
//! # Basic Operation
//!
//! ```rust,no_run
//! # use lzf;
//! let data = "foobar";
//!
//! let compressed = lzf::compress(data.as_bytes()).unwrap();
//!
//! let decompressed = lzf::decompress(compressed.as_slice(), data.len()).unwrap();
//! ```

#![experimental]

extern crate libc;

use libc::{c_uint,c_void};

extern {
    fn lzf_compress(in_data: *const c_void, in_len: c_uint, out_data: *const c_void, out_len: c_uint) -> c_uint;
    fn lzf_decompress(in_data: *const c_void, in_len: c_uint, out_data: *const c_void, out_len: c_uint) -> c_uint;
}

#[derive(PartialEq, Eq, Clone, Show, Copy)]
pub enum LzfError {
    BufferTooSmall,
    DataCorrupted,
    NoCompressionPossible,
    UnknownError(uint)
}
pub type LzfResult<T> = Result<T, LzfError>;

/// Compress the given data, if possible.
/// The return value will be set to the error if compression fails.
///
/// The buffer is always set to the same size as the input buffer.
/// If that is not enough to hold the lzf-compressed data,
/// an error will be returned.
///
/// Example:
///
/// ```rust
/// let data = "foobar";
/// let compressed = lzf::compress(data.as_bytes());
/// ```
pub fn compress(data: &[u8]) -> LzfResult<Vec<u8>> {
    let data_len = data.len();
    let mut out : Vec<u8> = Vec::with_capacity(data_len);

    let result = unsafe { lzf_compress(data.as_ptr() as *const c_void, data_len as c_uint,
                                       out.as_ptr() as *const c_void, data_len as c_uint) };

    match result {
        0 => Err(LzfError::NoCompressionPossible),
        _ => {
            unsafe { out.set_len(result as uint) };
            Ok(out)
        }
    }
}

/// Decompress the given data, if possible.
/// The return value will be set to the error if compression fails.
///
/// The length of the output buffer can be specified.
/// If the output buffer is not large enough to hold the decompressed data,
/// BufferTooSmall is returned.
/// Otherwise the number of decompressed bytes
/// (i.e. the original length of the data) is returned.
///
/// If an error in the compressed data is detected, DataCorrupted is returned.
///
/// Example:
///
/// ```rust,no_run
/// let data = "[your-compressed-data]";
/// let decompressed = lzf::decompress(data.as_bytes(), 10);
/// ```
pub fn decompress(data: &[u8], out_len: uint) -> LzfResult<Vec<u8>> {
    let mut out : Vec<u8> = Vec::with_capacity(out_len);

    let result = unsafe { lzf_decompress(data.as_ptr() as *const c_void, data.len() as c_uint,
                                         out.as_ptr() as *const c_void, out_len as c_uint) };
    match result {
        0 => {
            match std::os::errno() {
                7  => Err(LzfError::BufferTooSmall),
                22 => Err(LzfError::DataCorrupted),
                e  => Err(LzfError::UnknownError(e))
            }
        },
        _ => {
            unsafe { out.set_len(result as uint) };
            Ok(out)
        }
    }
}

#[test]
fn test_compress_skips_short() {
    match compress("foo".as_bytes()) {
        Ok(_) => panic!("Compression did _something_, with is wrong for 'foo'"),
        Err(err) => assert_eq!(LzfError::NoCompressionPossible, err)
    }
}

#[test]
fn test_compress_lorem() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    match compress(lorem.as_bytes()) {
        Ok(compressed) => {
            assert_eq!(272, compressed.len())
        }
        Err(err) => panic!("Compression failed with error {}", err)
    }
}

#[test]
fn test_compress_decompress_lorem_round() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = match compress(lorem.as_bytes()) {
        Ok(c) => c,
        Err(err) => panic!("Compression failed with error {}", err)
    };

    match decompress(compressed.as_slice(), lorem.len()) {
        Ok(decompressed) => {
            assert_eq!(lorem.len(), decompressed.len());
            assert_eq!(lorem.as_bytes(), decompressed.as_slice());
        },
        Err(err) => panic!("Decompression failed with error {}", err)
    };
}

#[test]
fn test_decompress_fails_with_short_buffer() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = match compress(lorem.as_bytes()) {
        Ok(c) => c,
        Err(err) => panic!("Compression failed with error {}", err)
    };

    match decompress(compressed.as_slice(), 10) {
        Ok(_) => panic!("Decompression worked. That should not happen"),
        Err(err) => assert_eq!(LzfError::BufferTooSmall, err)
    }
}

#[test]
fn test_decompress_fails_for_corrupted_data() {
    let lorem = "Lorem ipsum dolor sit amet";

    match decompress(lorem.as_bytes(), lorem.len()) {
        Ok(_) => panic!("Decompression worked. That should not happen"),
        Err(err) => assert_eq!(LzfError::DataCorrupted, err)
    }
}
<commit_msg>Use new usize instead of uint<commit_after>//! lzf-rs is a small wrapper around [LibLZF](http://software.schmorp.de/pkg/liblzf.html),
//! a very small data compression library.
//!
//! The compression algorithm is very, very fast, yet still written in portable C.
//!
//! This Rust library is a wrapper around the library from Marc Lehmann.
//!
//! # Basic Operation
//!
//! ```rust,no_run
//! # use lzf;
//! let data = "foobar";
//!
//! let compressed = lzf::compress(data.as_bytes()).unwrap();
//!
//! let decompressed = lzf::decompress(compressed.as_slice(), data.len()).unwrap();
//! ```

#![experimental]

extern crate libc;

use libc::{c_uint,c_void};

extern {
    fn lzf_compress(in_data: *const c_void, in_len: c_uint, out_data: *const c_void, out_len: c_uint) -> c_uint;
    fn lzf_decompress(in_data: *const c_void, in_len: c_uint, out_data: *const c_void, out_len: c_uint) -> c_uint;
}

#[derive(PartialEq, Eq, Clone, Show, Copy)]
pub enum LzfError {
    BufferTooSmall,
    DataCorrupted,
    NoCompressionPossible,
    UnknownError(usize)
}
pub type LzfResult<T> = Result<T, LzfError>;

/// Compress the given data, if possible.
/// The return value will be set to the error if compression fails.
///
/// The buffer is always set to the same size as the input buffer.
/// If that is not enough to hold the lzf-compressed data,
/// an error will be returned.
///
/// Example:
///
/// ```rust
/// let data = "foobar";
/// let compressed = lzf::compress(data.as_bytes());
/// ```
pub fn compress(data: &[u8]) -> LzfResult<Vec<u8>> {
    let data_len = data.len();
    let mut out : Vec<u8> = Vec::with_capacity(data_len);

    let result = unsafe { lzf_compress(data.as_ptr() as *const c_void, data_len as c_uint,
                                       out.as_ptr() as *const c_void, data_len as c_uint) };

    match result {
        0 => Err(LzfError::NoCompressionPossible),
        _ => {
            unsafe { out.set_len(result as usize) };
            Ok(out)
        }
    }
}

/// Decompress the given data, if possible.
/// The return value will be set to the error if compression fails.
///
/// The length of the output buffer can be specified.
/// If the output buffer is not large enough to hold the decompressed data,
/// BufferTooSmall is returned.
/// Otherwise the number of decompressed bytes
/// (i.e. the original length of the data) is returned.
///
/// If an error in the compressed data is detected, DataCorrupted is returned.
///
/// Example:
///
/// ```rust,no_run
/// let data = "[your-compressed-data]";
/// let decompressed = lzf::decompress(data.as_bytes(), 10);
/// ```
pub fn decompress(data: &[u8], out_len: usize) -> LzfResult<Vec<u8>> {
    let mut out : Vec<u8> = Vec::with_capacity(out_len);

    let result = unsafe { lzf_decompress(data.as_ptr() as *const c_void, data.len() as c_uint,
                                         out.as_ptr() as *const c_void, out_len as c_uint) };
    match result {
        0 => {
            match std::os::errno() {
                7  => Err(LzfError::BufferTooSmall),
                22 => Err(LzfError::DataCorrupted),
                e  => Err(LzfError::UnknownError(e))
            }
        },
        _ => {
            unsafe { out.set_len(result as usize) };
            Ok(out)
        }
    }
}

#[test]
fn test_compress_skips_short() {
    match compress("foo".as_bytes()) {
        Ok(_) => panic!("Compression did _something_, with is wrong for 'foo'"),
        Err(err) => assert_eq!(LzfError::NoCompressionPossible, err)
    }
}

#[test]
fn test_compress_lorem() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    match compress(lorem.as_bytes()) {
        Ok(compressed) => {
            assert_eq!(272, compressed.len())
        }
        Err(err) => panic!("Compression failed with error {}", err)
    }
}

#[test]
fn test_compress_decompress_lorem_round() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = match compress(lorem.as_bytes()) {
        Ok(c) => c,
        Err(err) => panic!("Compression failed with error {}", err)
    };

    match decompress(compressed.as_slice(), lorem.len()) {
        Ok(decompressed) => {
            assert_eq!(lorem.len(), decompressed.len());
            assert_eq!(lorem.as_bytes(), decompressed.as_slice());
        },
        Err(err) => panic!("Decompression failed with error {}", err)
    };
}

#[test]
fn test_decompress_fails_with_short_buffer() {
    let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

    let compressed = match compress(lorem.as_bytes()) {
        Ok(c) => c,
        Err(err) => panic!("Compression failed with error {}", err)
    };

    match decompress(compressed.as_slice(), 10) {
        Ok(_) => panic!("Decompression worked. That should not happen"),
        Err(err) => assert_eq!(LzfError::BufferTooSmall, err)
    }
}

#[test]
fn test_decompress_fails_for_corrupted_data() {
    let lorem = "Lorem ipsum dolor sit amet";

    match decompress(lorem.as_bytes(), lorem.len()) {
        Ok(_) => panic!("Decompression worked. That should not happen"),
        Err(err) => assert_eq!(LzfError::DataCorrupted, err)
    }
}
<|endoftext|>


<commit_before>//! Algorithmia client library
//!
//! # Examples
//!
//! ```no_run
//! use algorithmia::Algorithmia;
//! use algorithmia::algo::{Algorithm, Version};
//!
//! // Initialize with an API key
//! let client = Algorithmia::client("111112222233333444445555566");
//! let moving_avg = client.algo(("timeseries/SimpleMovingAverage", "0.1"));
//!
//! // Run the algorithm using a type safe decoding of the output to Vec<int>
//! //   since this algorithm outputs results as a JSON array of integers
//! let input = (vec![0,1,2,3,15,4,5,6,7], 3);
//! let result: Vec<f64> = moving_avg.pipe(&input).unwrap().decode().unwrap();
//! println!("Completed with result: {:?}", result);
//! ```

#![doc(html_logo_url = "https://algorithmia.com/assets/images/apple-touch-icon.png")]

#![feature(proc_macro)]

#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate hyper;
#[macro_use]
extern crate quick_error;

extern crate base64;
extern crate serde;
extern crate serde_json;
extern crate chrono;

use algo::{Algorithm, AlgoRef};
use data::{DataDir, DataFile, DataObject, HasDataPath};
use client::HttpClient;

use std::clone;

pub mod algo;
pub mod data;
pub mod error;
pub mod client;
pub use hyper::{mime, Url};
pub use client::ApiAuth::{self, SimpleAuth, NoAuth};

pub mod prelude {
    pub use ::Algorithmia;
    pub use ::client::ApiAuth::{self, SimpleAuth, NoAuth};
    pub use ::algo::{EntryPoint, DecodedEntryPoint, AlgoInput, AlgoOutput};
    pub use ::data::HasDataPath;
}

static DEFAULT_API_BASE_URL: &'static str = "https://api.algorithmia.com";

/// The top-level struct for instantiating Algorithmia client endpoints
pub struct Algorithmia {
    http_client: HttpClient,
}

impl<'a, 'c> Algorithmia {
    /// Instantiate a new client
    ///
    /// Client should be instatiated with your API key, except
    ///   when running within an algorithm on the Algorithmia platform.
    ///
    /// # Examples
    /// ```
    /// use algorithmia::*;
    /// // Initialize a client
    /// let client = Algorithmia::client("simUseYourApiKey");
    ///
    /// // Initialize a client (for algorithms running on the Algorithmia platform)
    /// let client = Algorithmia::client(NoAuth);
    /// ```
    pub fn client<A: Into<ApiAuth>>(api_key: A) -> Algorithmia {
        let api_address = std::env::var("ALGORITHMIA_API").unwrap_or(DEFAULT_API_BASE_URL.into());
        Algorithmia { http_client: HttpClient::new(api_key.into(), api_address) }
    }

    /// Instantiate a new client against alternate API servers
    pub fn alt_client<A: Into<ApiAuth>>(base_url: Url, api_key: A) -> Algorithmia {
        Algorithmia { http_client: HttpClient::new(api_key.into(), base_url.into_string()) }
    }

    /// Instantiate an [`Algorithm`](algo/algorithm.struct.html) from this client
    ///
    /// By using In
    /// # Examples
    ///
    /// ```
    /// use algorithmia::Algorithmia;
    /// use algorithmia::algo::Version;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let factor = client.algo("anowell/Dijkstra/0.1");
    /// let factor = client.algo(("anowell/Dijkstra", Version::Latest));
    /// ```
    pub fn algo<A: Into<AlgoRef>>(&self, algorithm: A) -> Algorithm {
        Algorithm::new(self.http_client.clone(), algorithm.into())
    }

    /// Instantiate a `DataDirectory` from this client
    ///
    /// # Examples
    ///
    /// ```
    /// use algorithmia::Algorithmia;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let rustfoo = client.dir("data://.my/rustfoo");
    /// ```
    pub fn dir(&self, path: &'a str) -> DataDir {
        DataDir::new(self.http_client.clone(), path)
    }

    /// Instantiate a `DataDirectory` from this client
    ///
    /// # Examples
    ///
    /// ```
    /// use algorithmia::Algorithmia;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let rustfoo = client.file("data://.my/rustfoo");
    /// ```
    pub fn file(&self, path: &'a str) -> DataFile {
        DataFile::new(self.http_client.clone(), path)
    }

    /// Instantiate a `DataPath` from this client
    ///
    /// Use this if you don't explicitly know if a Data URI is to a directory or file
    ///
    /// # Examples
    ///
    /// ```
    /// use algorithmia::Algorithmia;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let rustfoo = client.data("data://.my/rustfoo/what_am_i");
    /// ```
    pub fn data(&self, path: &'a str) -> DataObject {
        DataObject::new(self.http_client.clone(), path)
    }
}

/// Allow cloning in order to reuse http client (and API key) for multiple connections
impl clone::Clone for Algorithmia {
    fn clone(&self) -> Algorithmia {
        Algorithmia { http_client: self.http_client.clone() }
    }
}
<commit_msg>Reexport Error at root<commit_after>//! Algorithmia client library
//!
//! # Examples
//!
//! ```no_run
//! use algorithmia::Algorithmia;
//! use algorithmia::algo::{Algorithm, Version};
//!
//! // Initialize with an API key
//! let client = Algorithmia::client("111112222233333444445555566");
//! let moving_avg = client.algo(("timeseries/SimpleMovingAverage", "0.1"));
//!
//! // Run the algorithm using a type safe decoding of the output to Vec<int>
//! //   since this algorithm outputs results as a JSON array of integers
//! let input = (vec![0,1,2,3,15,4,5,6,7], 3);
//! let result: Vec<f64> = moving_avg.pipe(&input).unwrap().decode().unwrap();
//! println!("Completed with result: {:?}", result);
//! ```

#![doc(html_logo_url = "https://algorithmia.com/assets/images/apple-touch-icon.png")]

#![feature(proc_macro)]

#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate hyper;
#[macro_use]
extern crate quick_error;

extern crate base64;
extern crate serde;
extern crate serde_json;
extern crate chrono;

use algo::{Algorithm, AlgoRef};
use data::{DataDir, DataFile, DataObject, HasDataPath};
use client::HttpClient;

use std::clone;

pub mod algo;
pub mod data;
pub mod error;
pub mod client;
pub use error::Error;
pub use hyper::{mime, Url};
pub use client::ApiAuth::{self, SimpleAuth, NoAuth};

pub mod prelude {
    pub use ::Algorithmia;
    pub use ::client::ApiAuth::{self, SimpleAuth, NoAuth};
    pub use ::algo::{EntryPoint, DecodedEntryPoint, AlgoInput, AlgoOutput};
    pub use ::data::HasDataPath;
}

static DEFAULT_API_BASE_URL: &'static str = "https://api.algorithmia.com";

/// The top-level struct for instantiating Algorithmia client endpoints
pub struct Algorithmia {
    http_client: HttpClient,
}

impl<'a, 'c> Algorithmia {
    /// Instantiate a new client
    ///
    /// Client should be instatiated with your API key, except
    ///   when running within an algorithm on the Algorithmia platform.
    ///
    /// # Examples
    /// ```
    /// use algorithmia::*;
    /// // Initialize a client
    /// let client = Algorithmia::client("simUseYourApiKey");
    ///
    /// // Initialize a client (for algorithms running on the Algorithmia platform)
    /// let client = Algorithmia::client(NoAuth);
    /// ```
    pub fn client<A: Into<ApiAuth>>(api_key: A) -> Algorithmia {
        let api_address = std::env::var("ALGORITHMIA_API").unwrap_or(DEFAULT_API_BASE_URL.into());
        Algorithmia { http_client: HttpClient::new(api_key.into(), api_address) }
    }

    /// Instantiate a new client against alternate API servers
    pub fn alt_client<A: Into<ApiAuth>>(base_url: Url, api_key: A) -> Algorithmia {
        Algorithmia { http_client: HttpClient::new(api_key.into(), base_url.into_string()) }
    }

    /// Instantiate an [`Algorithm`](algo/algorithm.struct.html) from this client
    ///
    /// By using In
    /// # Examples
    ///
    /// ```
    /// use algorithmia::Algorithmia;
    /// use algorithmia::algo::Version;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let factor = client.algo("anowell/Dijkstra/0.1");
    /// let factor = client.algo(("anowell/Dijkstra", Version::Latest));
    /// ```
    pub fn algo<A: Into<AlgoRef>>(&self, algorithm: A) -> Algorithm {
        Algorithm::new(self.http_client.clone(), algorithm.into())
    }

    /// Instantiate a `DataDirectory` from this client
    ///
    /// # Examples
    ///
    /// ```
    /// use algorithmia::Algorithmia;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let rustfoo = client.dir("data://.my/rustfoo");
    /// ```
    pub fn dir(&self, path: &'a str) -> DataDir {
        DataDir::new(self.http_client.clone(), path)
    }

    /// Instantiate a `DataDirectory` from this client
    ///
    /// # Examples
    ///
    /// ```
    /// use algorithmia::Algorithmia;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let rustfoo = client.file("data://.my/rustfoo");
    /// ```
    pub fn file(&self, path: &'a str) -> DataFile {
        DataFile::new(self.http_client.clone(), path)
    }

    /// Instantiate a `DataPath` from this client
    ///
    /// Use this if you don't explicitly know if a Data URI is to a directory or file
    ///
    /// # Examples
    ///
    /// ```
    /// use algorithmia::Algorithmia;
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let rustfoo = client.data("data://.my/rustfoo/what_am_i");
    /// ```
    pub fn data(&self, path: &'a str) -> DataObject {
        DataObject::new(self.http_client.clone(), path)
    }
}

/// Allow cloning in order to reuse http client (and API key) for multiple connections
impl clone::Clone for Algorithmia {
    fn clone(&self) -> Algorithmia {
        Algorithmia { http_client: self.http_client.clone() }
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2019 Alibaba Cloud. All rights reserved.
// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause

//! Virtio Vhost Backend Drivers
//!
//! Virtio devices use virtqueues to transport data efficiently. The first generation of virtqueue
//! is a set of three different single-producer, single-consumer ring structures designed to store
//! generic scatter-gather I/O. The virtio specification 1.1 introduces an alternative compact
//! virtqueue layout named "Packed Virtqueue", which is more friendly to memory cache system and
//! hardware implemented virtio devices. The packed virtqueue uses read-write memory, that means
//! the memory will be both read and written by both host and guest. The new Packed Virtqueue is
//! preferred for performance.
//!
//! Vhost is a mechanism to improve performance of Virtio devices by delegate data plane operations
//! to dedicated IO service processes. Only the configuration, I/O submission notification, and I/O
//! completion interruption are piped through the hypervisor.
//! It uses the same virtqueue layout as Virtio to allow Vhost devices to be mapped directly to
//! Virtio devices. This allows a Vhost device to be accessed directly by a guest OS inside a
//! hypervisor process with an existing Virtio (PCI) driver.
//!
//! The initial vhost implementation is a part of the Linux kernel and uses ioctl interface to
//! communicate with userspace applications. Dedicated kernel worker threads are created to handle
//! IO requests from the guest.
//!
//! Later Vhost-user protocol is introduced to complement the ioctl interface used to control the
//! vhost implementation in the Linux kernel. It implements the control plane needed to establish
//! virtqueues sharing with a user space process on the same host. It uses communication over a
//! Unix domain socket to share file descriptors in the ancillary data of the message.
//! The protocol defines 2 sides of the communication, master and slave. Master is the application
//! that shares its virtqueues. Slave is the consumer of the virtqueues. Master and slave can be
//! either a client (i.e. connecting) or server (listening) in the socket communication.

#![deny(missing_docs)]

#[cfg_attr(feature = "vhost-user", macro_use)]
extern crate bitflags;
#[cfg_attr(feature = "vhost-kern", macro_use)]
extern crate vmm_sys_util;

mod backend;
pub use backend::*;

#[cfg(feature = "vhost-kern")]
pub mod vhost_kern;
#[cfg(feature = "vhost-user")]
pub mod vhost_user;
#[cfg(feature = "vhost-vsock")]
pub mod vsock;

/// Error codes for vhost operations
#[derive(Debug)]
pub enum Error {
    /// Invalid operations.
    InvalidOperation,
    /// Invalid guest memory.
    InvalidGuestMemory,
    /// Invalid guest memory region.
    InvalidGuestMemoryRegion,
    /// Invalid queue.
    InvalidQueue,
    /// Invalid descriptor table address.
    DescriptorTableAddress,
    /// Invalid used address.
    UsedAddress,
    /// Invalid available address.
    AvailAddress,
    /// Invalid log address.
    LogAddress,
    #[cfg(feature = "vhost-kern")]
    /// Error opening the vhost backend driver.
    VhostOpen(std::io::Error),
    #[cfg(feature = "vhost-kern")]
    /// Error while running ioctl.
    IoctlError(std::io::Error),
    /// Error from IO subsystem.
    IOError(std::io::Error),
    #[cfg(feature = "vhost-user")]
    /// Error from the vhost-user subsystem.
    VhostUserProtocol(vhost_user::Error),
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            Error::InvalidOperation => write!(f, "invalid vhost operations"),
            Error::InvalidGuestMemory => write!(f, "invalid guest memory object"),
            Error::InvalidGuestMemoryRegion => write!(f, "invalid guest memory region"),
            Error::InvalidQueue => write!(f, "invalid virtque"),
            Error::DescriptorTableAddress => write!(f, "invalid virtque descriptor talbe address"),
            Error::UsedAddress => write!(f, "invalid virtque used talbe address"),
            Error::AvailAddress => write!(f, "invalid virtque available table address"),
            Error::LogAddress => write!(f, "invalid virtque log address"),
            Error::IOError(e) => write!(f, "IO error: {}", e),
            #[cfg(feature = "vhost-kern")]
            Error::VhostOpen(e) => write!(f, "failure in opening vhost file: {}", e),
            #[cfg(feature = "vhost-kern")]
            Error::IoctlError(e) => write!(f, "failure in vhost ioctl: {}", e),
            #[cfg(feature = "vhost-user")]
            Error::VhostUserProtocol(e) => write!(f, "vhost-user: {}", e),
        }
    }
}

impl std::error::Error for Error {}

#[cfg(feature = "vhost-user")]
impl std::convert::From<vhost_user::Error> for Error {
    fn from(err: vhost_user::Error) -> Self {
        Error::VhostUserProtocol(err)
    }
}

/// Result of vhost operations
pub type Result<T> = std::result::Result<T, Error>;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_error() {
        assert_eq!(
            format!("{}", Error::AvailAddress),
            "invalid virtque available table address"
        );
        assert_eq!(
            format!("{}", Error::InvalidOperation),
            "invalid vhost operations"
        );
        assert_eq!(
            format!("{}", Error::InvalidGuestMemory),
            "invalid guest memory object"
        );
        assert_eq!(
            format!("{}", Error::InvalidGuestMemoryRegion),
            "invalid guest memory region"
        );
        assert_eq!(format!("{}", Error::InvalidQueue), "invalid virtque");
        assert_eq!(
            format!("{}", Error::DescriptorTableAddress),
            "invalid virtque descriptor talbe address"
        );
        assert_eq!(
            format!("{}", Error::UsedAddress),
            "invalid virtque used talbe address"
        );
        assert_eq!(
            format!("{}", Error::LogAddress),
            "invalid virtque log address"
        );

        assert_eq!(format!("{:?}", Error::AvailAddress), "AvailAddress");
    }

    #[cfg(feature = "vhost-user")]
    #[test]
    fn test_convert_from_vhost_user_error() {
        let e: Error = vhost_user::Error::OversizedMsg.into();

        assert_eq!(format!("{}", e), "vhost-user: oversized message");
    }
}
<commit_msg>Fix typos in the error messages<commit_after>// Copyright (C) 2019 Alibaba Cloud. All rights reserved.
// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause

//! Virtio Vhost Backend Drivers
//!
//! Virtio devices use virtqueues to transport data efficiently. The first generation of virtqueue
//! is a set of three different single-producer, single-consumer ring structures designed to store
//! generic scatter-gather I/O. The virtio specification 1.1 introduces an alternative compact
//! virtqueue layout named "Packed Virtqueue", which is more friendly to memory cache system and
//! hardware implemented virtio devices. The packed virtqueue uses read-write memory, that means
//! the memory will be both read and written by both host and guest. The new Packed Virtqueue is
//! preferred for performance.
//!
//! Vhost is a mechanism to improve performance of Virtio devices by delegate data plane operations
//! to dedicated IO service processes. Only the configuration, I/O submission notification, and I/O
//! completion interruption are piped through the hypervisor.
//! It uses the same virtqueue layout as Virtio to allow Vhost devices to be mapped directly to
//! Virtio devices. This allows a Vhost device to be accessed directly by a guest OS inside a
//! hypervisor process with an existing Virtio (PCI) driver.
//!
//! The initial vhost implementation is a part of the Linux kernel and uses ioctl interface to
//! communicate with userspace applications. Dedicated kernel worker threads are created to handle
//! IO requests from the guest.
//!
//! Later Vhost-user protocol is introduced to complement the ioctl interface used to control the
//! vhost implementation in the Linux kernel. It implements the control plane needed to establish
//! virtqueues sharing with a user space process on the same host. It uses communication over a
//! Unix domain socket to share file descriptors in the ancillary data of the message.
//! The protocol defines 2 sides of the communication, master and slave. Master is the application
//! that shares its virtqueues. Slave is the consumer of the virtqueues. Master and slave can be
//! either a client (i.e. connecting) or server (listening) in the socket communication.

#![deny(missing_docs)]

#[cfg_attr(feature = "vhost-user", macro_use)]
extern crate bitflags;
#[cfg_attr(feature = "vhost-kern", macro_use)]
extern crate vmm_sys_util;

mod backend;
pub use backend::*;

#[cfg(feature = "vhost-kern")]
pub mod vhost_kern;
#[cfg(feature = "vhost-user")]
pub mod vhost_user;
#[cfg(feature = "vhost-vsock")]
pub mod vsock;

/// Error codes for vhost operations
#[derive(Debug)]
pub enum Error {
    /// Invalid operations.
    InvalidOperation,
    /// Invalid guest memory.
    InvalidGuestMemory,
    /// Invalid guest memory region.
    InvalidGuestMemoryRegion,
    /// Invalid queue.
    InvalidQueue,
    /// Invalid descriptor table address.
    DescriptorTableAddress,
    /// Invalid used address.
    UsedAddress,
    /// Invalid available address.
    AvailAddress,
    /// Invalid log address.
    LogAddress,
    #[cfg(feature = "vhost-kern")]
    /// Error opening the vhost backend driver.
    VhostOpen(std::io::Error),
    #[cfg(feature = "vhost-kern")]
    /// Error while running ioctl.
    IoctlError(std::io::Error),
    /// Error from IO subsystem.
    IOError(std::io::Error),
    #[cfg(feature = "vhost-user")]
    /// Error from the vhost-user subsystem.
    VhostUserProtocol(vhost_user::Error),
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            Error::InvalidOperation => write!(f, "invalid vhost operations"),
            Error::InvalidGuestMemory => write!(f, "invalid guest memory object"),
            Error::InvalidGuestMemoryRegion => write!(f, "invalid guest memory region"),
            Error::InvalidQueue => write!(f, "invalid virtqueue"),
            Error::DescriptorTableAddress => {
                write!(f, "invalid virtqueue descriptor table address")
            }
            Error::UsedAddress => write!(f, "invalid virtqueue used table address"),
            Error::AvailAddress => write!(f, "invalid virtqueue available table address"),
            Error::LogAddress => write!(f, "invalid virtqueue log address"),
            Error::IOError(e) => write!(f, "IO error: {}", e),
            #[cfg(feature = "vhost-kern")]
            Error::VhostOpen(e) => write!(f, "failure in opening vhost file: {}", e),
            #[cfg(feature = "vhost-kern")]
            Error::IoctlError(e) => write!(f, "failure in vhost ioctl: {}", e),
            #[cfg(feature = "vhost-user")]
            Error::VhostUserProtocol(e) => write!(f, "vhost-user: {}", e),
        }
    }
}

impl std::error::Error for Error {}

#[cfg(feature = "vhost-user")]
impl std::convert::From<vhost_user::Error> for Error {
    fn from(err: vhost_user::Error) -> Self {
        Error::VhostUserProtocol(err)
    }
}

/// Result of vhost operations
pub type Result<T> = std::result::Result<T, Error>;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_error() {
        assert_eq!(
            format!("{}", Error::AvailAddress),
            "invalid virtqueue available table address"
        );
        assert_eq!(
            format!("{}", Error::InvalidOperation),
            "invalid vhost operations"
        );
        assert_eq!(
            format!("{}", Error::InvalidGuestMemory),
            "invalid guest memory object"
        );
        assert_eq!(
            format!("{}", Error::InvalidGuestMemoryRegion),
            "invalid guest memory region"
        );
        assert_eq!(format!("{}", Error::InvalidQueue), "invalid virtqueue");
        assert_eq!(
            format!("{}", Error::DescriptorTableAddress),
            "invalid virtqueue descriptor table address"
        );
        assert_eq!(
            format!("{}", Error::UsedAddress),
            "invalid virtqueue used table address"
        );
        assert_eq!(
            format!("{}", Error::LogAddress),
            "invalid virtqueue log address"
        );

        assert_eq!(format!("{:?}", Error::AvailAddress), "AvailAddress");
    }

    #[cfg(feature = "vhost-user")]
    #[test]
    fn test_convert_from_vhost_user_error() {
        let e: Error = vhost_user::Error::OversizedMsg.into();

        assert_eq!(format!("{}", e), "vhost-user: oversized message");
    }
}
<|endoftext|>


<commit_before>//! Custom memory allocators and utilities for using them.
//!
//! # Examples
//! ```rust
//! #![feature(placement_in_syntax)]
//!
//! use std::io;
//! use allocators::{Allocator, Scoped, BlockOwner, Proxy};
//!
//! #[derive(Debug)]
//! struct Bomb(u8);
//!
//! impl Drop for Bomb {
//!     fn drop(&mut self) {
//!         println!("Boom! {}", self.0);
//!     }
//! }
//! // new scoped allocator with 4 kilobytes of memory.
//! let alloc = Scoped::new(4 * 1024).unwrap();
//!
//! alloc.scope(|inner| {
//!     let mut bombs = Vec::new();
//!     // allocate makes the value on the stack first.
//!     for i in 0..100 { bombs.push(inner.allocate(Bomb(i)).unwrap())}
//!     // there's also in-place allocation!
//!     let bomb_101 = in inner.make_place().unwrap() { Bomb(101) };
//!     // watch the bombs go off!
//! });
//!
//!
//! // You can make allocators backed by other allocators.
//! {
//!     let secondary_alloc = Scoped::new_from(&alloc, 1024).unwrap();
//!     let mut val = secondary_alloc.allocate(0i32).unwrap();
//!     *val = 1;
//! }
//!
//! // Let's wrap our allocator in a proxy to log what it's doing.
//! let proxied = Proxy::new(alloc, io::stdout());
//! let logged_allocation = proxied.allocate([0u8; 32]).unwrap();
//! ```

#![feature(
    alloc,
    coerce_unsized,
    core_intrinsics,
    heap_api,
    placement_new_protocol,
    placement_in_syntax,
    raw,
    unsize
)]

use std::any::Any;
use std::borrow::{Borrow, BorrowMut};
use std::error::Error;
use std::fmt;
use std::marker::Unsize;
use std::mem;
use std::ops::Place as StdPlace;
use std::ops::{CoerceUnsized, Deref, DerefMut, InPlace, Placer};

use alloc::heap;

extern crate alloc;

pub mod composable;
pub mod scoped;

pub use composable::*;
pub use scoped::Scoped;

/// A custom memory allocator.
pub unsafe trait Allocator {
    /// Attempts to allocate the value supplied to it.
    ///
    /// # Examples
    /// ```rust
    /// use allocators::{Allocator, Allocated};
    /// fn alloc_array<A: Allocator>(allocator: &A) -> Allocated<[u8; 1000], A> {
    ///     allocator.allocate([0; 1000]).ok().unwrap()
    /// }
    /// ```
    #[inline(always)]
    fn allocate<T>(&self, val: T) -> Result<Allocated<T, Self>, (AllocatorError, T)>
        where Self: Sized
    {
        match self.make_place() {
            Ok(place) => {
                Ok(in place { val })
            }
            Err(err) => {
                Err((err, val))
            }
        }
    }

    /// Attempts to create a place to allocate into.
    /// For the general purpose, calling `allocate` on the allocator is enough.
    /// However, when you know the value you are allocating is too large
    /// to be constructed on the stack, you should use in-place allocation.
    ///
    /// # Examples
    /// ```rust
    /// #![feature(placement_in_syntax)]
    /// use allocators::{Allocator, Allocated};
    /// fn alloc_array<A: Allocator>(allocator: &A) -> Allocated<[u8; 1000], A> {
    ///     // if 1000 bytes were enough to smash the stack, this would still work.
    ///     in allocator.make_place().unwrap() { [0; 1000] }
    /// }
    /// ```
    fn make_place<T>(&self) -> Result<Place<T, Self>, AllocatorError>
        where Self: Sized
    {
        let (size, align) = (mem::size_of::<T>(), mem::align_of::<T>());
        match unsafe { self.allocate_raw(size, align) } {
            Ok(blk) => {
                Ok(Place {
                    allocator: self,
                    ptr: blk.ptr() as *mut T,
                    size: blk.size(),
                    align: blk.align(),
                    finalized: false,
                })
            }
            Err(e) => Err(e),
        }
    }

    /// Attempt to allocate a block of memory.
    ///
    /// Returns either a pointer to the block of memory allocated
    /// or an Error. If `size` is equal to 0, the pointer returned must
    /// be equal to `heap::EMPTY`
    ///
    /// # Safety
    /// Never use the pointer outside of the lifetime of the allocator.
    /// It must be deallocated with the same allocator as it was allocated with.
    /// It is undefined behavior to provide a non power-of-two align.
    unsafe fn allocate_raw(&self, size: usize, align: usize) -> Result<Block, AllocatorError>;

    /// Deallocate the memory referred to by this pointer.
    ///
    /// # Safety
    /// This block must have been allocated by this allocator.
    unsafe fn deallocate_raw(&self, blk: Block);
}

/// An allocator that knows which blocks have been issued by it.
pub trait BlockOwner: Allocator {
    /// Whether this allocator owns this allocated value.
    fn owns<'a, T, A: Allocator>(&self, val: &Allocated<'a, T, A>) -> bool {
        let blk = Block {
            ptr: val.item as *mut u8,
            size: val.size,
            align: val.align,
        };

        self.owns_block(&blk)
    }

    /// Whether this allocator owns the block passed to it.
    fn owns_block(&self, blk: &Block) -> bool;

    /// Joins this allocator with a fallback allocator.
    // TODO: Maybe not the right place for this?
    // Right now I've been more focused on shaking out the
    // specifics of allocation than crafting a fluent API.
    fn with_fallback<O: BlockOwner>(self, other: O) -> Fallback<Self, O>
    where Self: Sized {
        Fallback::new(self, other)
    }
}

/// A block of memory created by an allocator.
pub struct Block {
    ptr: *mut u8,
    size: usize,
    align: usize,
}

impl Block {
    fn ptr(&self) -> *mut u8 { self.ptr }
    fn size(&self) -> usize { self.size }
    fn align(&self) -> usize { self.align }
}

/// Errors that can occur while creating an allocator
/// or allocating from it.
#[derive(Debug, Eq, PartialEq)]
pub enum AllocatorError {
    /// The allocator failed to allocate the amount of memory requested of it.
    OutOfMemory,
    /// An allocator-specific error message.
    AllocatorSpecific(String),
}

impl fmt::Display for AllocatorError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(self.description())
    }
}

impl Error for AllocatorError {
    fn description(&self) -> &str {
        use AllocatorError::*;

        match *self {
            OutOfMemory => {
                "Allocator out of memory."
            }
            AllocatorSpecific(ref reason) => {
                reason
            }
        }
    }
}

/// Allocator stub that just forwards to heap allocation.
/// It is recommended to use the `HEAP` constant instead
/// of creating a new instance of this, to benefit from
/// the static lifetime that it provides.
#[derive(Debug)]
pub struct HeapAllocator;

// A constant for allocators to use the heap as a root.
// Values allocated with this are effectively `Box`es.
pub const HEAP: &'static HeapAllocator = &HeapAllocator;

unsafe impl Allocator for HeapAllocator {
    unsafe fn allocate_raw(&self, size: usize, align: usize) -> Result<Block, AllocatorError> {
        let ptr = if size != 0 {
            heap::allocate(size, align)
        } else {
            heap::EMPTY as *mut u8
        };

        if ptr.is_null() {
            Err(AllocatorError::OutOfMemory)
        } else {
            Ok(Block {
                ptr: ptr,
                size: size,
                align: align,
            })
        }
    }

    unsafe fn deallocate_raw(&self, blk: Block) {
        heap::deallocate(blk.ptr(), blk.size(), blk.align())
    }
}

/// An item allocated by a custom allocator.
pub struct Allocated<'a, T: 'a + ?Sized, A: 'a + Allocator> {
    item: *mut T,
    allocator: &'a A,
    size: usize,
    align: usize,
}

impl<'a, T: ?Sized, A: Allocator> Deref for Allocated<'a, T, A> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { mem::transmute(self.item) }
    }
}

impl<'a, T: ?Sized, A: Allocator> DerefMut for Allocated<'a, T, A> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { mem::transmute(self.item) }
    }
}

// Allocated can store trait objects!
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Allocated<'a, U, A>> for Allocated<'a, T, A> {}

impl<'a, A: Allocator> Allocated<'a, Any, A> {
    /// Attempts to downcast this `Allocated` to a concrete type.
    pub fn downcast<T: Any>(self) -> Result<Allocated<'a, T, A>, Allocated<'a, Any, A>> {
        use std::raw::TraitObject;
        if self.is::<T>() {
            let obj: TraitObject = unsafe { mem::transmute(self.item as *mut Any) };
            let new_allocated = Allocated {
                item: unsafe { mem::transmute(obj.data) },
                allocator: self.allocator,
                size: self.size,
                align: self.align,
            };
            mem::forget(self);
            Ok(new_allocated)
        } else {
            Err(self)
        }
    }
}

impl<'a, T: ?Sized, A: Allocator> Borrow<T> for Allocated<'a, T, A> {
    fn borrow(&self) -> &T {
        &**self
    }
}

impl<'a, T: ?Sized, A: Allocator> BorrowMut<T> for Allocated<'a, T, A> {
    fn borrow_mut(&mut self) -> &mut T {
        &mut **self
    }
}

impl<'a, T: ?Sized, A: Allocator> Drop for Allocated<'a, T, A> {
    #[inline]
    fn drop(&mut self) {
        use std::intrinsics::drop_in_place;
        unsafe {
            drop_in_place(self.item);

            self.allocator.deallocate_raw(Block {
                ptr: self.item as *mut u8,
                size: self.size,
                align: self.align
            });
        }

    }
}

/// A place for allocating into.
/// This is only used for in-place allocation,
/// e.g. `let val = in (alloc.make_place().unwrap())`
pub struct Place<'a, T: 'a, A: 'a + Allocator> {
    allocator: &'a A,
    ptr: *mut T,
    size: usize,
    align: usize,
    finalized: bool
}

impl<'a, T: 'a, A: 'a + Allocator> Placer<T> for Place<'a, T, A> {
    type Place = Self;
    fn make_place(self) -> Self { self }
}

impl<'a, T: 'a, A: 'a + Allocator> InPlace<T> for Place<'a, T, A> {
    type Owner = Allocated<'a, T, A>;
    unsafe fn finalize(mut self) -> Self::Owner {
        self.finalized = true;
        Allocated {
            item: self.ptr,
            allocator: self.allocator,
            size: self.size,
            align: self.size,
        }
    }
}

impl<'a, T: 'a, A: 'a + Allocator> StdPlace<T> for Place<'a, T, A> {
    fn pointer(&mut self) -> *mut T {
        self.ptr
    }
}

impl<'a, T: 'a, A: 'a + Allocator> Drop for Place<'a, T, A> {
    #[inline]
    fn drop(&mut self) {
        // almost identical to Allocated::Drop, but we only drop if this
        // was never finalized. If it was finalized, an Allocated manages this memory.
        use std::intrinsics::drop_in_place;
        if !self.finalized { unsafe {
            drop_in_place(self.ptr);

            self.allocator.deallocate_raw(Block {
                ptr: self.ptr as *mut u8,
                size: self.size,
                align: self.align,
            });
        } }

    }
}

// aligns a pointer forward to the next value aligned with `align`.
#[inline(always)]
fn align_forward(ptr: *mut u8, align: usize) -> *mut u8 {
    ((ptr as usize + align - 1) & !(align - 1)) as *mut u8
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn heap_lifetime() {
        let my_int;
        {
            my_int = HEAP.allocate(0i32).unwrap();
        }

        assert_eq!(*my_int, 0);
    }
    #[test]
    fn heap_in_place() {
        let big = in HEAP.make_place().unwrap() { [0u8; 8_000_000] };
        assert_eq!(big.len(), 8_000_000);
    }
}<commit_msg>Refactored Allocated and Place to be backed by Block.<commit_after>//! Custom memory allocators and utilities for using them.
//!
//! # Examples
//! ```rust
//! #![feature(placement_in_syntax)]
//!
//! use std::io;
//! use allocators::{Allocator, Scoped, BlockOwner, Proxy};
//!
//! #[derive(Debug)]
//! struct Bomb(u8);
//!
//! impl Drop for Bomb {
//!     fn drop(&mut self) {
//!         println!("Boom! {}", self.0);
//!     }
//! }
//! // new scoped allocator with 4 kilobytes of memory.
//! let alloc = Scoped::new(4 * 1024).unwrap();
//!
//! alloc.scope(|inner| {
//!     let mut bombs = Vec::new();
//!     // allocate makes the value on the stack first.
//!     for i in 0..100 { bombs.push(inner.allocate(Bomb(i)).unwrap())}
//!     // there's also in-place allocation!
//!     let bomb_101 = in inner.make_place().unwrap() { Bomb(101) };
//!     // watch the bombs go off!
//! });
//!
//!
//! // You can make allocators backed by other allocators.
//! {
//!     let secondary_alloc = Scoped::new_from(&alloc, 1024).unwrap();
//!     let mut val = secondary_alloc.allocate(0i32).unwrap();
//!     *val = 1;
//! }
//!
//! // Let's wrap our allocator in a proxy to log what it's doing.
//! let proxied = Proxy::new(alloc, io::stdout());
//! let logged_allocation = proxied.allocate([0u8; 32]).unwrap();
//! ```

#![feature(
    alloc,
    coerce_unsized,
    core_intrinsics,
    heap_api,
    placement_new_protocol,
    placement_in_syntax,
    raw,
    unsize,
)]

use std::any::Any;
use std::borrow::{Borrow, BorrowMut};
use std::error::Error;
use std::fmt;
use std::marker::{PhantomData, Unsize};
use std::mem;
use std::ops::Place as StdPlace;
use std::ops::{CoerceUnsized, Deref, DerefMut, InPlace, Placer};

use alloc::heap;

extern crate alloc;

pub mod composable;
pub mod scoped;

pub use composable::*;
pub use scoped::Scoped;

/// A custom memory allocator.
pub unsafe trait Allocator {
    /// Attempts to allocate the value supplied to it.
    ///
    /// # Examples
    /// ```rust
    /// use allocators::{Allocator, Allocated};
    /// fn alloc_array<A: Allocator>(allocator: &A) -> Allocated<[u8; 1000], A> {
    ///     allocator.allocate([0; 1000]).ok().unwrap()
    /// }
    /// ```
    #[inline(always)]
    fn allocate<T>(&self, val: T) -> Result<Allocated<T, Self>, (AllocatorError, T)>
        where Self: Sized
    {
        match self.make_place() {
            Ok(place) => {
                Ok(in place { val })
            }
            Err(err) => {
                Err((err, val))
            }
        }
    }

    /// Attempts to create a place to allocate into.
    /// For the general purpose, calling `allocate` on the allocator is enough.
    /// However, when you know the value you are allocating is too large
    /// to be constructed on the stack, you should use in-place allocation.
    ///
    /// # Examples
    /// ```rust
    /// #![feature(placement_in_syntax)]
    /// use allocators::{Allocator, Allocated};
    /// fn alloc_array<A: Allocator>(allocator: &A) -> Allocated<[u8; 1000], A> {
    ///     // if 1000 bytes were enough to smash the stack, this would still work.
    ///     in allocator.make_place().unwrap() { [0; 1000] }
    /// }
    /// ```
    fn make_place<T>(&self) -> Result<Place<T, Self>, AllocatorError>
        where Self: Sized
    {
        let (size, align) = (mem::size_of::<T>(), mem::align_of::<T>());
        match unsafe { self.allocate_raw(size, align) } {
            Ok(blk) => {
                Ok(Place {
                    allocator: self,
                    block: blk,
                    _marker: PhantomData
                })
            }
            Err(e) => Err(e),
        }
    }

    /// Attempt to allocate a block of memory.
    ///
    /// Returns either a pointer to the block of memory allocated
    /// or an Error. If `size` is equal to 0, the pointer returned must
    /// be equal to `heap::EMPTY`
    ///
    /// # Safety
    /// Never use the pointer outside of the lifetime of the allocator.
    /// It must be deallocated with the same allocator as it was allocated with.
    /// It is undefined behavior to provide a non power-of-two align.
    unsafe fn allocate_raw(&self, size: usize, align: usize) -> Result<Block, AllocatorError>;

    /// Deallocate the memory referred to by this pointer.
    ///
    /// # Safety
    /// This block must have been allocated by this allocator.
    unsafe fn deallocate_raw(&self, blk: Block);
}

/// An allocator that knows which blocks have been issued by it.
pub trait BlockOwner: Allocator {
    /// Whether this allocator owns this allocated value.
    fn owns<'a, T, A: Allocator>(&self, val: &Allocated<'a, T, A>) -> bool {
        self.owns_block(&val.block)
    }

    /// Whether this allocator owns the block passed to it.
    fn owns_block(&self, blk: &Block) -> bool;

    /// Joins this allocator with a fallback allocator.
    // TODO: Maybe not the right place for this?
    // Right now I've been more focused on shaking out the
    // specifics of allocation than crafting a fluent API.
    fn with_fallback<O: BlockOwner>(self, other: O) -> Fallback<Self, O>
    where Self: Sized {
        Fallback::new(self, other)
    }
}

/// A block of memory created by an allocator.
// TODO: should blocks be tied to lifetimes? seems good for safety!
pub struct Block {
    ptr: *mut u8,
    size: usize,
    align: usize,
}

impl Block {
    pub fn ptr(&self) -> *mut u8 { self.ptr }
    pub fn size(&self) -> usize { self.size }
    pub fn align(&self) -> usize { self.align }

    // private clone implementation since
    // having a public one is a little scary for now.
    fn clone(&self) -> Block {
        Block {
            ptr: self.ptr(),
            size: self.size(),
            align: self.align(),
        }
    }
}

/// Errors that can occur while creating an allocator
/// or allocating from it.
#[derive(Debug, Eq, PartialEq)]
pub enum AllocatorError {
    /// The allocator failed to allocate the amount of memory requested of it.
    OutOfMemory,
    /// An allocator-specific error message.
    AllocatorSpecific(String),
}

impl fmt::Display for AllocatorError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str(self.description())
    }
}

impl Error for AllocatorError {
    fn description(&self) -> &str {
        use AllocatorError::*;

        match *self {
            OutOfMemory => {
                "Allocator out of memory."
            }
            AllocatorSpecific(ref reason) => {
                reason
            }
        }
    }
}

/// Allocator stub that just forwards to heap allocation.
/// It is recommended to use the `HEAP` constant instead
/// of creating a new instance of this, to benefit from
/// the static lifetime that it provides.
#[derive(Debug)]
pub struct HeapAllocator;

// A constant for allocators to use the heap as a root.
// Values allocated with this are effectively `Box`es.
pub const HEAP: &'static HeapAllocator = &HeapAllocator;

unsafe impl Allocator for HeapAllocator {
    unsafe fn allocate_raw(&self, size: usize, align: usize) -> Result<Block, AllocatorError> {
        let ptr = if size != 0 {
            heap::allocate(size, align)
        } else {
            heap::EMPTY as *mut u8
        };

        if ptr.is_null() {
            Err(AllocatorError::OutOfMemory)
        } else {
            Ok(Block { ptr: ptr, size: size, align: align} )
        }
    }

    unsafe fn deallocate_raw(&self, blk: Block) {
        heap::deallocate(blk.ptr(), blk.size(), blk.align())
    }
}

/// An item allocated by a custom allocator.
pub struct Allocated<'a, T: 'a + ?Sized, A: 'a + Allocator> {
    item: *mut T,
    allocator: &'a A,
    block: Block,
}

impl<'a, T: ?Sized, A: Allocator> Deref for Allocated<'a, T, A> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { mem::transmute(self.item) }
    }
}

impl<'a, T: ?Sized, A: Allocator> DerefMut for Allocated<'a, T, A> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { mem::transmute(self.item) }
    }
}

// Allocated can store trait objects!
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Allocated<'a, U, A>> for Allocated<'a, T, A> {}

impl<'a, A: Allocator> Allocated<'a, Any, A> {
    /// Attempts to downcast this `Allocated` to a concrete type.
    pub fn downcast<T: Any>(self) -> Result<Allocated<'a, T, A>, Allocated<'a, Any, A>> {
        use std::raw::TraitObject;
        if self.is::<T>() {
            let obj: TraitObject = unsafe { mem::transmute(self.item as *mut Any) };
            let new_allocated = Allocated {
                item: obj.data as *mut T,
                allocator: self.allocator,
                block: self.block.clone(),
            };
            mem::forget(self);
            Ok(new_allocated)
        } else {
            Err(self)
        }
    }
}

impl<'a, T: ?Sized, A: Allocator> Borrow<T> for Allocated<'a, T, A> {
    fn borrow(&self) -> &T {
        &**self
    }
}

impl<'a, T: ?Sized, A: Allocator> BorrowMut<T> for Allocated<'a, T, A> {
    fn borrow_mut(&mut self) -> &mut T {
        &mut **self
    }
}

impl<'a, T: ?Sized, A: Allocator> Drop for Allocated<'a, T, A> {
    #[inline]
    fn drop(&mut self) {
        use std::intrinsics::drop_in_place;
        unsafe {
            drop_in_place(self.item);
;
            self.allocator.deallocate_raw(self.block.clone());
        }

    }
}

/// A place for allocating into.
/// This is only used for in-place allocation,
/// e.g. `let val = in (alloc.make_place().unwrap())`
pub struct Place<'a, T: 'a, A: 'a + Allocator> {
    allocator: &'a A,
    block: Block,
    _marker: PhantomData<T>,
}

impl<'a, T: 'a, A: 'a + Allocator> Placer<T> for Place<'a, T, A> {
    type Place = Self;
    fn make_place(self) -> Self { self }
}

impl<'a, T: 'a, A: 'a + Allocator> InPlace<T> for Place<'a, T, A> {
    type Owner = Allocated<'a, T, A>;
    unsafe fn finalize(self) -> Self::Owner {
        let allocated = Allocated {
            item: self.block.ptr() as *mut T,
            allocator: self.allocator,
            block: self.block.clone()
        };

        mem::forget(self);
        allocated
    }
}

impl<'a, T: 'a, A: 'a + Allocator> StdPlace<T> for Place<'a, T, A> {
    fn pointer(&mut self) -> *mut T {
        self.block.ptr() as *mut T
    }
}

impl<'a, T: 'a, A: 'a + Allocator> Drop for Place<'a, T, A> {
    #[inline]
    fn drop(&mut self) {
        // almost identical to Allocated::Drop, but we don't drop
        // the value in place. This is because if the finalize
        // method was never called, that means the expression
        // to create the value failed, and the memory at the
        // pointer is still uninitialized.
        unsafe {
            self.allocator.deallocate_raw(self.block.clone());
        }

    }
}

// aligns a pointer forward to the next value aligned with `align`.
#[inline(always)]
fn align_forward(ptr: *mut u8, align: usize) -> *mut u8 {
    ((ptr as usize + align - 1) & !(align - 1)) as *mut u8
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn heap_lifetime() {
        let my_int;
        {
            my_int = HEAP.allocate(0i32).unwrap();
        }

        assert_eq!(*my_int, 0);
    }
    #[test]
    fn heap_in_place() {
        let big = in HEAP.make_place().unwrap() { [0u8; 8_000_000] };
        assert_eq!(big.len(), 8_000_000);
    }
}<|endoftext|>


<commit_before>/// Implementation of https://tools.ietf.org/html/rfc6762

use std::time::{Duration, Instant};

#[derive(Debug)]
pub struct Mdns {
    socket_timeout : Duration,
    cached_descriptors : Vec<Descriptor>,
    published_descriptors : Vec<Descriptor>,
}

#[derive(Debug, Clone)]
pub struct Descriptor {
    name : String,
    timeout : Instant,
}

impl Mdns {
    pub fn new() -> Mdns {
        Mdns {
            socket_timeout : Duration::from_secs(30), // 30 Sekunden
            cached_descriptors : vec![],
            published_descriptors : vec![],
        }
    }

    pub fn lookup_name(&mut self, name : &str) -> Vec<Descriptor> {
        self.filter_timedout();

        self.cached_descriptors.iter().filter(|&e| {
            e.name == name
        }).cloned().into_iter().collect()
    }

    pub fn publish(&mut self, descriptor : Descriptor) {
        self.published_descriptors.push( descriptor );
    }

    pub fn publish_unique(&mut self, descriptor : Descriptor) {
        // TODO probe first
        self.publish(descriptor);
    }

    fn filter_timedout(&mut self) {
        let now = Instant::now();
        self.cached_descriptors.retain(|&e| e.timeout < now);
    }
}

impl Drop for Descriptor {
    fn drop(&mut self) {
        // TODO send 10.1. Goodbye Packets
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::time::Duration;
    use std::thread;

    #[test]
    fn drop_out_cache() {
        let mut md = Mdns {
            socket_timeout : Duration::from_millis(0),
            cached_descriptors : vec![ Descriptor{ name: "bye-bye.local".into() } ],
            published_descriptors : vec![],
        };

        let r1 = md.lookup_name("bye-bye.local");
        assert_eq!( 1, r1.len() );

        thread::sleep(Duration::from_millis(23));

        let r0 = md.lookup_name("bye-bye.local");
        assert!( r0.is_empty() );
    }

    #[test]
    fn listen_to_published() {

    }
}
<commit_msg>adapt test<commit_after>/// Implementation of https://tools.ietf.org/html/rfc6762

use std::time::{Duration, Instant};

#[derive(Debug)]
pub struct Mdns {
    socket_timeout : Duration,
    cached_descriptors : Vec<Descriptor>,
    published_descriptors : Vec<Descriptor>,
}

#[derive(Debug, Clone)]
pub struct Descriptor {
    name : String,
    timeout : Instant,
}

impl Mdns {
    pub fn new() -> Mdns {
        Mdns {
            socket_timeout : Duration::from_secs(30), // 30 Sekunden
            cached_descriptors : vec![],
            published_descriptors : vec![],
        }
    }

    pub fn lookup_name(&mut self, name : &str) -> Vec<Descriptor> {
        self.filter_timedout();

        self.cached_descriptors.iter().filter(|&e| {
            e.name == name
        }).cloned().into_iter().collect()
    }

    pub fn publish(&mut self, descriptor : Descriptor) {
        self.published_descriptors.push( descriptor );
    }

    pub fn publish_unique(&mut self, descriptor : Descriptor) {
        // TODO probe first
        self.publish(descriptor);
    }

    fn filter_timedout(&mut self) {
        let now = Instant::now();
        self.cached_descriptors.retain(|&e| e.timeout < now);
    }
}

impl Drop for Descriptor {
    fn drop(&mut self) {
        // TODO send 10.1. Goodbye Packets
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::time::{Duration, Instant};
    use std::thread;

    #[test]
    fn drop_out_cache() {
        let mut md = Mdns {
            socket_timeout : Duration::from_millis(0),
            cached_descriptors : vec![
                Descriptor{
                    name: "bye-bye.local".into(),
                    timeout : Instant::now(),
                }
            ],
            published_descriptors : vec![],
        };

        let r1 = md.lookup_name("bye-bye.local");
        assert_eq!( 1, r1.len() );

        thread::sleep(Duration::from_millis(23));

        let r0 = md.lookup_name("bye-bye.local");
        assert!( r0.is_empty() );
    }

    #[test]
    fn listen_to_published() {

    }
}
<|endoftext|>


<commit_before>#![deny(missing_doc)]

//! The XPath module from libxml2

extern crate libc;
pub use document::Document;
pub use context::Context;
pub use xpath_object::XPathObject;
pub use xpath_object::NodeSet;
pub use xpath_object::Node;

mod ffi;
mod document;
mod context;
mod xpath_object;

#[cfg(test)]
mod test;
<commit_msg>missing_doc -> missing_docs<commit_after>#![deny(missing_docs)]

//! The XPath module from libxml2

extern crate libc;
pub use document::Document;
pub use context::Context;
pub use xpath_object::XPathObject;
pub use xpath_object::NodeSet;
pub use xpath_object::Node;

mod ffi;
mod document;
mod context;
mod xpath_object;

#[cfg(test)]
mod test;
<|endoftext|>


<commit_before>#![feature(proc_macro, conservative_impl_trait, generators)]

extern crate bytes;
extern crate rustls;
extern crate futures_await as futures;
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_rustls;
extern crate http;
extern crate h2;
extern crate io_dump;

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

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

mod pool;
use pool::*;

macro_rules! poll {
    ($e:expr) => ({
        loop {
            match $e {
                ::futures::__rt::Ok(::futures::Async::Ready(e)) => {
                    break ::futures::__rt::Ok(e)
                }
                ::futures::__rt::Ok(::futures::Async::NotReady) => {}
                ::futures::__rt::Err(e) => {
                    break ::futures::__rt::Err(e)
                }
            }
            yield
        }
    })
}

fn client(listen_addr: SocketAddr, server_addr: SocketAddr) {
    let mut lp = Core::new().unwrap();

    let listener = TcpListener::bind(&listen_addr, &lp.handle()).unwrap();
    println!("Listening on: {}", listen_addr);
    println!("Proxying to: {}", server_addr);

    let pool = pool::H2ClientPool::new(lp.handle(), server_addr);
    let pool_handle = pool.handle();
    let done = listener.incoming().for_each(move |(client, client_addr)| {
        client_handle(client, pool_handle.clone())
            .map(move |(client_to_server, server_to_client)| {
                println!(
                    "{:?}: {}, {}",
                    client_addr,
                    client_to_server,
                    server_to_client
                );
            })
            .or_else(|e| {
                println!("{:?}", e);
                Ok(())
            })
    });
    lp.handle().spawn(pool);
    lp.run(done).unwrap();
}

#[async]
fn client_handle(client: TcpStream, pool_handle: PoolHandle) -> Result<(usize, usize), h2::Error> {
    let req = http::Request::builder()
        .method(http::Method::CONNECT)
        .uri("https://iovxw.net")
        .body(())
        .unwrap();
    let (client_reader, client_writer) = client.split();
    println!("C: request");
    let mut stream = await!(pool_handle.request(req, false))?;
    println!("C: request done");
    let (parts, body) = poll!(stream.poll_response())?.into_parts();
    println!("CCCCC");
    if parts.status != http::StatusCode::OK {
        unimplemented!();
    }
    let server_to_client = copy_from_h2(body, client_writer);
    let client_to_server = copy_to_h2(client_reader, stream);
    await!(client_to_server.join(server_to_client))
}

#[async]
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;
    }
    shutdown(dst);
    Ok(counter)
}

trait SendData<B: IntoBuf> {
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error>;
}

impl<B: IntoBuf> SendData<B> for h2c::Stream<B> {
    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> SendData<B> for h2s::Stream<B> {
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error> {
        h2s::Stream::send_data(self, data, end_of_stream)
    }
}

#[async]
fn copy_to_h2<R: AsyncRead + 'static, H: SendData<Bytes> + 'static>(
    mut src: R,
    mut dst: H,
) -> Result<usize, h2::Error> {
    let mut counter = 0;
    let mut buf = BytesMut::with_capacity(1024);
    loop {
        let n = poll!(src.read_buf(&mut buf))?;
        if n == 0 {
            dst.send_data(buf.take().freeze(), true)?;
            break;
        } else {
            dst.send_data(buf.take().freeze(), false)?;
        }
        counter += n;
    }
    Ok(counter)
}

fn server(listen_addr: SocketAddr, server_addr: SocketAddr) {
    let mut lp = Core::new().unwrap();
    let handle = lp.handle();

    let listener = TcpListener::bind(&listen_addr, &lp.handle()).unwrap();
    println!("Listening on: {}", listen_addr);
    println!("Proxying to: {}", server_addr);

    let done = listener.incoming().for_each(move |(client, client_addr)| {
        let handle2 = handle.clone();
        let client = io_dump::Dump::to_stdout(client);
        let connection = h2s::Server::handshake(client)
            .and_then(move |conn| {
                let handle = handle2.clone();
                println!("S: handshake done");
                conn.for_each(move |(request, stream)| {
                    println!("SSSS");
                    server_handle(handle.clone(), request, stream)
                        .map(move |(client_to_server, server_to_client)| {
                            println!(
                                "{:?}: {}, {}",
                                client_addr,
                                client_to_server,
                                server_to_client
                            );
                        })
                        .or_else(|e: h2::Error| {
                            println!("{:?}", e);
                            Ok(())
                        })
                })
            })
            .map_err(|e| println!("{:?}", e));

        handle.spawn(connection);
        Ok(())
    });
    lp.run(done).unwrap();
}

#[async]
fn server_handle(
    handle: Handle,
    request: http::Request<h2s::Body<Bytes>>,
    stream: h2s::Stream<Bytes>,
) -> Result<(usize, usize), h2::Error> {
    let (parts, body) = request.into_parts();
    if parts.method != http::Method::CONNECT {
        unimplemented!();
    }
    let addr = "127.0.0.1:8080".parse().unwrap();
    let server = await!(TcpStream::connect(&addr, &handle))?;
    let (server_reader, server_writer) = server.split();
    let server_to_client = copy_to_h2(server_reader, stream);
    let client_to_server = copy_from_h2(body, server_writer);
    await!(client_to_server.join(server_to_client))
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn it_works() {
        let client_addr = "127.0.0.1:3345".parse().unwrap();
        let server_addr = "127.0.0.1:3346".parse().unwrap();
        let s = ::std::thread::spawn(move || server(server_addr, server_addr));
        let c = ::std::thread::spawn(move || client(client_addr, server_addr));
        s.join().unwrap();
        c.join().unwrap();
    }
}
<commit_msg>Fix `ProtocolError`<commit_after>#![feature(proc_macro, conservative_impl_trait, generators)]

extern crate bytes;
extern crate rustls;
extern crate futures_await as futures;
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_rustls;
extern crate http;
extern crate h2;
extern crate io_dump;

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

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

mod pool;
use pool::*;

macro_rules! poll {
    ($e:expr) => ({
        loop {
            match $e {
                ::futures::__rt::Ok(::futures::Async::Ready(e)) => {
                    break ::futures::__rt::Ok(e)
                }
                ::futures::__rt::Ok(::futures::Async::NotReady) => {}
                ::futures::__rt::Err(e) => {
                    break ::futures::__rt::Err(e)
                }
            }
            yield
        }
    })
}

fn client(listen_addr: SocketAddr, server_addr: SocketAddr) {
    let mut lp = Core::new().unwrap();

    let listener = TcpListener::bind(&listen_addr, &lp.handle()).unwrap();
    println!("Listening on: {}", listen_addr);
    println!("Proxying to: {}", server_addr);

    let pool = pool::H2ClientPool::new(lp.handle(), server_addr);
    let pool_handle = pool.handle();
    let done = listener.incoming().for_each(move |(client, client_addr)| {
        client_handle(client, pool_handle.clone())
            .map(move |(client_to_server, server_to_client)| {
                println!(
                    "{:?}: {}, {}",
                    client_addr,
                    client_to_server,
                    server_to_client
                );
            })
            .or_else(|e| {
                println!("{:?}", e);
                Ok(())
            })
    });
    lp.handle().spawn(pool);
    lp.run(done).unwrap();
}

#[async]
fn client_handle(client: TcpStream, pool_handle: PoolHandle) -> Result<(usize, usize), h2::Error> {
    let req = http::Request::builder()
        .method(http::Method::CONNECT)
        .uri("https://iovxw.net/")
        .body(())
        .unwrap();
    let (client_reader, client_writer) = client.split();
    println!("C: request");
    let mut stream = await!(pool_handle.request(req, false))?;
    println!("C: request done");
    let (parts, body) = poll!(stream.poll_response())?.into_parts();
    println!("CCCCC");
    if parts.status != http::StatusCode::OK {
        unimplemented!();
    }
    let server_to_client = copy_from_h2(body, client_writer);
    let client_to_server = copy_to_h2(client_reader, stream);
    await!(client_to_server.join(server_to_client))
}

#[async]
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;
    }
    shutdown(dst);
    Ok(counter)
}

trait SendData<B: IntoBuf> {
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error>;
}

impl<B: IntoBuf> SendData<B> for h2c::Stream<B> {
    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> SendData<B> for h2s::Stream<B> {
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error> {
        h2s::Stream::send_data(self, data, end_of_stream)
    }
}

#[async]
fn copy_to_h2<R: AsyncRead + 'static, H: SendData<Bytes> + 'static>(
    mut src: R,
    mut dst: H,
) -> Result<usize, h2::Error> {
    let mut counter = 0;
    let mut buf = BytesMut::with_capacity(1024);
    loop {
        let n = poll!(src.read_buf(&mut buf))?;
        if n == 0 {
            dst.send_data(buf.take().freeze(), true)?;
            break;
        } else {
            dst.send_data(buf.take().freeze(), false)?;
        }
        counter += n;
    }
    Ok(counter)
}

fn server(listen_addr: SocketAddr, server_addr: SocketAddr) {
    let mut lp = Core::new().unwrap();
    let handle = lp.handle();

    let listener = TcpListener::bind(&listen_addr, &lp.handle()).unwrap();
    println!("Listening on: {}", listen_addr);
    println!("Proxying to: {}", server_addr);

    let done = listener.incoming().for_each(move |(client, client_addr)| {
        let handle2 = handle.clone();
        let client = io_dump::Dump::to_stdout(client);
        let connection = h2s::Server::handshake(client)
            .and_then(move |conn| {
                let handle = handle2.clone();
                println!("S: handshake done");
                conn.for_each(move |(request, stream)| {
                    println!("SSSS");
                    server_handle(handle.clone(), request, stream)
                        .map(move |(client_to_server, server_to_client)| {
                            println!(
                                "{:?}: {}, {}",
                                client_addr,
                                client_to_server,
                                server_to_client
                            );
                        })
                        .or_else(|e: h2::Error| {
                            println!("{:?}", e);
                            Ok(())
                        })
                })
            })
            .map_err(|e| println!("{:?}", e));

        handle.spawn(connection);
        Ok(())
    });
    lp.run(done).unwrap();
}

#[async]
fn server_handle(
    handle: Handle,
    request: http::Request<h2s::Body<Bytes>>,
    stream: h2s::Stream<Bytes>,
) -> Result<(usize, usize), h2::Error> {
    let (parts, body) = request.into_parts();
    if parts.method != http::Method::CONNECT {
        unimplemented!();
    }
    let addr = "127.0.0.1:8080".parse().unwrap();
    let server = await!(TcpStream::connect(&addr, &handle))?;
    let (server_reader, server_writer) = server.split();
    let server_to_client = copy_to_h2(server_reader, stream);
    let client_to_server = copy_from_h2(body, server_writer);
    await!(client_to_server.join(server_to_client))
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn it_works() {
        let client_addr = "127.0.0.1:3345".parse().unwrap();
        let server_addr = "127.0.0.1:3346".parse().unwrap();
        let s = ::std::thread::spawn(move || server(server_addr, server_addr));
        let c = ::std::thread::spawn(move || client(client_addr, server_addr));
        s.join().unwrap();
        c.join().unwrap();
    }
}
<|endoftext|>