Skip to content

Commit

Permalink
Merge pull request #32 from WiSaGaN/release/0.8.0
Browse files Browse the repository at this point in the history
Release/0.8.0
  • Loading branch information
WiSaGaN committed Jan 30, 2016
2 parents be72714 + 19a42df commit 69e9f82
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 29 deletions.
48 changes: 48 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1 +1,49 @@
sudo: false
language: rust
# necessary for `travis-cargo coveralls --no-sudo`
addons:
apt:
packages:
- libcurl4-openssl-dev
- libelf-dev
- libdw-dev
- binutils-dev # optional: only required for the --verify flag of coveralls

# run builds for all the trains (and more)
rust:
- nightly
- beta
# check it compiles on the latest stable compiler
- stable
# and the first stable one (this should be bumped as the minimum
# Rust version required changes)
- 1.6.0

# load travis-cargo
before_script:
- |
pip install 'travis-cargo<0.2' --user &&
export PATH=$HOME/.local/bin:$PATH
# the main build
script:
- |
travis-cargo build &&
travis-cargo test &&
travis-cargo bench &&
travis-cargo --only stable doc
after_success:
# upload the documentation from the build with stable (automatically only actually
# runs on the master branch, not individual PRs)
- travis-cargo --only stable doc-upload
# measure code coverage and upload to coveralls.io (the verify
# argument mitigates kcov crashes due to malformed debuginfo, at the
# cost of some speed <https://github.com/huonw/travis-cargo/issues/12>)
- travis-cargo coveralls --no-sudo --verify

env:
global:
# override the default `--features unstable` used for the nightly branch (optional)
- TRAVIS_CARGO_NIGHTLY_FEATURE=""
# encrypted github token for doc upload (see `GH_TOKEN` link above)
- secure: "..."
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Changelog

