<commit_before>#![feature(const_fn)]
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

extern crate serde;
extern crate serde_json;

use serde::Deserialize;
use std::fmt;
use std::io::{self, Read};
use std::convert;
use std::collections::HashMap;
use std::net::{
    TcpListener,
    TcpStream,
    SocketAddr,
    ToSocketAddrs,
};
use std::sync::{
    self,
    Mutex,
    Arc,
};
use std::sync::mpsc::{
    channel,
    Sender,
    TryRecvError,
};
use std::thread::{
    self,
    JoinHandle,
};

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Json(serde_json::Error),
    Sender,
    Unimplemented,
}

impl convert::From<serde_json::Error> for Error {
    fn from(err: serde_json::Error) -> Error {
        match err {
            serde_json::Error::IoError(err) => Error::Io(err),
            err => Error::Json(err),
        }
    }
}

impl convert::From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl<T> convert::From<sync::mpsc::SendError<T>> for Error {
    fn from(_: sync::mpsc::SendError<T>) -> Error {
        Error::Sender
    }
}

pub type Result<T> = std::result::Result<T, Error>;

fn handle_conn<F, Request, Reply>(stream: TcpStream, f: F) -> Result<()>
    where Request: 'static + fmt::Debug + Send + serde::de::Deserialize + serde::ser::Serialize,
          Reply: 'static + fmt::Debug + serde::ser::Serialize,
          F: 'static + Clone + Serve<Request, Reply>
{
    let read_stream = try!(stream.try_clone());
    let mut de = serde_json::Deserializer::new(read_stream.bytes());
    let stream = Arc::new(Mutex::new(stream));
    loop {
        let request_packet: Packet<Request> = try!(Packet::deserialize(&mut de));
        match request_packet {
            Packet::Shutdown => {
                let stream = stream.clone();
                let mut my_stream = stream.lock().unwrap();
                try!(serde_json::to_writer(&mut *my_stream, &request_packet));
                break;
            },
            Packet::Message(id, message) => {
                let f = f.clone();
                let arc_stream = stream.clone();
                thread::spawn(move || {
                    let reply = f.serve(message);
                    let reply_packet = Packet::Message(id, reply);
                    let mut my_stream = arc_stream.lock().unwrap();
                    serde_json::to_writer(&mut *my_stream, &reply_packet).unwrap();
                });
            },
        }
    }
    Ok(())
}

pub struct Shutdown {
    tx: Sender<()>,
    join_handle: JoinHandle<()>,
    addr: SocketAddr,
}

impl Shutdown {
    pub fn wait(self) {
        self.join_handle.join().unwrap();
    }

    pub fn shutdown(self) {
        self.tx.send(()).expect(&line!().to_string());
        TcpStream::connect(&self.addr).unwrap();
        self.join_handle.join().expect(&line!().to_string());
    }
}

pub fn serve_async<A, F, Request, Reply>(addr: A, f: F) -> io::Result<Shutdown>
    where A: ToSocketAddrs,
          Request: 'static + fmt::Debug + Send + serde::de::Deserialize + fmt::Debug + serde::ser::Serialize,
          Reply: 'static + fmt::Debug + serde::ser::Serialize,
          F: 'static + Clone + Serve<Request, Reply>,
{
    let addr = addr.to_socket_addrs().unwrap().next().unwrap();
    let listener = try!(TcpListener::bind(addr.clone()));
    let (die_tx, die_rx) = channel();
    let join_handle = thread::spawn(move || {
        for conn in listener.incoming() {
            match die_rx.try_recv() {
                Ok(_) => break,
                Err(TryRecvError::Disconnected) => {
                    println!("serve: sender disconnected ");
                    break;
                },
                _ => (),
            }
            let conn = match conn {
                Err(err) => {
                    println!("I couldn't unwrap the connection :( {:?}", err);
                    return;
                },
                Ok(c) => c,
            };
            let f = f.clone();
            thread::spawn(move || {
                if let Err(err) = handle_conn(conn, f) {
                    println!("error handling connection: {:?}", err);
                }
            });
        }
    });
    Ok(Shutdown{
        tx: die_tx,
        join_handle: join_handle,
        addr: addr.clone(),
    })
}

pub trait Serve<Request, Reply>: Send + Sync {
    fn serve(&self, request: Request) -> Reply;
}

