image-stream 0.1.0

Stream RgbImages
Documentation
use std::io::prelude::*;
use image::RgbImage;

use message::*;

#[derive(Debug)]
pub struct Server<S: Read + Write> {
    messenger: Messenger<S>,
    dimensions: (u32, u32)
}

impl<S: Read + Write> Server<S> {
    pub fn new(stream: S, dimensions: (u32, u32)) -> Result<Server<S>, String> {
        let messenger = Messenger::new(stream);
       
        match messenger.send(&Message::Dimensions(dimensions)) {
            Err(e) => return Err(e),
            Ok(len) => println!("sent {} bytes", len)
        };

        Ok(Server {
            messenger,
            dimensions
        })
    }

    pub fn recv(&self) -> Result<RgbImage, String> {
        let message = match self.messenger.recv() { 
            Ok(m) => m,
            Err(e) => return Err(e)
        };


        match message {
            Message::RgbImage(raw) => {
                let (width, height) = self.dimensions;
                match RgbImage::from_raw(width, height, raw) {
                    Some(image) => Ok(image),
                    None => Err("Couldn't deserialize RgbImage: Mismatched dimensions".to_string())
                }
            },
            _ => Err("Unexpected Message, expected ImageData".to_string())
        }
    }
}


#[cfg(test)]
mod tests {
    use std::net::{TcpStream, TcpListener};
    use std::time;
    use image::Rgb;
    use rand::random;

    use super::*;
    use client::Client;
    
    fn server_client(dimensions: (u32, u32)) -> (Server<TcpStream>, Client<TcpStream>) {
        let server_addr = "127.0.0.1:31415";
        let listener = TcpListener::bind(server_addr).unwrap();
        let client_stream = TcpStream::connect(server_addr).unwrap();
        let (server_stream, _client_addr) = listener.accept().unwrap();

        let server = Server::new(server_stream, dimensions.clone()).unwrap();
        let client = Client::new(client_stream).unwrap();

        (server, client)
    }

    #[test]
    fn dimensions() {
        let dimensions = (64, 32);
        let (_server, client) = server_client(dimensions);
        assert_eq!(dimensions, client.dimensions());

        let (_server, client) = server_client(dimensions);
        let dimensions = (65, 32);
        assert_ne!(dimensions, client.dimensions());
    }

    #[test]
    fn simple_image() {
        let (width, height) = (64, 32);
        let (server, client) = server_client((width, height));
        let image = RgbImage::from_fn(width, height, |x, y| {
            let (x, y) = (x as u8, y as u8);
            if x.wrapping_mul(y) % 5 == 0 {
                Rgb([x, y, x.wrapping_add(y)])
            }
            else {
                Rgb([255u8.wrapping_sub(y), 255u8.wrapping_sub(x.wrapping_mul(y)), x.wrapping_add(y)])
            }
        });
        client.send(image.clone()).unwrap();
        let recieved_image = server.recv().unwrap();
        assert_eq!(image.into_raw(), recieved_image.into_raw());
    }

    fn framerate(minimum: u8) {
        let (width, height) = (64, 32);
        let (server, client) = server_client((width, height));
        let test_duration = time::Duration::new(2, 0);
        let start = time::Instant::now();
        let mut frames = 0;

        let image = RgbImage::from_fn(width, height, |_, _| {
            Rgb([random::<u8>(), random::<u8>(), random::<u8>()])
        });
        let image_raw = image.clone().into_raw();

        while time::Instant::now() - start < test_duration {
            let t0 = time::Instant::now();
            for _ in 0..10 {
                client.send(image.clone()).unwrap();
            }
            let t1 = time::Instant::now();
            for _ in 0..10 {
                let recieved_image = server.recv().unwrap();
                assert_eq!(image_raw, recieved_image.into_raw());
            }
            let t2 = time::Instant::now();
            frames += 10;
            println!("send:   {:?}", t1 - t0);
            println!("recv:   {:?}", t2 - t1);
            println!("total : {:?}", t2 - t0);
            println!("===============");
        }

        let rate = (frames / test_duration.as_secs()) as u8;
        println!("Framerate: {}, minimum: {}", rate, minimum);
        assert!(rate >= minimum);
    }

    #[test]
    fn framerate_20() {
        framerate(20);
    }
    
    #[test]
    fn framerate_40() {
        framerate(40);
    }

    #[test]
    fn framerate_60() {
        framerate(60);
    }
}