This project roughly adheres to [Semantic Versioning](http://semver.org/). For 0.x.y releases, `x` is the major version in semver, while `y` is the minor version.

## [0.8.0] - 2016-01-31

### Breaking changes

* Change `Error` to use `std::io::ErrorKind` as one of the variants

### Library

* Implement `std::io::Iterator` for `FileReader`
* Fix corrupt segment issue on FileWriter

### Project

* Use multiple version Rust to compile on Travis: nightly, beta, stable, 1.6.0
* Add support for Coveralls
* Add documentation page on crates.io
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[package]

name = "diffusion"
version = "0.7.4"
version = "0.8.0"
authors = ["Wangshan Lu <wisagan@gmail.com>"]
license = "MIT/Apache-2.0"
readme = "README.md"
documentation = "http://wisagan.github.io/rust-diffusion/diffusion/"
repository = "https://github.com/WiSaGaN/rust-diffusion"
homepage = "https://github.com/WiSaGaN/rust-diffusion"
description = """
This is the rust implementation of diffusion library. Diffusion is an effcient message-based data distribution library.
"""
Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
# rust-diffusion

[![Build Status](https://travis-ci.org/WiSaGaN/rust-diffusion.svg?branch=master)](https://travis-ci.org/WiSaGaN/rust-diffusion)
[![crates.io](http://meritbadge.herokuapp.com/diffusion)](https://crates.io/crates/diffusion)
[![Build Status](https://travis-ci.org/WiSaGaN/rust-diffusion.svg?branch=master)](https://travis-ci.org/WiSaGaN/rust-diffusion)
[![Coverage Status](https://coveralls.io/repos/github/WiSaGaN/rust-diffusion/badge.svg?branch=master)](https://coveralls.io/github/WiSaGaN/rust-diffusion?branch=master)

This is the rust implementation of diffusion library. Diffusion is an effcient message-based data distribution library.

## [API documentation](http://wisagan.github.io/rust-diffusion/diffusion/)

## Notes

This library requires stable Rust 1.6.0.
38 changes: 27 additions & 11 deletions src/file.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std;
use std::io::{Read, Write};
use ::{Error, Reader, Result, Writer};

use super::{Error, Reader, Result, Writer};
use std::io::{Read, Write};
use std::mem::{size_of, transmute};

const FILE_HEADER: &'static [u8] = b"DFSN";

Expand Down Expand Up @@ -34,9 +34,9 @@ impl<T> Reader for FileReader<T> where T: Read {
// Rust currently does not support constexpr.
let mut header = [0u8; 4];
let header_read_length = try!(self.file.read(&mut header));
if header_read_length == std::mem::size_of::<i32>() {
let header_ptr: *const i32 = unsafe { std::mem::transmute(&header[0]) };
let body_length_number = unsafe { std::ptr::read::<i32>(header_ptr) };
if header_read_length == size_of::<i32>() {
let header_ptr: *const i32 = unsafe { transmute(&header[0]) };
let body_length_number = unsafe { ::std::ptr::read::<i32>(header_ptr) };
let body_length = body_length_number as usize;
let mut remaining_length = body_length;
let mut full_buffer = Vec::with_capacity(body_length);
Expand Down Expand Up @@ -66,6 +66,17 @@ impl<T> Reader for FileReader<T> where T: Read {
}
}

impl<T> Iterator for FileReader<T> where T: Read {
type Item = Result<Vec<u8>>;
fn next(&mut self) -> Option<Result<Vec<u8>>> {
match self.read() {
Ok(Some(data)) => Some(Ok(data)),
Ok(None) => None,
Err(error) => Some(Err(error)),
}
}
}

/// is a writer for file.
/// It can only start to write a new file but not append to an existing file.
#[derive(Debug)]
Expand All @@ -79,17 +90,22 @@ impl<T> FileWriter<T> where T: Write {
/// returns a new file writer instance.
/// It returns error if there is IO error during the process.
pub fn new(mut file: T) -> Result<FileWriter<T>> {
try!(file.write(FILE_HEADER));
Ok(FileWriter { file: file })
if try!(file.write(FILE_HEADER)) == FILE_HEADER.len() {
Ok(FileWriter { file: file })
} else {
Err(Error::CorruptSegmentHeader)
}
}
}

impl<T> Writer for FileWriter<T> where T: Write {
fn write(&mut self, buf: &[u8]) -> Result<()> {
let value = buf.len() as i32;
let header_ptr: *const u8 = unsafe { std::mem::transmute(&value) };
let header_length = std::mem::size_of::<i32>();
let slice = unsafe { std::slice::from_raw_parts(header_ptr, header_length) };
let header_ptr: *const u8 = unsafe { transmute(&value) };
let header_length = size_of::<i32>();
let slice = unsafe { ::std::slice::from_raw_parts(header_ptr, header_length) };
// TODO: Check insufficient write. Or even need to add new error types. Restore upon
// failuer? And add tests.
try!(self.file.write(slice));
try!(self.file.write(buf));
Ok(())
Expand Down
58 changes: 51 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//! Diffusion is a static library that provides several transport with a unified interface for
//! messages based sub-pub style communication.

extern crate net2;

mod file;
mod multicast;
Expand All @@ -16,7 +17,7 @@ use std::convert::From;
use std::{error, fmt};

/// represents errors that can be encountered during the usage of of reader and writer.
#[derive(Debug)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Error {
/// indicates corruption when initializing the reader. This can only happens in a file.
CorruptSegmentHeader,
Expand All @@ -27,7 +28,7 @@ pub enum Error {
InsufficientLength(usize),
/// indicates there is an IO error happening during reading or writing. This can happen in all
/// transport types.
IoError(Box<error::Error>),
IoError(std::io::ErrorKind),
}

impl fmt::Display for Error {
Expand All @@ -47,16 +48,13 @@ impl error::Error for Error {
}

fn cause(&self) -> Option<&error::Error> {
match *self {
Error::IoError(ref cause) => Some(&**cause),
_ => None,
}
None
}
}

impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Error {
Error::IoError(Box::new(err))
Error::IoError(err.kind())
}
}

Expand All @@ -79,3 +77,49 @@ pub trait Writer {

pub use file::{FileReader, FileWriter};
pub use multicast::{MulticastReader, MulticastWriter};

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

#[test]
fn reader_return_err_on_corrupted_header() {
let empty = std::io::empty();
assert_eq!(Error::CorruptSegmentHeader, FileReader::new(empty).err().unwrap());
let wrong_header = &b"DFSM"[..];
assert_eq!(Error::CorruptSegmentHeader, FileReader::new(wrong_header).err().unwrap());
}

#[test]
fn reader_read_one_message() {
let data = &b"DFSN\x05\0\0\0hello"[..];
assert_eq!(b"hello"[..], FileReader::new(data).unwrap().read().unwrap().unwrap()[..]);
}

#[test]
fn reader_return_err_on_truncated_data() {
let truncated_data = &b"DFSN\x05\0\0\0hell"[..];
assert_eq!(Err(Error::InsufficientLength(1)), FileReader::new(truncated_data).unwrap().read());
}

#[test]
fn reader_return_err_on_corrupted_message_header() {
let data_with_corrupted_header = &b"DFSN\x05\0\0"[..];
assert_eq!(Err(Error::CorruptMsgHeader), FileReader::new(data_with_corrupted_header).unwrap().read());
}

#[test]
fn writer_return_err_when_writing_header_with_short_length() {
let mut buffer = [0u8;3];
assert_eq!(Error::CorruptSegmentHeader, FileWriter::new(&mut buffer[..]).err().unwrap());
}

#[test]
fn writer_write_one_message() {
let message: &[u8] = b"hello";
let mut writer: Vec<u8> = vec![];
assert!(FileWriter::new(&mut writer).unwrap().write(message).is_ok());
assert_eq!(b"DFSN\x05\0\0\0hello".as_ref(), &writer[..]);
}
}
12 changes: 4 additions & 8 deletions src/multicast.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
extern crate net2;
use ::{Reader, Result, Writer};

use self::net2::UdpSocketExt;

use std;
use std::net::{SocketAddrV4, UdpSocket};

use super::{Reader, Result, Writer};
use net2::UdpSocketExt;
use std::net::{Ipv4Addr, SocketAddrV4, UdpSocket};

/// is writer for multicast.
/// `MulticastWriter` uses the natual UDP packet as message boundary.
Expand Down Expand Up @@ -47,7 +43,7 @@ impl MulticastReader {
/// Binds to `addr`.
pub fn new(addr: SocketAddrV4) -> Result<MulticastReader> {
let socket = try!(UdpSocket::bind(&addr));
try!(socket.join_multicast_v4(&addr.ip(), &std::net::Ipv4Addr::new(0u8, 0u8, 0u8, 0u8)));
try!(socket.join_multicast_v4(&addr.ip(), &Ipv4Addr::new(0u8, 0u8, 0u8, 0u8)));
Ok(MulticastReader {
socket: socket,
buf: vec![0u8; 1536usize],
Expand Down

0 comments on commit 69e9f82

Please sign in to comment.