impl<Request, Reply, S> Serve<Request, Reply> for Arc<S>
    where S: Serve<Request, Reply>
{
    fn serve(&self, request: Request) -> Reply {
        S::serve(self, request)
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
enum Packet<T> {
    Message(u64, T),
    Shutdown,
}

fn reader<Reply>(
    stream: TcpStream,
    requests: Arc<Mutex<HashMap<u64, Sender<Reply>>>>)
    where Reply: serde::Deserialize
{
    let mut de = serde_json::Deserializer::new(stream.bytes());
    loop {
        match Packet::deserialize(&mut de) {
            Ok(Packet::Message(id, reply)) => {
                let mut requests = requests.lock().unwrap();
                let reply_tx = requests.remove(&id).unwrap();
                reply_tx.send(reply).unwrap();
            },
            Ok(Packet::Shutdown) => {
                break;
            }
            // TODO: This shutdown logic is janky.. What's the right way to do this?
            Err(err) => panic!("unexpected error while parsing!: {:?}", err),
        }
    }
}

fn increment(cur_id: &mut u64) -> u64 {
    let id = *cur_id;
    *cur_id += 1;
    id
}

struct SyncedClientState {
    next_id: u64,
    stream: TcpStream,
}

pub struct Client<Request, Reply>
    where Request: serde::ser::Serialize
{
    synced_state: Mutex<SyncedClientState>,
    requests: Arc<Mutex<HashMap<u64, Sender<Reply>>>>,
    reader_guard: Option<thread::JoinHandle<()>>,
    _request: std::marker::PhantomData<Request>,
}

impl<Request, Reply> Client<Request, Reply>
    where Reply: serde::de::Deserialize + Send + 'static,
          Request: serde::ser::Serialize
{
    pub fn new(stream: TcpStream) -> io::Result<Self> {
        let requests = Arc::new(Mutex::new(HashMap::new()));
        let reader_stream = try!(stream.try_clone());
        let reader_requests = requests.clone();
        let reader_guard =
            thread::spawn(move || reader(reader_stream, reader_requests));
        Ok(Client{
            synced_state: Mutex::new(SyncedClientState{
                next_id: 0,
                stream: stream,
            }),
            requests: requests,
            reader_guard: Some(reader_guard),
            _request: std::marker::PhantomData,
        })
    }

    pub fn rpc(&self, request: &Request) -> Result<Reply>
        where Request: serde::ser::Serialize + Send + 'static
    {
        let (tx, rx) = channel();
        let mut state = self.synced_state.lock().unwrap();
        let id = increment(&mut state.next_id);
        {
            let mut requests = self.requests.lock().unwrap();
            requests.insert(id, tx);
        }
        let packet = Packet::Message(id, request);
        try!(serde_json::to_writer(&mut state.stream, &packet));
        drop(state);
        Ok(rx.recv().unwrap())
    }
}

impl<Request, Reply> Drop for Client<Request, Reply>
    where Request: serde::ser::Serialize
{
    fn drop(&mut self) {
        {
            let mut state = self.synced_state.lock().unwrap();
            let packet: Packet<Request> = Packet::Shutdown;
            serde_json::to_writer(&mut state.stream, &packet);
        }
        self.reader_guard.take().unwrap().join().unwrap();
    }
}

#[cfg(test)]
mod test {
    use serde;
    use super::*;
    use std::fmt;
    use std::io;
    use std::net::{TcpStream, SocketAddr, ToSocketAddrs};
    use std::sync::{Arc, Mutex, Barrier};
    use std::sync::atomic::{AtomicUsize, Ordering};
    use std::thread;

    const PORT: AtomicUsize = AtomicUsize::new(10000);

    fn next_addr() -> SocketAddr {
        let addr = format!("127.0.0.1:{}", PORT.fetch_add(1, Ordering::SeqCst));
        addr.to_socket_addrs().unwrap().next().unwrap()
    }

    #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
    enum Request {
        Increment
    }

    #[derive(Debug, PartialEq, Serialize, Deserialize)]
    enum Reply {
        Increment(u64)
    }

    struct Server {
        counter: Mutex<u64>,
    }

    impl Serve<Request, Reply> for Server {
        fn serve(&self, _: Request) -> Reply {
            let mut counter = self.counter.lock().unwrap();
            let reply = Reply::Increment(*counter);
            *counter += 1;
            reply
        }
    }

    impl Server {
        fn new() -> Server {
            Server{counter: Mutex::new(0)}
        }

        fn count(&self) -> u64 {
            *self.counter.lock().unwrap()
        }
    }

    fn wtf<F, Request, Reply>(server: F) -> (SocketAddr, Shutdown)
        where Request: 'static + fmt::Debug + Send + serde::de::Deserialize + fmt::Debug + serde::ser::Serialize,
              Reply: 'static + fmt::Debug + Send + serde::ser::Serialize,
              F: 'static + Clone + Serve<Request, Reply>
    {
        let mut addr;
        let mut shutdown;
        while let &Err(_) = {shutdown = serve_async({addr = next_addr(); &addr}, server.clone()); &shutdown} { }
        (addr, shutdown.unwrap())
    }

    #[test]
    fn test_handle() {
        let server = Arc::new(Server::new());
        let (addr, shutdown) = wtf(server.clone());
        let client_stream = TcpStream::connect(&addr).unwrap();
        let client: Client<Reply> = Client::new(client_stream).expect(&line!().to_string());
        client.disconnect::<Request>().unwrap();
        shutdown.shutdown();
    }

    #[test]
    fn test() {
        let server = Arc::new(Server::new());
        let (addr, shutdown) = wtf(server.clone());
        let client_stream = TcpStream::connect(&addr).unwrap();
        let client = Client::new(client_stream).unwrap();
        assert_eq!(Reply::Increment(0), client.rpc(&Request::Increment).unwrap());
        assert_eq!(1, server.count());
        assert_eq!(Reply::Increment(1), client.rpc(&Request::Increment).unwrap());
        assert_eq!(2, server.count());
        client.disconnect::<Request>().unwrap();
        shutdown.shutdown();
    }

    struct BarrierServer {
        barrier: Barrier,
        inner: Server,
    }

    impl Serve<Request, Reply> for BarrierServer {
        fn serve(&self, request: Request) -> Reply {
            self.barrier.wait();
            let reply = try!(self.inner.serve(request));
            Ok(reply)
        }
    }

    impl BarrierServer {
        fn new(n: usize) -> BarrierServer {
            BarrierServer{barrier: Barrier::new(n), inner: Server::new()}
        }

        fn count(&self) -> u64 {
            self.inner.count()
        }
    }

    #[test]
    fn test_concurrent() {
        let server = Arc::new(BarrierServer::new(10));
        let (addr, shutdown) = wtf(server.clone());
        let client_stream = TcpStream::connect(&addr).unwrap();
        let client: Arc<Client<Reply>> = Arc::new(Client::new(client_stream).unwrap());
        let mut join_handles = vec![];
        for _ in 0..10 {
            let my_client = client.clone();
            join_handles.push(thread::spawn(move || my_client.rpc(&Request::Increment).unwrap()));
        }
        for handle in join_handles.into_iter() {
            handle.join().unwrap();
        }
        assert_eq!(10, server.count());
        let client = match Arc::try_unwrap(client) {
            Err(_) => panic!("couldn't unwrap arc"),
            Ok(c) => c,
        };
        client.disconnect::<Request>().unwrap();
        shutdown.shutdown();
    }
}
<commit_msg>Warn if an error occurs when disconnecting client from server<commit_after>#![feature(const_fn)]
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

extern crate serde;
extern crate serde_json;

use serde::Deserialize;
use std::fmt;
use std::io::{self, Read};
use std::convert;
use std::collections::HashMap;
use std::net::{
    TcpListener,
    TcpStream,
    SocketAddr,
    ToSocketAddrs,
};
use std::sync::{
    self,
    Mutex,
    Arc,
};
use std::sync::mpsc::{
    channel,
    Sender,
    TryRecvError,
};
use std::thread::{
    self,
    JoinHandle,
};

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Json(serde_json::Error),
    Sender,
    Unimplemented,
}

impl convert::From<serde_json::Error> for Error {
    fn from(err: serde_json::Error) -> Error {
        match err {
            serde_json::Error::IoError(err) => Error::Io(err),
            err => Error::Json(err),
        }
    }
}

impl convert::From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl<T> convert::From<sync::mpsc::SendError<T>> for Error {
    fn from(_: sync::mpsc::SendError<T>) -> Error {
        Error::Sender
    }
}

pub type Result<T> = std::result::Result<T, Error>;

fn handle_conn<F, Request, Reply>(stream: TcpStream, f: F) -> Result<()>
    where Request: 'static + fmt::Debug + Send + serde::de::Deserialize + serde::ser::Serialize,
          Reply: 'static + fmt::Debug + serde::ser::Serialize,
          F: 'static + Clone + Serve<Request, Reply>
{
    let read_stream = try!(stream.try_clone());
    let mut de = serde_json::Deserializer::new(read_stream.bytes());
    let stream = Arc::new(Mutex::new(stream));
    loop {
        let request_packet: Packet<Request> = try!(Packet::deserialize(&mut de));
        match request_packet {
            Packet::Shutdown => {
                let stream = stream.clone();
                let mut my_stream = stream.lock().unwrap();
                try!(serde_json::to_writer(&mut *my_stream, &request_packet));
                break;
            },
            Packet::Message(id, message) => {
                let f = f.clone();
                let arc_stream = stream.clone();
                thread::spawn(move || {
                    let reply = f.serve(message);
                    let reply_packet = Packet::Message(id, reply);
                    let mut my_stream = arc_stream.lock().unwrap();
                    serde_json::to_writer(&mut *my_stream, &reply_packet).unwrap();
                });
            },
        }
    }
    Ok(())
}

pub struct Shutdown {
    tx: Sender<()>,
    join_handle: JoinHandle<()>,
    addr: SocketAddr,
}

impl Shutdown {
    pub fn wait(self) {
        self.join_handle.join().unwrap();
    }

    pub fn shutdown(self) {
        self.tx.send(()).expect(&line!().to_string());
        TcpStream::connect(&self.addr).unwrap();
        self.join_handle.join().expect(&line!().to_string());
    }
}

pub fn serve_async<A, F, Request, Reply>(addr: A, f: F) -> io::Result<Shutdown>
    where A: ToSocketAddrs,
          Request: 'static + fmt::Debug + Send + serde::de::Deserialize + fmt::Debug + serde::ser::Serialize,
          Reply: 'static + fmt::Debug + serde::ser::Serialize,
          F: 'static + Clone + Serve<Request, Reply>,
{
    let addr = addr.to_socket_addrs().unwrap().next().unwrap();
    let listener = try!(TcpListener::bind(addr.clone()));
    let (die_tx, die_rx) = channel();
    let join_handle = thread::spawn(move || {
        for conn in listener.incoming() {
            match die_rx.try_recv() {
                Ok(_) => break,
                Err(TryRecvError::Disconnected) => {
                    println!("serve: sender disconnected ");
                    break;
                },
                _ => (),
            }
            let conn = match conn {
                Err(err) => {
                    println!("I couldn't unwrap the connection :( {:?}", err);
                    return;
                },
                Ok(c) => c,
            };
            let f = f.clone();
            thread::spawn(move || {
                if let Err(err) = handle_conn(conn, f) {
                    println!("error handling connection: {:?}", err);
                }
            });
        }
    });
    Ok(Shutdown{
        tx: die_tx,
        join_handle: join_handle,
        addr: addr.clone(),
    })
}

pub trait Serve<Request, Reply>: Send + Sync {
    fn serve(&self, request: Request) -> Reply;
}

impl<Request, Reply, S> Serve<Request, Reply> for Arc<S>
    where S: Serve<Request, Reply>
{
    fn serve(&self, request: Request) -> Reply {
        S::serve(self, request)
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
enum Packet<T> {
    Message(u64, T),
    Shutdown,
}

fn reader<Reply>(
    stream: TcpStream,
    requests: Arc<Mutex<HashMap<u64, Sender<Reply>>>>)
    where Reply: serde::Deserialize
{
    let mut de = serde_json::Deserializer::new(stream.bytes());
    loop {
        match Packet::deserialize(&mut de) {
            Ok(Packet::Message(id, reply)) => {
                let mut requests = requests.lock().unwrap();
                let reply_tx = requests.remove(&id).unwrap();
                reply_tx.send(reply).unwrap();
            },
            Ok(Packet::Shutdown) => {
                break;
            }
            // TODO: This shutdown logic is janky.. What's the right way to do this?
            Err(err) => panic!("unexpected error while parsing!: {:?}", err),
        }
    }
}

fn increment(cur_id: &mut u64) -> u64 {
    let id = *cur_id;
    *cur_id += 1;
    id
}

struct SyncedClientState {
    next_id: u64,
    stream: TcpStream,
}

pub struct Client<Request, Reply>
    where Request: serde::ser::Serialize
{
    synced_state: Mutex<SyncedClientState>,
    requests: Arc<Mutex<HashMap<u64, Sender<Reply>>>>,
    reader_guard: Option<thread::JoinHandle<()>>,
    _request: std::marker::PhantomData<Request>,
}

impl<Request, Reply> Client<Request, Reply>
    where Reply: serde::de::Deserialize + Send + 'static,
          Request: serde::ser::Serialize
{
    pub fn new(stream: TcpStream) -> io::Result<Self> {
        let requests = Arc::new(Mutex::new(HashMap::new()));
        let reader_stream = try!(stream.try_clone());
        let reader_requests = requests.clone();
        let reader_guard =
            thread::spawn(move || reader(reader_stream, reader_requests));
        Ok(Client{
            synced_state: Mutex::new(SyncedClientState{
                next_id: 0,
                stream: stream,
            }),
            requests: requests,
            reader_guard: Some(reader_guard),
            _request: std::marker::PhantomData,
        })
    }

    pub fn rpc(&self, request: &Request) -> Result<Reply>
        where Request: serde::ser::Serialize + Send + 'static
    {
        let (tx, rx) = channel();
        let mut state = self.synced_state.lock().unwrap();
        let id = increment(&mut state.next_id);
        {
            let mut requests = self.requests.lock().unwrap();
            requests.insert(id, tx);
        }
        let packet = Packet::Message(id, request);
        try!(serde_json::to_writer(&mut state.stream, &packet));
        drop(state);
        Ok(rx.recv().unwrap())
    }
}

impl<Request, Reply> Drop for Client<Request, Reply>
    where Request: serde::ser::Serialize
{
    fn drop(&mut self) {
        {
            let mut state = self.synced_state.lock().unwrap();
            let packet: Packet<Request> = Packet::Shutdown;
            if let Err(err) = serde_json::to_writer(&mut state.stream, &packet) {
                println!("WARN: while disconnecting client from server: {:?}", err);
            }
        }
        self.reader_guard.take().unwrap().join().unwrap();
    }
}

#[cfg(test)]
mod test {
    use serde;
    use super::*;
    use std::fmt;
    use std::io;
    use std::net::{TcpStream, SocketAddr, ToSocketAddrs};
    use std::sync::{Arc, Mutex, Barrier};
    use std::sync::atomic::{AtomicUsize, Ordering};
    use std::thread;

    const PORT: AtomicUsize = AtomicUsize::new(10000);

    fn next_addr() -> SocketAddr {
        let addr = format!("127.0.0.1:{}", PORT.fetch_add(1, Ordering::SeqCst));
        addr.to_socket_addrs().unwrap().next().unwrap()
    }

    #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
    enum Request {
        Increment
    }

    #[derive(Debug, PartialEq, Serialize, Deserialize)]
    enum Reply {
        Increment(u64)
    }

    struct Server {
        counter: Mutex<u64>,
    }

    impl Serve<Request, Reply> for Server {
        fn serve(&self, _: Request) -> Reply {
            let mut counter = self.counter.lock().unwrap();
            let reply = Reply::Increment(*counter);
            *counter += 1;
            reply
        }
    }

    impl Server {
        fn new() -> Server {
            Server{counter: Mutex::new(0)}
        }

        fn count(&self) -> u64 {
            *self.counter.lock().unwrap()
        }
    }

    fn wtf<F, Request, Reply>(server: F) -> (SocketAddr, Shutdown)
        where Request: 'static + fmt::Debug + Send + serde::de::Deserialize + fmt::Debug + serde::ser::Serialize,
              Reply: 'static + fmt::Debug + Send + serde::ser::Serialize,
              F: 'static + Clone + Serve<Request, Reply>
    {
        let mut addr;
        let mut shutdown;
        while let &Err(_) = {shutdown = serve_async({addr = next_addr(); &addr}, server.clone()); &shutdown} { }
        (addr, shutdown.unwrap())
    }

    #[test]
    fn test_handle() {
        let server = Arc::new(Server::new());
        let (addr, shutdown) = wtf(server.clone());
        let client_stream = TcpStream::connect(&addr).unwrap();
        let client: Client<Reply> = Client::new(client_stream).expect(&line!().to_string());
        client.disconnect::<Request>().unwrap();
        shutdown.shutdown();
    }

    #[test]
    fn test() {
        let server = Arc::new(Server::new());
        let (addr, shutdown) = wtf(server.clone());
        let client_stream = TcpStream::connect(&addr).unwrap();
        let client = Client::new(client_stream).unwrap();
        assert_eq!(Reply::Increment(0), client.rpc(&Request::Increment).unwrap());
        assert_eq!(1, server.count());
        assert_eq!(Reply::Increment(1), client.rpc(&Request::Increment).unwrap());
        assert_eq!(2, server.count());
        client.disconnect::<Request>().unwrap();
        shutdown.shutdown();
    }

    struct BarrierServer {
        barrier: Barrier,
        inner: Server,
    }

    impl Serve<Request, Reply> for BarrierServer {
        fn serve(&self, request: Request) -> Reply {
            self.barrier.wait();
            let reply = try!(self.inner.serve(request));
            Ok(reply)
        }
    }

    impl BarrierServer {
        fn new(n: usize) -> BarrierServer {
            BarrierServer{barrier: Barrier::new(n), inner: Server::new()}
        }

        fn count(&self) -> u64 {
            self.inner.count()
        }
    }

    #[test]
    fn test_concurrent() {
        let server = Arc::new(BarrierServer::new(10));
        let (addr, shutdown) = wtf(server.clone());
        let client_stream = TcpStream::connect(&addr).unwrap();
        let client: Arc<Client<Reply>> = Arc::new(Client::new(client_stream).unwrap());
        let mut join_handles = vec![];
        for _ in 0..10 {
            let my_client = client.clone();
            join_handles.push(thread::spawn(move || my_client.rpc(&Request::Increment).unwrap()));
        }
        for handle in join_handles.into_iter() {
            handle.join().unwrap();
        }
        assert_eq!(10, server.count());
        let client = match Arc::try_unwrap(client) {
            Err(_) => panic!("couldn't unwrap arc"),
            Ok(c) => c,
        };
        client.disconnect::<Request>().unwrap();
        shutdown.shutdown();
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use libc::{c_char, c_int, strlen};
use std::ffi::{NulError, CString};

const MAX_USERNAME: c_int = 256;

// TODO: We can do better here. The man pages indicate the specific
// errors we may receive. For example, krb5_aname_to_localname returns
// either KRB5_LNAME_NOTRANS or KRB5_CONFIG_NOTENUFSPACE. Also we
// should create our own struct which implements the Error trait which
// wraps the raw Error so that it may later be retrieved and
// inspected.
#[derive(Debug)]
pub enum Error {
    Krb5(c_int),
    Nul(NulError),
}

impl From<NulError> for Error {
    fn from(e: NulError) -> Error {
        Error::Nul(e)
    }
}

pub type Result<T> = std::result::Result<T, Error>;

// From krb5.h:
//  struct _krb5_context;
//  typedef struct _krb5_context * krb5_context;
//  This is opaque in the c header file.
#[allow(non_camel_case_types)]
#[repr(C)]
struct krb5_context;

#[allow(raw_pointer_derive)]
#[derive(Debug)]
pub struct Context {
    ctx: *mut krb5_context,
}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe{
            krb5_free_context(self.ctx)
        }
    }
}

impl Context {
    pub fn new() -> Result<Context> {
        let mut kcontext: *mut krb5_context = std::ptr::null_mut();
        let err = unsafe {krb5_init_context(&mut kcontext)};
        if err == 0 {
            Ok(Context{ctx: kcontext})
        } else {
            Err(Error::Krb5(err))
        }
    }

    // TODO: evaluate if it's appropriate to return a CString, an
    // OsString, or something else. It probably doesn't make sense to
    // require Utf8 encoding in this library.
    pub fn localname(&self, name: &str) -> Result<String> {
        let mut kprinc: *mut krb5_principal = std::ptr::null_mut();
        let cname = try!(CString::new(name.as_bytes()));
        let err = unsafe {krb5_parse_name(self.ctx, cname.as_ptr(), &mut kprinc)};
        if err != 0 {
            return Err(Error::Krb5(err));
        }

        let mut lname: Vec<u8> = Vec::with_capacity(MAX_USERNAME as usize);
        unsafe {lname.set_len((MAX_USERNAME - 1) as usize)};
        lname.push('\0' as u8);
        let err = unsafe {krb5_aname_to_localname(self.ctx,
                                                  kprinc,
                                                  MAX_USERNAME - 1,
                                                  &mut lname[..])};
        unsafe {krb5_free_principal(self.ctx, kprinc)}
        if err != 0 {
            return Err(Error::Krb5(err));
        }

        // Need to find the length (position of the NUL put in place by
        // krb5_aname_to_lname to indicate the end of the string and
        // truncate the Vec<u8> to that size so that we can convert it
        // it to a String
        let len = unsafe {strlen(lname.as_ptr() as *const i8)};
        lname.truncate(len as usize);

        // TODO: Fix this error. Having issues w/ the From Trait on
        // this error type, it's not Utf8Error, it's something in
        // collections.
        match String::from_utf8(lname) {
            Ok(s) => Ok(s),
            Err(_) => Err(Error::Krb5(-1)),
        }
    }
}

// TODO: Do we want to make a Principal struct which wraps
// krb5_principal so that it can become a first class citizen with
// it's own Drop? If we do, we'll be able to actually use them to do
// other things at some time. Unfortunately, the mechanism by which
// it's freed would require us to capture a reference to the Context
// within the Principal struct so it's available.
// From krb5.h:
//  typedef struct krb5_principal_data {
//      krb5_magic magic;
//      krb5_data realm;
//      krb5_data *data;            /**< An array of strings */
//      krb5_int32 length;
//      krb5_int32 type;
//  } krb5_principal_data;
//  typedef krb5_principal_data * krb5_principal;
// Note: I'm leaving this as opaque because we don't actually use its
// contents at all.
#[allow(non_camel_case_types)]
#[repr(C)]
struct krb5_principal;

#[link(name = "krb5")]
extern "C" {
    // From krb5.h:
    //  krb5_error_code KRB5_CALLCONV
    //  krb5_init_context(krb5_context *context);
    fn krb5_init_context(context: *mut *mut krb5_context) -> c_int;

    // From krb5.h:
    //  void KRB5_CALLCONV
    //  krb5_free_context(krb5_context context);
    fn krb5_free_context(context: *mut krb5_context);

    // From krb5.h:
    //  krb5_error_code KRB5_CALLCONV
    //  krb5_parse_name(krb5_context context,
    //                  const char *name,
    //                  krb5_principal *nprincipal);
    fn krb5_parse_name(context: *mut krb5_context,
                       name: *const c_char,
                       principal: *mut *mut krb5_principal) -> c_int;

    // From krb5.h:
    //  void KRB5_CALLCONV
    //  krb5_free_principal(krb5_context context,
    //                      krb5_principal val);
    fn krb5_free_principal(context: *mut krb5_context,
                           val: *mut krb5_principal);

    // From krb5.h:
    //  krb5_error_code KRB5_CALLCONV
    //  krb5_aname_to_localname(krb5_context context,
    //                          krb5_const_principal aname,
    //                          int lnsize_in,
    //                          char *lname);
    fn krb5_aname_to_localname(context: *mut krb5_context,
                               aname: *mut krb5_principal,
                               size: c_int,
                               lname: *mut [u8]) -> c_int;
}
<commit_msg>Cleanup errors<commit_after>extern crate libc;

use libc::{c_char, c_int, strlen};
use std::ffi::{NulError, CString};
use std::string::FromUtf8Error;

const MAX_USERNAME: c_int = 256;

// TODO: We can do better here. The man pages indicate the specific
// errors we may receive. For example, krb5_aname_to_localname returns
// either KRB5_LNAME_NOTRANS or KRB5_CONFIG_NOTENUFSPACE. Also we
// should create our own struct which implements the Error trait which
// wraps the raw Error so that it may later be retrieved and
// inspected.
#[derive(Debug)]
pub enum Error {
    Krb5(c_int),
    FromUtf8(FromUtf8Error),
    Nul(NulError),
}

impl From<NulError> for Error {
    fn from(e: NulError) -> Error {
        Error::Nul(e)
    }
}

impl From<FromUtf8Error> for Error {
    fn from(e: FromUtf8Error) -> Error {
        Error::FromUtf8(e)
    }
}

pub type Result<T> = std::result::Result<T, Error>;

// From krb5.h:
//  struct _krb5_context;
//  typedef struct _krb5_context * krb5_context;
//  This is opaque in the c header file.
#[allow(non_camel_case_types)]
#[repr(C)]
struct krb5_context;

#[allow(raw_pointer_derive)]
#[derive(Debug)]
pub struct Context {
    ctx: *mut krb5_context,
}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe{
            krb5_free_context(self.ctx)
        }
    }
}

impl Context {
    pub fn new() -> Result<Context> {
        let mut kcontext: *mut krb5_context = std::ptr::null_mut();
        let err = unsafe {krb5_init_context(&mut kcontext)};
        if err == 0 {
            Ok(Context{ctx: kcontext})
        } else {
            Err(Error::Krb5(err))
        }
    }

    // TODO: evaluate if it's appropriate to return a CString, an
    // OsString, or something else. It probably doesn't make sense to
    // require Utf8 encoding in this library.
    pub fn localname(&self, name: &str) -> Result<String> {
        let mut kprinc: *mut krb5_principal = std::ptr::null_mut();
        let cname = try!(CString::new(name.as_bytes()));
        let err = unsafe {krb5_parse_name(self.ctx, cname.as_ptr(), &mut kprinc)};
        if err != 0 {
            return Err(Error::Krb5(err));
        }

        let mut lname: Vec<u8> = Vec::with_capacity(MAX_USERNAME as usize);
        unsafe {lname.set_len((MAX_USERNAME - 1) as usize)};
        lname.push('\0' as u8);
        let err = unsafe {krb5_aname_to_localname(self.ctx,
                                                  kprinc,
                                                  MAX_USERNAME - 1,
                                                  &mut lname[..])};
        unsafe {krb5_free_principal(self.ctx, kprinc)}
        if err != 0 {
            return Err(Error::Krb5(err));
        }

        // Need to find the length (position of the NUL put in place by
        // krb5_aname_to_lname to indicate the end of the string and
        // truncate the Vec<u8> to that size so that we can convert it
        // it to a String
        let len = unsafe {strlen(lname.as_ptr() as *const i8)};
        lname.truncate(len as usize);

        Ok(try!(String::from_utf8(lname)))
    }
}

// TODO: Do we want to make a Principal struct which wraps
// krb5_principal so that it can become a first class citizen with
// it's own Drop? If we do, we'll be able to actually use them to do
// other things at some time. Unfortunately, the mechanism by which
// it's freed would require us to capture a reference to the Context
// within the Principal struct so it's available.
// From krb5.h:
//  typedef struct krb5_principal_data {
//      krb5_magic magic;
//      krb5_data realm;
//      krb5_data *data;            /**< An array of strings */
//      krb5_int32 length;
//      krb5_int32 type;
//  } krb5_principal_data;
//  typedef krb5_principal_data * krb5_principal;
// Note: I'm leaving this as opaque because we don't actually use its
// contents at all.
#[allow(non_camel_case_types)]
#[repr(C)]
struct krb5_principal;

#[link(name = "krb5")]
extern "C" {
    // From krb5.h:
    //  krb5_error_code KRB5_CALLCONV
    //  krb5_init_context(krb5_context *context);
    fn krb5_init_context(context: *mut *mut krb5_context) -> c_int;

    // From krb5.h:
    //  void KRB5_CALLCONV
    //  krb5_free_context(krb5_context context);
    fn krb5_free_context(context: *mut krb5_context);

    // From krb5.h:
    //  krb5_error_code KRB5_CALLCONV
    //  krb5_parse_name(krb5_context context,
    //                  const char *name,
    //                  krb5_principal *nprincipal);
    fn krb5_parse_name(context: *mut krb5_context,
                       name: *const c_char,
                       principal: *mut *mut krb5_principal) -> c_int;

    // From krb5.h:
    //  void KRB5_CALLCONV
    //  krb5_free_principal(krb5_context context,
    //                      krb5_principal val);
    fn krb5_free_principal(context: *mut krb5_context,
                           val: *mut krb5_principal);

    // From krb5.h:
    //  krb5_error_code KRB5_CALLCONV
    //  krb5_aname_to_localname(krb5_context context,
    //                          krb5_const_principal aname,
    //                          int lnsize_in,
    //                          char *lname);
    fn krb5_aname_to_localname(context: *mut krb5_context,
                               aname: *mut krb5_principal,
                               size: c_int,
                               lname: *mut [u8]) -> c_int;
}
<|endoftext|>


<commit_before>//! Implementation of the Micro Transport Protocol.[^spec]
//!
//! [^spec]: http://www.bittorrent.org/beps/bep_0029.html

//   __________  ____  ____
//  /_  __/ __ \/ __ \/ __ \
//   / / / / / / / / / / / /
//  / / / /_/ / /_/ / /_/ /
// /_/  \____/_____/\____/
//
// - Lossy UDP socket for testing purposes: send and receive ops are wrappers
// that stochastically drop or reorder packets.
// - Sending FIN on drop
// - Handle packet loss
// - Path MTU discovery (RFC4821)

#![deny(missing_docs)]
#![feature(core, collections, io)]

extern crate rand;
extern crate time;
#[macro_use] extern crate log;

// Public API
pub use socket::UtpSocket;
pub use stream::UtpStream;

mod util;
mod bit_iterator;
mod packet;
mod socket;
mod stream;
<commit_msg>Add example to module documentation.<commit_after>//! Implementation of the Micro Transport Protocol.[^spec]
//!
//! [^spec]: http://www.bittorrent.org/beps/bep_0029.html

//! # Examples
//!
//! ```
//! extern crate utp;
//!
//! use utp::UtpStream;
//! use std::io::{Read, Write};
//!
//! fn main() {
//!     // Connect to an hypothetical local server running on port 8080
//!     let addr = "127.0.0.1:8080";
//!     let mut stream = match UtpStream::connect(addr) {
//!         Ok(stream) => stream,
//!         Err(e) => panic!("{}", e),
//!     };
//!
//!     // Send a string
//!     match stream.write("Hi there!".as_bytes()) {
//!         Ok(_) => (),
//!         Err(e) => println!("Write failed with {}", e)
//!     }
//!
//!     // Close the stream
//!     match stream.close() {
//!         Ok(()) => println!("Connection closed"),
//!         Err(e) => println!("{}", e)
//!     }
//! }
//! ```

//   __________  ____  ____
//  /_  __/ __ \/ __ \/ __ \
//   / / / / / / / / / / / /
//  / / / /_/ / /_/ / /_/ /
// /_/  \____/_____/\____/
//
// - Lossy UDP socket for testing purposes: send and receive ops are wrappers
// that stochastically drop or reorder packets.
// - Sending FIN on drop
// - Handle packet loss
// - Path MTU discovery (RFC4821)

#![deny(missing_docs)]
#![feature(core, collections, io)]

extern crate rand;
extern crate time;
#[macro_use] extern crate log;

// Public API
pub use socket::UtpSocket;
pub use stream::UtpStream;

mod util;
mod bit_iterator;
mod packet;
mod socket;
mod stream;
<|endoftext|>


<commit_before>//! **mprovision** is a tool that helps `iOS` developers to manage mobileprovision
//! files. Main purpose of this crate is to contain functions and types
//! for **mprovision**.

#[cfg(test)]
#[macro_use(expect)]
extern crate expectest;
#[cfg(test)]
extern crate tempdir;
extern crate plist;
extern crate chrono;
extern crate crossbeam;
extern crate rayon;
extern crate memmem;

use chrono::*;
use rayon::prelude::*;

use std::fs::{self, DirEntry, File};
use std::path::{Path, PathBuf};
use std::env;
use std::io::Read;

pub use error::Error;
pub use profile::Profile;
pub use context::Context;

mod error;
mod profile;
mod context;

/// A Result type for this crate.
pub type Result<T> = std::result::Result<T, Error>;

/// Returns an iterator over the `*.mobileprovision` entries within a given
/// directory.
///
/// # Errors
/// This function will return an error in the following cases:
///
/// - the user lacks the requisite permissions
/// - there is no entry in the filesystem at the provided path
/// - the provided path is not a directory
pub fn entries(dir: &Path) -> Result<Box<Iterator<Item = DirEntry>>> {
    let entries = try!(fs::read_dir(dir));
    let filtered = entries.filter_map(|entry| entry.ok())
                          .filter_map(|entry| {
                              if let Some(ext) = entry.path().extension() {
                                  if ext == "mobileprovision" {
                                      return Some(entry);
                                  }
                              }
                              None
                          });
    Ok(Box::new(filtered))
}

/// Returns the path to the directory that contains installed mobile
/// provisioning profiles.
///
/// Should return `~/Library/MobileDevice/Provisioning Profiles` directory.
///
/// # Errors
/// This function will return an error if 'HOME' environment variable is not set
/// or equal to the empty string.
pub fn directory() -> Result<PathBuf> {
    env::home_dir()
        .map(|path| path.join("Library/MobileDevice/Provisioning Profiles"))
        .ok_or_else(|| {
            Error::Own("'HOME' environment variable is not set or equal to the empty string."
                           .to_owned())
        })
}

pub fn with_dir<F, T>(dir: Option<&Path>, f: F) -> Result<T>
    where F: FnOnce(&Path) -> Result<T>
{
    if let Some(dir) = dir {
        f(&dir)
    } else {
        let dir = try!(directory());
        f(&dir)
    }
}

pub struct SearchInfo {
    pub total: usize,
    pub profiles: Vec<Profile>,
}

pub fn search(dir: &Path, s: &str) -> Result<SearchInfo> {
    let entries: Vec<DirEntry> = try!(entries(dir)).collect();
    Ok(SearchInfo {
        total: entries.len(),
        profiles: parallel(entries, |profile| profile.contains(s)),
    })
}

pub fn remove(dir: &Path, uuid: &str) -> Result<()> {
    find_by_uuid(dir, uuid)
        .and_then(|profile| std::fs::remove_file(&profile.path).map_err(|err| err.into()))
}

pub fn xml(dir: &Path, uuid: &str) -> Result<String> {
    match find_by_uuid(dir, uuid) {
        Ok(profile) => {
            let context = Context::new();
            let mut file = try!(File::open(&profile.path));
            let mut buf = Vec::new();
            try!(file.read_to_end(&mut buf));
            let data = try!(context.find_plist(&buf)
                                   .ok_or(Error::Own("Couldn't parse file.".into())));
            Ok(try!(String::from_utf8(data.to_owned())))
        }
        Err(err) => Err(err),
    }
}

pub fn expired_profiles(dir: &Path, date: DateTime<UTC>) -> Result<SearchInfo> {
    let entries: Vec<DirEntry> = try!(entries(dir)).collect();
    Ok(SearchInfo {
        total: entries.len(),
        profiles: parallel(entries, |profile| profile.expiration_date <= date),
    })
}

fn parallel<F>(entries: Vec<DirEntry>, f: F) -> Vec<Profile>
    where F: Fn(&Profile) -> bool + Sync
{
    let context = Context::new();
    collect(entries.into_par_iter()
                   .weight_max()
                   .filter_map(|entry| Profile::from_file(&entry.path(), &context).ok())
                   .filter(f))
}

fn collect<I>(par_iter: I) -> Vec<I::Item>
    where I: ParallelIterator
{
    let queue = crossbeam::sync::MsQueue::new();

    par_iter.for_each(|item| queue.push(item));

    let mut items = Vec::new();
    while let Some(item) = queue.try_pop() {
        items.push(item);
    }
    items
}

fn find_by_uuid(dir: &Path, uuid: &str) -> Result<Profile> {
    let entries: Vec<DirEntry> = try!(entries(dir)).collect();
    if let Some(profile) = parallel(entries, |profile| profile.uuid == uuid).pop() {
        Ok(profile)
    } else {
        Err(Error::Own(format!("Profile '{}' is not found.", uuid)))
    }
}

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

    #[test]
    fn filter_mobileprovision_files() {
        use tempdir::TempDir;
        use std::fs::File;

        let temp_dir = TempDir::new("test").unwrap();
        let result = entries(temp_dir.path()).map(|iter| iter.count());
        expect!(result).to(be_ok().value(0));

        File::create(temp_dir.path().join("1.mobileprovision")).unwrap();
        File::create(temp_dir.path().join("2.mobileprovision")).unwrap();
        File::create(temp_dir.path().join("3.txt")).unwrap();
        let result = entries(temp_dir.path()).map(|iter| iter.count());
        expect!(result).to(be_ok().value(2));
    }
}
<commit_msg>Remove needless borrow.<commit_after>//! **mprovision** is a tool that helps `iOS` developers to manage mobileprovision
//! files. Main purpose of this crate is to contain functions and types
//! for **mprovision**.

#[cfg(test)]
#[macro_use(expect)]
extern crate expectest;
#[cfg(test)]
extern crate tempdir;
extern crate plist;
extern crate chrono;
extern crate crossbeam;
extern crate rayon;
extern crate memmem;

use chrono::*;
use rayon::prelude::*;

use std::fs::{self, DirEntry, File};
use std::path::{Path, PathBuf};
use std::env;
use std::io::Read;

pub use error::Error;
pub use profile::Profile;
pub use context::Context;

mod error;
mod profile;
mod context;

/// A Result type for this crate.
pub type Result<T> = std::result::Result<T, Error>;

/// Returns an iterator over the `*.mobileprovision` entries within a given
/// directory.
///
/// # Errors
/// This function will return an error in the following cases:
///
/// - the user lacks the requisite permissions
/// - there is no entry in the filesystem at the provided path
/// - the provided path is not a directory
pub fn entries(dir: &Path) -> Result<Box<Iterator<Item = DirEntry>>> {
    let entries = try!(fs::read_dir(dir));
    let filtered = entries.filter_map(|entry| entry.ok())
                          .filter_map(|entry| {
                              if let Some(ext) = entry.path().extension() {
                                  if ext == "mobileprovision" {
                                      return Some(entry);
                                  }
                              }
                              None
                          });
    Ok(Box::new(filtered))
}

/// Returns the path to the directory that contains installed mobile
/// provisioning profiles.
///
/// Should return `~/Library/MobileDevice/Provisioning Profiles` directory.
///
/// # Errors
/// This function will return an error if 'HOME' environment variable is not set
/// or equal to the empty string.
pub fn directory() -> Result<PathBuf> {
    env::home_dir()
        .map(|path| path.join("Library/MobileDevice/Provisioning Profiles"))
        .ok_or_else(|| {
            Error::Own("'HOME' environment variable is not set or equal to the empty string."
                           .to_owned())
        })
}

pub fn with_dir<F, T>(dir: Option<&Path>, f: F) -> Result<T>
    where F: FnOnce(&Path) -> Result<T>
{
    if let Some(dir) = dir {
        f(dir)
    } else {
        let dir = try!(directory());
        f(&dir)
    }
}

pub struct SearchInfo {
    pub total: usize,
    pub profiles: Vec<Profile>,
}

pub fn search(dir: &Path, s: &str) -> Result<SearchInfo> {
    let entries: Vec<DirEntry> = try!(entries(dir)).collect();
    Ok(SearchInfo {
        total: entries.len(),
        profiles: parallel(entries, |profile| profile.contains(s)),
    })
}

pub fn remove(dir: &Path, uuid: &str) -> Result<()> {
    find_by_uuid(dir, uuid)
        .and_then(|profile| std::fs::remove_file(&profile.path).map_err(|err| err.into()))
}

pub fn xml(dir: &Path, uuid: &str) -> Result<String> {
    match find_by_uuid(dir, uuid) {
        Ok(profile) => {
            let context = Context::new();
            let mut file = try!(File::open(&profile.path));
            let mut buf = Vec::new();
            try!(file.read_to_end(&mut buf));
            let data = try!(context.find_plist(&buf)
                                   .ok_or(Error::Own("Couldn't parse file.".into())));
            Ok(try!(String::from_utf8(data.to_owned())))
        }
        Err(err) => Err(err),
    }
}

pub fn expired_profiles(dir: &Path, date: DateTime<UTC>) -> Result<SearchInfo> {
    let entries: Vec<DirEntry> = try!(entries(dir)).collect();
    Ok(SearchInfo {
        total: entries.len(),
        profiles: parallel(entries, |profile| profile.expiration_date <= date),
    })
}

fn parallel<F>(entries: Vec<DirEntry>, f: F) -> Vec<Profile>
    where F: Fn(&Profile) -> bool + Sync
{
    let context = Context::new();
    collect(entries.into_par_iter()
                   .weight_max()
                   .filter_map(|entry| Profile::from_file(&entry.path(), &context).ok())
                   .filter(f))
}

fn collect<I>(par_iter: I) -> Vec<I::Item>
    where I: ParallelIterator
{
    let queue = crossbeam::sync::MsQueue::new();

    par_iter.for_each(|item| queue.push(item));

    let mut items = Vec::new();
    while let Some(item) = queue.try_pop() {
        items.push(item);
    }
    items
}

fn find_by_uuid(dir: &Path, uuid: &str) -> Result<Profile> {
    let entries: Vec<DirEntry> = try!(entries(dir)).collect();
    if let Some(profile) = parallel(entries, |profile| profile.uuid == uuid).pop() {
        Ok(profile)
    } else {
        Err(Error::Own(format!("Profile '{}' is not found.", uuid)))
    }
}

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

    #[test]
    fn filter_mobileprovision_files() {
        use tempdir::TempDir;
        use std::fs::File;

        let temp_dir = TempDir::new("test").unwrap();
        let result = entries(temp_dir.path()).map(|iter| iter.count());
        expect!(result).to(be_ok().value(0));

        File::create(temp_dir.path().join("1.mobileprovision")).unwrap();
        File::create(temp_dir.path().join("2.mobileprovision")).unwrap();
        File::create(temp_dir.path().join("3.txt")).unwrap();
        let result = entries(temp_dir.path()).map(|iter| iter.count());
        expect!(result).to(be_ok().value(2));
    }
}
<|endoftext|>


<commit_before>//! Fancy pure Rust crypto and hash library.
//!
//! The main reason this exists is so I can learn about cryptography.
//!
//! If you're asking "We have rust-crypto, why the hell do we need a new
//! library?"), `rust-crypto` was (at the time of Octavo's creation) big pile of… mess. To be honest
//! I doesn't hate `rust-crypto` but I wanted something that will be organized in fancy way, not
//! another OpenSSL (but written in Rust, so probably less buggy).
//!
//! Anther reason is that I want Octavo to became highly configurable via Cargo features. Each
//! cipher, hash family, MAC, etc. should be behind a feature.
//!
//! Oh… one more thing. I want to create C wrapper for Octavo (maybe even OpenSSL compatible), so
//! that you could use this beautiful peace of crap.
//!
//! Happy coding!
//!
//! ## Examples
//!
//!

#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(not(feature = "lints"), allow(unknown_lints))]

#![deny(unreachable_code, while_true)]
#![cfg_attr(not(test), deny(trivial_casts))]
#![warn(unused_qualifications, missing_docs)]

#[cfg(test)] extern crate quickcheck;
#[cfg(test)] extern crate openssl;

extern crate byteorder;
#[cfg(feature = "num")] extern crate num;
#[cfg(feature = "rand")] extern crate rand;

pub mod crypto;
pub mod digest;
pub mod mac;
pub mod kdf;

mod utils;
<commit_msg>fix(): Remove old lint<commit_after>//! Fancy pure Rust crypto and hash library.
//!
//! The main reason this exists is so I can learn about cryptography.
//!
//! If you're asking "We have rust-crypto, why the hell do we need a new
//! library?"), `rust-crypto` was (at the time of Octavo's creation) big pile of… mess. To be honest
//! I doesn't hate `rust-crypto` but I wanted something that will be organized in fancy way, not
//! another OpenSSL (but written in Rust, so probably less buggy).
//!
//! Anther reason is that I want Octavo to became highly configurable via Cargo features. Each
//! cipher, hash family, MAC, etc. should be behind a feature.
//!
//! Oh… one more thing. I want to create C wrapper for Octavo (maybe even OpenSSL compatible), so
//! that you could use this beautiful peace of crap.
//!
//! Happy coding!
//!
//! ## Examples
//!
//!

#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(not(feature = "lints"), allow(unknown_lints))]

#![deny(unreachable_code, while_true)]
#![cfg_attr(not(test), deny(trivial_casts))]
#![warn(missing_docs)]

#[cfg(test)] extern crate quickcheck;
#[cfg(test)] extern crate openssl;

extern crate byteorder;
#[cfg(feature = "num")] extern crate num;
#[cfg(feature = "rand")] extern crate rand;

pub mod crypto;
pub mod digest;
pub mod mac;
pub mod kdf;

mod utils;
<|endoftext|>


<commit_before>#![feature(core, collections)]

use std::fmt::{self, Debug, Formatter};

/// A data-structure for storing a sequence of 4-bit values.
///
/// Values are stored in a `Vec<u8>`, with two values per byte.
///
/// Values at even indices are stored in the most-significant half of their byte,
/// while values at odd indices are stored in the least-significant half.
///
/// Imagine a vector of MSB bytes, and you'll be right.
///
/// n = [_ _ | _ _ | _ _]
///
/// # Invariants
/// * If the length is odd, then the second half of the last byte must be 0.
pub struct NibbleVec {
    length: usize,
    data: Vec<u8>
}

impl NibbleVec {
    /// Create an empty nibble vector.
    pub fn new() -> NibbleVec {
        NibbleVec {
            length: 0,
            data: Vec::new()
        }
    }

    /// Create a nibble vector from a vector of bytes.
    ///
    /// Each byte is split into two 4-bit entries (MSB, LSB).
    pub fn from_byte_vec(vec: Vec<u8>) -> NibbleVec {
        let length = 2 * vec.len();
        NibbleVec {
            length: length,
            data: vec
        }
    }

    /// Get the number of elements stored in the vector.
    pub fn len(&self) -> usize {
        self.length
    }

    /// Fetch a single entry from the vector.
    ///
    /// Guaranteed to be a value in the interval [0, 15].
    ///
    /// **Panics** if `idx >= self.len()`.
    pub fn get(&self, idx: usize) -> u8 {
        if idx >= self.length {
            panic!("attempted access beyond vector end. len is {}, index is {}", self.length, idx);
        }
        let vec_idx = idx / 2;
        match idx % 2 {
            // If the index is even, take the first (most significant) half of the stored byte.
            0 => self.data[vec_idx] >> 4,
            // If the index is odd, take the second (least significant) half.
            _ => self.data[vec_idx] & 0x0F
        }
    }

    /// Add a single nibble to the vector.
    ///
    /// Only the 4 least-significant bits of the value are used.
    pub fn push(&mut self, val: u8) {
        if self.length % 2 == 0 {
            self.data.push(val << 4);
        } else {
            let vec_len = self.data.len();

            // Zero the second half of the last byte just to be safe.
            self.data[vec_len - 1] &= 0xF0;

            // Write the new value.
            self.data[vec_len - 1] |= val & 0x0F;
        }
        self.length += 1;
    }

    /// Split the vector into two parts.
    ///
    /// All elements at or following the given index are returned in a new `NibbleVec`,
    /// with exactly `idx` elements remaining in this vector.
    ///
    /// **Panics** if `idx > self.len()`.
    pub fn split(&mut self, idx: usize) -> NibbleVec {
        if idx > self.length {
            panic!("attempted to split past vector end. len is {}, index is {}", self.length, idx);
        } else if idx == self.length {
            NibbleVec::new()
        } else if idx % 2 == 0 {
            self.split_even(idx)
        } else {
            self.split_odd(idx)
        }
    }

    /// Split function for odd *indices*.
    #[inline(always)]
    fn split_odd(&mut self, idx: usize) -> NibbleVec {
        let tail_vec_size = (self.length - idx) / 2;
        let mut tail = NibbleVec::from_byte_vec(Vec::with_capacity(tail_vec_size));

        // Perform an overlap copy, copying the last nibble of the original vector only if
        // the length of the new tail is *odd*.
        let tail_length = self.length - idx;
        let take_last = tail_length % 2 == 1;
        self.overlap_copy(idx / 2, self.data.len(), &mut tail.data, &mut tail.length, take_last);

        // Remove the copied bytes, being careful to skip the idx byte.
        for _ in range(idx / 2 + 1, self.data.len()) {
            self.data.pop();
        }

        // Zero the second half of the index byte so as to maintain the last-nibble invariant.
        self.data[idx / 2] &= 0xF0;

        // Update the length of the first NibbleVec.
        self.length = idx;

        tail
    }

    /// Split function for even *indices*.
    #[inline(always)]
    fn split_even(&mut self, idx: usize) -> NibbleVec {
        // Avoid allocating a temporary vector by copying all the bytes in order, then popping them.

        // Possible to prove: l_d - ⌊i / 2⌋ = ⌊(l_v - i + 1) / 2⌋
        //  where l_d = self.data.len()
        //        l_v = self.length
        let tail_vec_size = (self.length - idx + 1) / 2;
        let mut tail = NibbleVec::from_byte_vec(Vec::with_capacity(tail_vec_size));

        // Copy the bytes.
        for i in range(idx / 2, self.data.len()) {
            tail.data.push(self.data[i]);
        }

        // Pop the same bytes.
        for _ in range(idx / 2, self.data.len()) {
            self.data.pop();
        }

        // Update lengths.
        tail.length = self.length - idx;
        self.length = idx;

        tail
    }

    /// Copy data between the second half of self.data[start] and
    /// self.data[end - 1]. The second half of the last entry is included
    /// if include_last is true.
    #[inline(always)]
    fn overlap_copy(&self, start: usize, end: usize, vec: &mut Vec<u8>, length: &mut usize, include_last: bool) {
        // Copy up to the first half of the last byte.
        for i in range(start, end - 1) {
            // The first half is the second half of the old entry.
            let first_half = self.data[i] & 0x0f;

            // The second half is the first half of the next entry.
            let second_half = self.data[i + 1] >> 4;

            vec.push((first_half << 4) | second_half);
            *length += 2;
        }

        if include_last {
            let last = self.data[end - 1] & 0x0f;
            vec.push(last << 4);
            *length += 1;
        }
    }

    /// Append another nibble vector.
    pub fn join(mut self, other: &NibbleVec) -> NibbleVec {
        // If the length is even, we can append directly.
        if self.length % 2 == 0 {
            self.length += other.length;
            self.data.push_all(other.data.as_slice());
            return self;
        }

        // If the other vector is empty, bail out.
        if other.len() == 0 {
            return self;
        }

        // If the length is odd, we have to perform an overlap copy.
        // Copy the first half of the first element, to make the vector an even length.
        self.push(other.get(0));

        // Copy the rest of the vector using an overlap copy.
        let take_last = other.len() % 2 == 0;
        other.overlap_copy(0, other.data.len(), &mut self.data, &mut self.length, take_last);

        self
    }
}

impl PartialEq<NibbleVec> for NibbleVec {
    fn eq(&self, other: &NibbleVec) -> bool {
        self.length == other.length &&
        self.data == other.data
    }
}

impl Eq for NibbleVec {}

impl PartialEq<[u8]> for NibbleVec {
    fn eq(&self, other: &[u8]) -> bool {
        if other.len() != self.len() {
            return false;
        }

        for (i, x) in other.iter().enumerate() {
            if self.get(i) != *x {
                return false;
            }
        }
        true
    }
}

impl Clone for NibbleVec {
    fn clone(&self) -> NibbleVec {
        NibbleVec {
            length: self.length,
            data: self.data.clone()
        }
    }
}

impl Debug for NibbleVec {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        try!(write!(fmt, "NibbleVec ["));

        if self.len() > 0 {
            try!(write!(fmt, "{}", self.get(0)));
        }

        for i in range(1, self.len()) {
            try!(write!(fmt, ", {}", self.get(i)));
        }
        write!(fmt, "]")
    }
}

#[cfg(test)]
mod test {
    use NibbleVec;

    fn v8_7_6_5() -> NibbleVec {
        NibbleVec::from_byte_vec(vec![8 << 4 | 7, 6 << 4 | 5])
    }

    fn v11_10_9() -> NibbleVec {
        let mut result = NibbleVec::from_byte_vec(vec![11 << 4 | 10]);
        result.push(9);
        result
    }

    #[test]
    fn get() {
        let nv = NibbleVec::from_byte_vec(vec![3 << 4 | 7]);
        assert_eq!(nv.get(0), 3u8);
        assert_eq!(nv.get(1), 7u8);
    }

    #[test]
    fn push() {
        let mut nv = NibbleVec::new();
        let data = vec![0, 1, 3, 5, 7, 9, 11, 15];
        for val in data.iter() {
            nv.push(*val);
        }

        for (i, val) in data.iter().enumerate() {
            assert_eq!(nv.get(i), *val);
        }
    }

    fn split_test(  nibble_vec: &NibbleVec,
                    idx: usize,
                    first: Vec<u8>,
                    second: Vec<u8>) {
        let mut init = nibble_vec.clone();
        let tail = init.split(idx);
        assert!(init == first[..]);
        assert!(tail == second[..]);
    }

    #[test]
    fn split_even_length() {
        let even_length = v8_7_6_5();
        split_test(&even_length, 0, vec![], vec![8, 7, 6, 5]);
        split_test(&even_length, 1, vec![8], vec![7, 6, 5]);
        split_test(&even_length, 2, vec![8, 7], vec![6, 5]);
        split_test(&even_length, 4, vec![8, 7, 6, 5], vec![]);
    }

    #[test]
    fn split_odd_length() {
        let odd_length = v11_10_9();
        split_test(&odd_length, 0, vec![], vec![11, 10, 9]);
        split_test(&odd_length, 1, vec![11], vec![10, 9]);
        split_test(&odd_length, 2, vec![11, 10], vec![9]);
        split_test(&odd_length, 3, vec![11, 10, 9], vec![]);
    }

    /// Join vec2 onto vec1 and ensure that the results matches the one expected.
    fn join_test(vec1: &NibbleVec, vec2: &NibbleVec, result: Vec<u8>) {
        let joined = vec1.clone().join(vec2);
        assert!(joined == result[..]);
    }

    #[test]
    fn join_even_length() {
        let v1 = v8_7_6_5();
        let v2 = v11_10_9();
        join_test(&v1, &v2, vec![8, 7, 6, 5, 11, 10, 9]);
        join_test(&v1, &v1, vec![8, 7, 6, 5, 8, 7, 6, 5]);
        join_test(&v1, &NibbleVec::new(), vec![8, 7, 6, 5]);
        join_test(&NibbleVec::new(), &v1, vec![8, 7, 6, 5]);
    }

    #[test]
    fn join_odd_length() {
        let v1 = v8_7_6_5();
        let v2 = v11_10_9();
        join_test(&v2, &v1, vec![11, 10, 9, 8, 7, 6, 5]);
        join_test(&v2, &v2, vec![11, 10, 9, 11, 10, 9]);
        join_test(&v2, &NibbleVec::new(), vec![11, 10, 9]);
    }

    /// Ensure that the last nibble is zeroed before reuse.
    #[test]
    fn memory_reuse() {
        let mut vec = NibbleVec::new();
        vec.push(10);
        vec.push(1);

        // Pushing.
        vec.split(1);
        vec.push(2);
        assert_eq!(vec.get(1), 2);

        // Joining.
        vec.split(1);
        vec = vec.join(&NibbleVec::from_byte_vec(vec![1 << 4 | 3, 5 << 4]));
        assert_eq!(vec.get(1), 1);
    }
}
<commit_msg>Improve documentation.<commit_after>#![feature(core, collections)]

use std::fmt::{self, Debug, Formatter};

/// A data-structure for storing a sequence of 4-bit values.
///
/// Values are stored in a `Vec<u8>`, with two values per byte.
///
/// Values at even indices are stored in the most-significant half of their byte,
/// while values at odd indices are stored in the least-significant half.
///
/// Imagine a vector of [MSB][msb-wiki] first bytes, and you'll be right.
///
/// n = [_ _ | _ _ | _ _]
///
/// [msb-wiki]: http://en.wikipedia.org/wiki/Most_significant_bit
pub struct NibbleVec {
    length: usize,
    data: Vec<u8>
}

impl NibbleVec {
    /// Create an empty nibble vector.
    pub fn new() -> NibbleVec {
        NibbleVec {
            length: 0,
            data: Vec::new()
        }
    }

    /// Create a nibble vector from a vector of bytes.
    ///
    /// Each byte is split into two 4-bit entries (MSB, LSB).
    pub fn from_byte_vec(vec: Vec<u8>) -> NibbleVec {
        let length = 2 * vec.len();
        NibbleVec {
            length: length,
            data: vec
        }
    }

    /// Get the number of elements stored in the vector.
    pub fn len(&self) -> usize {
        self.length
    }

    /// Fetch a single entry from the vector.
    ///
    /// Guaranteed to be a value in the interval [0, 15].
    ///
    /// **Panics** if `idx >= self.len()`.
    pub fn get(&self, idx: usize) -> u8 {
        if idx >= self.length {
            panic!("attempted access beyond vector end. len is {}, index is {}", self.length, idx);
        }
        let vec_idx = idx / 2;
        match idx % 2 {
            // If the index is even, take the first (most significant) half of the stored byte.
            0 => self.data[vec_idx] >> 4,
            // If the index is odd, take the second (least significant) half.
            _ => self.data[vec_idx] & 0x0F
        }
    }

    /// Add a single nibble to the vector.
    ///
    /// Only the 4 least-significant bits of the value are used.
    pub fn push(&mut self, val: u8) {
        if self.length % 2 == 0 {
            self.data.push(val << 4);
        } else {
            let vec_len = self.data.len();

            // Zero the second half of the last byte just to be safe.
            self.data[vec_len - 1] &= 0xF0;

            // Write the new value.
            self.data[vec_len - 1] |= val & 0x0F;
        }
        self.length += 1;
    }

    /// Split the vector into two parts.
    ///
    /// All elements at or following the given index are returned in a new `NibbleVec`,
    /// with exactly `idx` elements remaining in this vector.
    ///
    /// **Panics** if `idx > self.len()`.
    pub fn split(&mut self, idx: usize) -> NibbleVec {
        if idx > self.length {
            panic!("attempted to split past vector end. len is {}, index is {}", self.length, idx);
        } else if idx == self.length {
            NibbleVec::new()
        } else if idx % 2 == 0 {
            self.split_even(idx)
        } else {
            self.split_odd(idx)
        }
    }

    /// Split function for odd *indices*.
    #[inline(always)]
    fn split_odd(&mut self, idx: usize) -> NibbleVec {
        let tail_vec_size = (self.length - idx) / 2;
        let mut tail = NibbleVec::from_byte_vec(Vec::with_capacity(tail_vec_size));

        // Perform an overlap copy, copying the last nibble of the original vector only if
        // the length of the new tail is *odd*.
        let tail_length = self.length - idx;
        let take_last = tail_length % 2 == 1;
        self.overlap_copy(idx / 2, self.data.len(), &mut tail.data, &mut tail.length, take_last);

        // Remove the copied bytes, being careful to skip the idx byte.
        for _ in range(idx / 2 + 1, self.data.len()) {
            self.data.pop();
        }

        // Zero the second half of the index byte so as to maintain the last-nibble invariant.
        self.data[idx / 2] &= 0xF0;

        // Update the length of the first NibbleVec.
        self.length = idx;

        tail
    }

    /// Split function for even *indices*.
    #[inline(always)]
    fn split_even(&mut self, idx: usize) -> NibbleVec {
        // Avoid allocating a temporary vector by copying all the bytes in order, then popping them.

        // Possible to prove: l_d - ⌊i / 2⌋ = ⌊(l_v - i + 1) / 2⌋
        //  where l_d = self.data.len()
        //        l_v = self.length
        let tail_vec_size = (self.length - idx + 1) / 2;
        let mut tail = NibbleVec::from_byte_vec(Vec::with_capacity(tail_vec_size));

        // Copy the bytes.
        for i in range(idx / 2, self.data.len()) {
            tail.data.push(self.data[i]);
        }

        // Pop the same bytes.
        for _ in range(idx / 2, self.data.len()) {
            self.data.pop();
        }

        // Update lengths.
        tail.length = self.length - idx;
        self.length = idx;

        tail
    }

    /// Copy data between the second half of self.data[start] and
    /// self.data[end - 1]. The second half of the last entry is included
    /// if include_last is true.
    #[inline(always)]
    fn overlap_copy(&self, start: usize, end: usize, vec: &mut Vec<u8>, length: &mut usize, include_last: bool) {
        // Copy up to the first half of the last byte.
        for i in range(start, end - 1) {
            // The first half is the second half of the old entry.
            let first_half = self.data[i] & 0x0f;

            // The second half is the first half of the next entry.
            let second_half = self.data[i + 1] >> 4;

            vec.push((first_half << 4) | second_half);
            *length += 2;
        }

        if include_last {
            let last = self.data[end - 1] & 0x0f;
            vec.push(last << 4);
            *length += 1;
        }
    }

    /// Append another nibble vector whilst consuming this vector.
    pub fn join(mut self, other: &NibbleVec) -> NibbleVec {
        // If the length is even, we can append directly.
        if self.length % 2 == 0 {
            self.length += other.length;
            self.data.push_all(other.data.as_slice());
            return self;
        }

        // If the other vector is empty, bail out.
        if other.len() == 0 {
            return self;
        }

        // If the length is odd, we have to perform an overlap copy.
        // Copy the first half of the first element, to make the vector an even length.
        self.push(other.get(0));

        // Copy the rest of the vector using an overlap copy.
        let take_last = other.len() % 2 == 0;
        other.overlap_copy(0, other.data.len(), &mut self.data, &mut self.length, take_last);

        self
    }
}

impl PartialEq<NibbleVec> for NibbleVec {
    fn eq(&self, other: &NibbleVec) -> bool {
        self.length == other.length &&
        self.data == other.data
    }
}

impl Eq for NibbleVec {}

/// Compare a NibbleVec and a slice of bytes *element-by-element*.
/// Bytes are **not** interpreted as two NibbleVec entries.
impl PartialEq<[u8]> for NibbleVec {
    fn eq(&self, other: &[u8]) -> bool {
        if other.len() != self.len() {
            return false;
        }

        for (i, x) in other.iter().enumerate() {
            if self.get(i) != *x {
                return false;
            }
        }
        true
    }
}

impl Clone for NibbleVec {
    fn clone(&self) -> NibbleVec {
        NibbleVec {
            length: self.length,
            data: self.data.clone()
        }
    }
}

impl Debug for NibbleVec {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        try!(write!(fmt, "NibbleVec ["));

        if self.len() > 0 {
            try!(write!(fmt, "{}", self.get(0)));
        }

        for i in range(1, self.len()) {
            try!(write!(fmt, ", {}", self.get(i)));
        }
        write!(fmt, "]")
    }
}

#[cfg(test)]
mod test {
    use NibbleVec;

    fn v8_7_6_5() -> NibbleVec {
        NibbleVec::from_byte_vec(vec![8 << 4 | 7, 6 << 4 | 5])
    }

    fn v11_10_9() -> NibbleVec {
        let mut result = NibbleVec::from_byte_vec(vec![11 << 4 | 10]);
        result.push(9);
        result
    }

    #[test]
    fn get() {
        let nv = NibbleVec::from_byte_vec(vec![3 << 4 | 7]);
        assert_eq!(nv.get(0), 3u8);
        assert_eq!(nv.get(1), 7u8);
    }

    #[test]
    fn push() {
        let mut nv = NibbleVec::new();
        let data = vec![0, 1, 3, 5, 7, 9, 11, 15];
        for val in data.iter() {
            nv.push(*val);
        }

        for (i, val) in data.iter().enumerate() {
            assert_eq!(nv.get(i), *val);
        }
    }

    fn split_test(  nibble_vec: &NibbleVec,
                    idx: usize,
                    first: Vec<u8>,
                    second: Vec<u8>) {
        let mut init = nibble_vec.clone();
        let tail = init.split(idx);
        assert!(init == first[..]);
        assert!(tail == second[..]);
    }

    #[test]
    fn split_even_length() {
        let even_length = v8_7_6_5();
        split_test(&even_length, 0, vec![], vec![8, 7, 6, 5]);
        split_test(&even_length, 1, vec![8], vec![7, 6, 5]);
        split_test(&even_length, 2, vec![8, 7], vec![6, 5]);
        split_test(&even_length, 4, vec![8, 7, 6, 5], vec![]);
    }

    #[test]
    fn split_odd_length() {
        let odd_length = v11_10_9();
        split_test(&odd_length, 0, vec![], vec![11, 10, 9]);
        split_test(&odd_length, 1, vec![11], vec![10, 9]);
        split_test(&odd_length, 2, vec![11, 10], vec![9]);
        split_test(&odd_length, 3, vec![11, 10, 9], vec![]);
    }

    /// Join vec2 onto vec1 and ensure that the results matches the one expected.
    fn join_test(vec1: &NibbleVec, vec2: &NibbleVec, result: Vec<u8>) {
        let joined = vec1.clone().join(vec2);
        assert!(joined == result[..]);
    }

    #[test]
    fn join_even_length() {
        let v1 = v8_7_6_5();
        let v2 = v11_10_9();
        join_test(&v1, &v2, vec![8, 7, 6, 5, 11, 10, 9]);
        join_test(&v1, &v1, vec![8, 7, 6, 5, 8, 7, 6, 5]);
        join_test(&v1, &NibbleVec::new(), vec![8, 7, 6, 5]);
        join_test(&NibbleVec::new(), &v1, vec![8, 7, 6, 5]);
    }

    #[test]
    fn join_odd_length() {
        let v1 = v8_7_6_5();
        let v2 = v11_10_9();
        join_test(&v2, &v1, vec![11, 10, 9, 8, 7, 6, 5]);
        join_test(&v2, &v2, vec![11, 10, 9, 11, 10, 9]);
        join_test(&v2, &NibbleVec::new(), vec![11, 10, 9]);
    }

    /// Ensure that the last nibble is zeroed before reuse.
    #[test]
    fn memory_reuse() {
        let mut vec = NibbleVec::new();
        vec.push(10);
        vec.push(1);

        // Pushing.
        vec.split(1);
        vec.push(2);
        assert_eq!(vec.get(1), 2);

        // Joining.
        vec.split(1);
        vec = vec.join(&NibbleVec::from_byte_vec(vec![1 << 4 | 3, 5 << 4]));
        assert_eq!(vec.get(1), 1);
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Itoa Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::{io, mem, ptr, slice};

#[inline]
pub fn write<W: io::Write, V: Integer>(wr: &mut W, value: V) -> io::Result<()> {
    value.write(wr)
}

pub trait Integer {
    fn write<W: io::Write>(self, &mut W) -> io::Result<()>;
}

const DEC_DIGITS_LUT: &'static[u8] =
    b"0001020304050607080910111213141516171819\
      2021222324252627282930313233343536373839\
      4041424344454647484950515253545556575859\
      6061626364656667686970717273747576777879\
      8081828384858687888990919293949596979899";

// Adaptation of the original implementation at
// https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L188-L266
macro_rules! impl_Integer {
    ($($t:ident),* as $conv_fn:ident) => ($(
    impl Integer for $t {
        #[allow(unused_comparisons)]
        fn write<W: io::Write>(self, wr: &mut W) -> io::Result<()> {
            let is_nonnegative = self >= 0;
            let mut n = if is_nonnegative {
                self as $conv_fn
            } else {
                try!(wr.write_all(b"-"));
                // convert the negative num to positive by summing 1 to it's 2 complement
                (!(self as $conv_fn)).wrapping_add(1)
            };
            let mut buf: [u8; 20] = unsafe { mem::uninitialized() };
            let mut curr = buf.len() as isize;
            let buf_ptr = buf.as_mut_ptr();
            let lut_ptr = DEC_DIGITS_LUT.as_ptr();

            unsafe {
                // eagerly decode 4 characters at a time
                if <$t>::max_value() as u64 >= 10000 {
                    while n >= 10000 {
                        let rem = (n % 10000) as isize;
                        n /= 10000;

                        let d1 = (rem / 100) << 1;
                        let d2 = (rem % 100) << 1;
                        curr -= 4;
                        ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
                        ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
                    }
                }

                // if we reach here numbers are <= 9999, so at most 4 chars long
                let mut n = n as isize; // possibly reduce 64bit math

                // decode 2 more chars, if > 2 chars
                if n >= 100 {
                    let d1 = (n % 100) << 1;
                    n /= 100;
                    curr -= 2;
                    ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
                }

                // decode last 1 or 2 chars
                if n < 10 {
                    curr -= 1;
                    *buf_ptr.offset(curr) = (n as u8) + 48;
                } else {
                    let d1 = n << 1;
                    curr -= 2;
                    ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
                }
            }

            wr.write_all(unsafe {
                slice::from_raw_parts(buf_ptr.offset(curr), buf.len() - curr as usize)
            })
        }
    })*);
}

impl_Integer!(i8, u8, i16, u16, i32, u32 as u32);
impl_Integer!(i64, u64 as u64);
#[cfg(target_pointer_width = "16")]
impl_Integer!(isize, usize as u16);
#[cfg(target_pointer_width = "32")]
impl_Integer!(isize, usize as u32);
#[cfg(target_pointer_width = "64")]
impl_Integer!(isize, usize as u64);
<commit_msg>Accept references to trait objects<commit_after>// Copyright 2016 Itoa Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::{io, mem, ptr, slice};

#[inline]
pub fn write<W: io::Write + ?Sized, V: Integer>(wr: &mut W, value: V) -> io::Result<()> {
    value.write(wr)
}

pub trait Integer {
    fn write<W: io::Write + ?Sized>(self, &mut W) -> io::Result<()>;
}

const DEC_DIGITS_LUT: &'static[u8] =
    b"0001020304050607080910111213141516171819\
      2021222324252627282930313233343536373839\
      4041424344454647484950515253545556575859\
      6061626364656667686970717273747576777879\
      8081828384858687888990919293949596979899";

// Adaptation of the original implementation at
// https://github.com/rust-lang/rust/blob/b8214dc6c6fc20d0a660fb5700dca9ebf51ebe89/src/libcore/fmt/num.rs#L188-L266
macro_rules! impl_Integer {
    ($($t:ident),* as $conv_fn:ident) => ($(
    impl Integer for $t {
        #[allow(unused_comparisons)]
        fn write<W: io::Write + ?Sized>(self, wr: &mut W) -> io::Result<()> {
            let is_nonnegative = self >= 0;
            let mut n = if is_nonnegative {
                self as $conv_fn
            } else {
                try!(wr.write_all(b"-"));
                // convert the negative num to positive by summing 1 to it's 2 complement
                (!(self as $conv_fn)).wrapping_add(1)
            };
            let mut buf: [u8; 20] = unsafe { mem::uninitialized() };
            let mut curr = buf.len() as isize;
            let buf_ptr = buf.as_mut_ptr();
            let lut_ptr = DEC_DIGITS_LUT.as_ptr();

            unsafe {
                // eagerly decode 4 characters at a time
                if <$t>::max_value() as u64 >= 10000 {
                    while n >= 10000 {
                        let rem = (n % 10000) as isize;
                        n /= 10000;

                        let d1 = (rem / 100) << 1;
                        let d2 = (rem % 100) << 1;
                        curr -= 4;
                        ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
                        ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
                    }
                }

                // if we reach here numbers are <= 9999, so at most 4 chars long
                let mut n = n as isize; // possibly reduce 64bit math

                // decode 2 more chars, if > 2 chars
                if n >= 100 {
                    let d1 = (n % 100) << 1;
                    n /= 100;
                    curr -= 2;
                    ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
                }

                // decode last 1 or 2 chars
                if n < 10 {
                    curr -= 1;
                    *buf_ptr.offset(curr) = (n as u8) + 48;
                } else {
                    let d1 = n << 1;
                    curr -= 2;
                    ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
                }
            }

            wr.write_all(unsafe {
                slice::from_raw_parts(buf_ptr.offset(curr), buf.len() - curr as usize)
            })
        }
    })*);
}

impl_Integer!(i8, u8, i16, u16, i32, u32 as u32);
impl_Integer!(i64, u64 as u64);
#[cfg(target_pointer_width = "16")]
impl_Integer!(isize, usize as u16);
#[cfg(target_pointer_width = "32")]
impl_Integer!(isize, usize as u32);
#[cfg(target_pointer_width = "64")]
impl_Integer!(isize, usize as u64);
<|endoftext|>


<commit_before>mod common;

#[test]
#[cfg(feature = "devkit-arm-tests")]
pub fn test_mla() {
    let (cpu, _mem) = common::execute_arm(
        "mla",
        "
        ldr     r2, =0xFFFFFFF6
        mov     r3, #0x14
        ldr     r4, =0xD0
        mlas    r2, r3, r2, r4
        ",
    );
    assert!(!cpu.registers.getf_n());
    assert!(!cpu.registers.getf_z());
    assert_eq!(cpu.registers.read(2), 8);
}

#[test]
#[cfg(feature = "devkit-arm-tests")]
pub fn test_mul() {
    let (cpu, _mem) = common::execute_arm(
        "mul",
        "
        ldr     r2, =0xFFFFFFF6
        mov     r3, #0x14
        ldr     r4, =0xFFFFFF38
        muls    r2, r3, r2
        ",
    );
    assert!(cpu.registers.getf_n());
    assert!(!cpu.registers.getf_z());
    assert_eq!(cpu.registers.read(2), cpu.registers.read(4));
}

#[test]
#[cfg(feature = "devkit-arm-tests")]
pub fn test_umull() {
    let (cpu, _mem) = common::execute_arm(
        "umull",
        "
        ldr     r2, =0x80000000
        mov     r3, #8
        umulls  r4, r5, r2, r3
        ",
    );
    assert!(!cpu.registers.getf_n());
    assert!(cpu.registers.getf_z());
    assert_eq!(cpu.registers.read(5), 4);
}

#[test]
#[cfg(feature = "devkit-arm-tests")]
pub fn test_smull() {
    let (cpu, _mem) = common::execute_arm(
        "smull",
        "
        ldr     r2, =0x80000000
        mov     r3, #8
        smulls  r4, r5, r2, r3
        ",
    );
    assert!(cpu.registers.getf_n());
    assert!(!cpu.registers.getf_z());
    assert_eq!(cpu.registers.read(5), 0xFFFFFFFC);
}
<commit_msg>Fix bad ARM MUL test.<commit_after>mod common;

#[test]
#[cfg(feature = "devkit-arm-tests")]
pub fn test_mla() {
    let (cpu, _mem) = common::execute_arm(
        "mla",
        "
        ldr     r2, =0xFFFFFFF6
        mov     r3, #0x14
        ldr     r4, =0xD0
        mlas    r2, r3, r2, r4
        ",
    );
    assert!(!cpu.registers.getf_n());
    assert!(!cpu.registers.getf_z());
    assert_eq!(cpu.registers.read(2), 8);
}

#[test]
#[cfg(feature = "devkit-arm-tests")]
pub fn test_mul() {
    let (cpu, _mem) = common::execute_arm(
        "mul",
        "
        ldr     r2, =0xFFFFFFF6
        mov     r3, #0x14
        ldr     r4, =0xFFFFFF38
        muls    r2, r3, r2
        ",
    );
    assert!(cpu.registers.getf_n());
    assert!(!cpu.registers.getf_z());
    assert_eq!(cpu.registers.read(2), cpu.registers.read(4));
}

#[test]
#[cfg(feature = "devkit-arm-tests")]
pub fn test_umull() {
    let (cpu, _mem) = common::execute_arm(
        "umull",
        "
        ldr     r2, =0x80000000
        mov     r3, #8
        umulls  r4, r5, r2, r3
        ",
    );
    assert!(!cpu.registers.getf_n());
    assert!(!cpu.registers.getf_z());
    assert_eq!(cpu.registers.read(5), 4);
}

#[test]
#[cfg(feature = "devkit-arm-tests")]
pub fn test_smull() {
    let (cpu, _mem) = common::execute_arm(
        "smull",
        "
        ldr     r2, =0x80000000
        mov     r3, #8
        smulls  r4, r5, r2, r3
        ",
    );
    assert!(cpu.registers.getf_n());
    assert!(!cpu.registers.getf_z());
    assert_eq!(cpu.registers.read(5), 0xFFFFFFFC);
}
<|endoftext|>


<commit_before>extern crate ascii;

mod pascal_str;
mod pascal_string;

const PASCAL_STRING_BUF_SIZE: usize = 255;

pub use pascal_str::{Chars, CharsMut, PascalStr};
pub use pascal_string::{IntoChars, PascalString, PascalStringAppendError, PascalStringCreateError, AsciiError};

#[cfg(test)]
mod tests {
    use super::*;
    use ascii::*;
    use std::borrow::Cow;
    use std::ffi::{CStr, CString};

    #[test]
    fn test_string_creation() {
        let test = "Hello, my world!".to_owned();
        let test_pascal = PascalString::from(&test).unwrap();
        assert_eq!(&test, test_pascal.as_str());

        let too_many_bytes = vec![12u8; 256];
        assert!(match PascalString::from(&too_many_bytes) {
            Err(PascalStringCreateError::InputTooLong) => true,
            _ => false
        });
    }

    #[test]
    fn test_character_append() {
        let mut string = PascalString::new();
        assert!(string.try_push('h').is_ok());
        string.push('e');
        string.push(76u8);
        string.push('l');
        string.push(AsciiChar::L);
        string.push('o');
        string.push(AsciiChar::Null);

        assert_eq!(string.as_str(), "heLlLo\0");
    }

    #[test]
    fn test_string_append() {
        let mut string = PascalString::new();
        string.push_str("Hola, ");
        string.push_str("Senor!");
        assert_eq!(string.as_str(), "Hola, Senor!");
    }

    #[test]
    fn test_string_indexing_and_char_iteration() {
        {
            let string = PascalString::from("q").unwrap();
            assert_eq!(string[0u8], AsciiChar::q);
        }

        {
            let string2 = PascalString::from("WASD").unwrap();
            let mut iter = string2.chars();
            assert_eq!(iter.next(), Some(&AsciiChar::W));
            assert_eq!(iter.next(), Some(&AsciiChar::A));
            assert_eq!(iter.next(), Some(&AsciiChar::S));
            assert_eq!(iter.next(), Some(&AsciiChar::D));
        }
    }

    #[test]
    fn test_as_cstr() {
        {
            let msg = "I am your favourite cookie monster >:-)\0";
            let pstr = PascalString::from(&msg).unwrap();
            let cstr = CStr::from_bytes_with_nul(msg.as_bytes()).unwrap();
            let pstr_as_cstr = pstr.as_cstr().unwrap();
            assert!(match pstr_as_cstr {
                Cow::Borrowed(_) => true,
                _ => false
            });
            assert_eq!(&*pstr_as_cstr, cstr);
        }

        {
            let oversized = ['l'; 255];
            let string_oversized = {
                let mut s = String::new();
                for i in 0..oversized.len() {
                    s.push(oversized[i]);
                }
                s
            };
            let pstr_oversized = PascalString::from_fixed_ascii_array(255, oversized).unwrap();
            let cstr_from_pstr_oversized = pstr_oversized.as_cstr().unwrap();
            let cstr_from_string_oversized = CString::new(string_oversized).unwrap();
            assert!(match cstr_from_pstr_oversized {
                Cow::Owned(_) => true,
                _ => false
            });
            assert_eq!(cstr_from_pstr_oversized.into_owned(), cstr_from_string_oversized);
        }

        {
            let has_interior_null = "lol\0hi";
            let pstr = PascalString::from(&has_interior_null).unwrap();
            let err = match pstr.as_cstr() {
                Err(err) => err,
                _ => panic!("incorrect result")
            };
            assert_eq!(err.interior_null_index(), 3);
        }
    }
}
<commit_msg>Add initial crate-level doc comment<commit_after>#![warn(missing_docs)]

//! Pascal Strings in Rust.

extern crate ascii;

mod pascal_str;
mod pascal_string;

const PASCAL_STRING_BUF_SIZE: usize = 255;

pub use pascal_str::{Chars, CharsMut, PascalStr};
pub use pascal_string::{IntoChars, PascalString, PascalStringAppendError, PascalStringCreateError, AsciiError};

#[cfg(test)]
mod tests {
    use super::*;
    use ascii::*;
    use std::borrow::Cow;
    use std::ffi::{CStr, CString};

    #[test]
    fn test_string_creation() {
        let test = "Hello, my world!".to_owned();
        let test_pascal = PascalString::from(&test).unwrap();
        assert_eq!(&test, test_pascal.as_str());

        let too_many_bytes = vec![12u8; 256];
        assert!(match PascalString::from(&too_many_bytes) {
            Err(PascalStringCreateError::InputTooLong) => true,
            _ => false
        });
    }

    #[test]
    fn test_character_append() {
        let mut string = PascalString::new();
        assert!(string.try_push('h').is_ok());
        string.push('e');
        string.push(76u8);
        string.push('l');
        string.push(AsciiChar::L);
        string.push('o');
        string.push(AsciiChar::Null);

        assert_eq!(string.as_str(), "heLlLo\0");
    }

    #[test]
    fn test_string_append() {
        let mut string = PascalString::new();
        string.push_str("Hola, ");
        string.push_str("Senor!");
        assert_eq!(string.as_str(), "Hola, Senor!");
    }

    #[test]
    fn test_string_indexing_and_char_iteration() {
        {
            let string = PascalString::from("q").unwrap();
            assert_eq!(string[0u8], AsciiChar::q);
        }

        {
            let string2 = PascalString::from("WASD").unwrap();
            let mut iter = string2.chars();
            assert_eq!(iter.next(), Some(&AsciiChar::W));
            assert_eq!(iter.next(), Some(&AsciiChar::A));
            assert_eq!(iter.next(), Some(&AsciiChar::S));
            assert_eq!(iter.next(), Some(&AsciiChar::D));
        }
    }

    #[test]
    fn test_as_cstr() {
        {
            let msg = "I am your favourite cookie monster >:-)\0";
            let pstr = PascalString::from(&msg).unwrap();
            let cstr = CStr::from_bytes_with_nul(msg.as_bytes()).unwrap();
            let pstr_as_cstr = pstr.as_cstr().unwrap();
            assert!(match pstr_as_cstr {
                Cow::Borrowed(_) => true,
                _ => false
            });
            assert_eq!(&*pstr_as_cstr, cstr);
        }

        {
            let oversized = ['l'; 255];
            let string_oversized = {
                let mut s = String::new();
                for i in 0..oversized.len() {
                    s.push(oversized[i]);
                }
                s
            };
            let pstr_oversized = PascalString::from_fixed_ascii_array(255, oversized).unwrap();
            let cstr_from_pstr_oversized = pstr_oversized.as_cstr().unwrap();
            let cstr_from_string_oversized = CString::new(string_oversized).unwrap();
            assert!(match cstr_from_pstr_oversized {
                Cow::Owned(_) => true,
                _ => false
            });
            assert_eq!(cstr_from_pstr_oversized.into_owned(), cstr_from_string_oversized);
        }

        {
            let has_interior_null = "lol\0hi";
            let pstr = PascalString::from(&has_interior_null).unwrap();
            let err = match pstr.as_cstr() {
                Err(err) => err,
                _ => panic!("incorrect result")
            };
            assert_eq!(err.interior_null_index(), 3);
        }
    }
}
<|endoftext|>