<commit_before>#![crate_name="civet"]
#![crate_type="rlib"]
#![feature(unsafe_destructor)]

extern crate libc;
extern crate debug;
extern crate native;
extern crate collections;
extern crate semver;
extern crate conduit;

use std::io;
use std::io::net::ip::{IpAddr, Ipv4Addr};
use std::io::{IoResult, util, BufferedWriter};
use std::collections::HashMap;

use conduit::{Request, HeaderEntries, Handler, Extensions};

use raw::{RequestInfo,Header};
use raw::{get_header,get_headers,get_request_info};
use status::{ToStatusCode};

pub use raw::Config;

mod raw;
pub mod status;

pub struct Connection<'a> {
    request: CivetRequest<'a>,
    written: bool,
}

pub struct CivetRequest<'a> {
    conn: &'a raw::Connection,
    request_info: RequestInfo<'a>,
    headers: Headers<'a>,
    extensions: Extensions
}

fn ver(major: uint, minor: uint) -> semver::Version {
    semver::Version {
        major: major,
        minor: minor,
        patch: 0,
        pre: vec!(),
        build: vec!()
    }
}

impl<'a> conduit::Request for CivetRequest<'a> {
    fn http_version(&self) -> semver::Version {
        let version = self.request_info.http_version().unwrap();
        match version {
            "1.0" => ver(1, 0),
            "1.1" => ver(1, 1),
            _ => ver(1, 1)
        }
    }

    fn conduit_version(&self) -> semver::Version {
        ver(0, 1)
    }

    fn method(&self) -> conduit::Method {
        match self.request_info.method().unwrap() {
            "HEAD" => conduit::Head,
            "GET" => conduit::Get,
            "POST" => conduit::Post,
            "PUT" => conduit::Put,
            "DELETE" => conduit::Delete,
            "PATCH" => conduit::Patch,
            "PURGE" => conduit::Purge,
            "CONNECT" => conduit::Connect,
            "OPTIONS" => conduit::Options,
            "TRACE" => conduit::Trace,
            other @ _ => fail!("Civet does not support {} requests", other)
        }
    }

    fn scheme(&self) -> conduit::Scheme {
        if self.request_info.is_ssl() {
            conduit::Https
        } else {
            conduit::Http
        }
    }

    fn host<'a>(&'a self) -> conduit::Host<'a> {
        conduit::HostName(get_header(self.conn, "Host").unwrap())
    }

    fn virtual_root<'a>(&'a self) -> Option<&'a str> {
        None
    }

    fn path<'a>(&'a self) -> &'a str {
        self.request_info.url().unwrap()
    }

    fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.request_info.query_string()
    }

    fn remote_ip(&self) -> IpAddr {
        let ip = self.request_info.remote_ip();
        Ipv4Addr((ip >> 24) as u8,
                 (ip >> 16) as u8,
                 (ip >>  8) as u8,
                 (ip >>  0) as u8)
    }

    fn content_length(&self) -> Option<uint> {
        get_header(self.conn, "Content-Length").and_then(from_str)
    }

    fn headers<'a>(&'a self) -> &'a conduit::Headers {
        &self.headers as &conduit::Headers
    }

    fn body<'a>(&'a mut self) -> &'a mut Reader {
        self as &mut Reader
    }

    fn extensions<'a>(&'a self) -> &'a Extensions {
        &self.extensions
    }

    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
        &mut self.extensions
    }
}

pub fn response<S: ToStatusCode, R: Reader + Send>(status: S,
    headers: HashMap<String, Vec<String>>, body: R) -> conduit::Response
{
    conduit::Response {
        status: status.to_status().unwrap().to_code(),
        headers: headers,
        body: box body as Box<Reader + Send>
    }
}

impl<'a> Connection<'a> {
    fn new<'a>(conn: &'a raw::Connection) -> Result<Connection<'a>, String> {
        match request_info(conn) {
            Ok(info) => {
                let request = CivetRequest {
                    conn: conn,
                    request_info: info,
                    headers: Headers { conn: conn },
                    extensions: HashMap::new()
                };

                Ok(Connection {
                    request: request,
                    written: false,
                })
            },
            Err(err) => Err(err)
        }
    }

}

impl<'a> Writer for Connection<'a> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.written = true;
        write_bytes(self.request.conn, buf).map_err(|_| {
            io::standard_error(io::IoUnavailable)
        })
    }
}

impl<'a> Reader for CivetRequest<'a> {
    fn read(&mut self, buf: &mut[u8]) -> IoResult<uint> {
        let ret = raw::read(self.conn, buf);

        if ret == 0 {
            Err(io::standard_error(io::EndOfFile))
        } else {
            Ok(ret as uint)
        }
    }
}

#[unsafe_destructor]
impl<'a> Drop for Connection<'a> {
    fn drop(&mut self) {
        if !self.written {
            let _ = writeln!(self, "HTTP/1.1 500 Internal Server Error");
        }
    }
}

pub struct Headers<'a> {
    conn: &'a raw::Connection
}

impl<'a> conduit::Headers for Headers<'a> {
    fn find<'a>(&'a self, string: &str) -> Option<Vec<&'a str>> {
        get_header(self.conn, string).map(|s| vec!(s))
    }

    fn has(&self, string: &str) -> bool {
        get_header(self.conn, string).is_some()
    }

    fn iter<'a>(&'a self) -> conduit::HeaderEntries<'a> {
        box HeaderIterator::new(self.conn) as conduit::HeaderEntries<'a>
    }
}

pub struct HeaderIterator<'a> {
    headers: Vec<Header<'a>>,
    position: uint
}

impl<'a> HeaderIterator<'a> {
    fn new<'b>(conn: &'b raw::Connection) -> HeaderIterator<'b> {
        HeaderIterator { headers: get_headers(conn), position: 0 }
    }
}

impl<'a> Iterator<(&'a str, Vec<&'a str>)> for HeaderIterator<'a> {
    fn next(&mut self) -> Option<(&'a str, Vec<&'a str>)> {
        let pos = self.position;
        let headers = &self.headers;

        if self.headers.len() <= pos {
            None
        } else {
            let header = &headers[pos];
            self.position += 1;
            header.name().map(|name| (name, vec!(header.value().unwrap())))
        }
    }
}

pub struct Server(raw::Server<Box<Handler + 'static + Sync>>);

impl Server {
    pub fn start<H: Handler + 'static + Sync>(options: Config, handler: H)
        -> IoResult<Server>
    {
        fn internal_handler(conn: &mut raw::Connection,
                            handler: &Box<Handler>) -> Result<(), ()> {
            let mut connection = Connection::new(conn).unwrap();
            let response = handler.call(&mut connection.request);
            let mut writer = BufferedWriter::new(connection);

            fn err<W: Writer>(writer: &mut W) {
                let _ = writeln!(writer, "HTTP/1.1 500 Internal Server Error");
            }

            let conduit::Response { status, headers, mut body } = match response {
                Ok(r) => r,
                Err(_) => return Err(err(&mut writer)),
            };
            let (code, string) = status;
            try!(write!(&mut writer, "HTTP/1.1 {:u} {:s}\r\n", code, string).map_err(|_| ()));

            for (key, value) in headers.iter() {
                for header in value.iter() {
                    try!(write!(&mut writer, "{:s}: {:s}\r\n", *key, *header).map_err(|_| ()));
                }
            }

            try!(write!(&mut writer, "\r\n").map_err(|_| ()));
            let mut body: &mut Reader = body;
            try!(util::copy(&mut body, &mut writer).map_err(|_| ()));

            Ok(())
        }

        let raw_callback = raw::ServerCallback::new(internal_handler,
                                                    box handler);
        Ok(Server(try!(raw::Server::start(options, raw_callback))))
    }
}

fn write_bytes(connection: &raw::Connection, bytes: &[u8]) -> Result<(), String> {
    let ret = raw::write(connection, bytes);

    if ret == -1 {
        return Err("Couldn't write bytes to the connection".to_string())
    }

    Ok(())
}

fn request_info<'a>(connection: &'a raw::Connection)
    -> Result<RequestInfo<'a>, String>
{
    match get_request_info(connection) {
        Some(info) => Ok(info),
        None => Err("Couldn't get request info for connection".to_string())
    }
}

#[cfg(test)]
mod test {
    use std::collections::HashMap;
    use std::io::net::ip::SocketAddr;
    use std::io::net::tcp::TcpStream;
    use std::io::test::next_test_ip4;
    use std::io::{IoResult, MemReader};
    use std::fmt::Show;
    use std::sync::Mutex;
    use super::{Server, Config, response};
    use conduit::{Request, Response, Handler};

    fn noop(_: &mut Request) -> IoResult<Response> { unreachable!() }

    fn request(addr: SocketAddr, req: &str) -> String {
        let mut s = TcpStream::connect(addr.ip.to_string().as_slice(),
                                       addr.port).unwrap();
        s.write_str(req.trim_left()).unwrap();
        s.read_to_string().unwrap()
    }

    #[test]
    fn smoke() {
        let addr = next_test_ip4();
        Server::start(Config { port: addr.port, threads: 1 }, noop).unwrap();
    }

    #[test]
    fn dupe_port() {
        let addr = next_test_ip4();
        let s1 = Server::start(Config { port: addr.port, threads: 1 }, noop);
        assert!(s1.is_ok());
        let s2 = Server::start(Config { port: addr.port, threads: 1 }, noop);
        assert!(s2.is_err());
    }

    #[test]
    fn drops_handler() {
        static mut DROPPED: bool = false;
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show>> {
                fail!()
            }
        }
        impl Drop for Foo {
            fn drop(&mut self) { unsafe { DROPPED = true; } }
        }

        let addr = next_test_ip4();
        drop(Server::start(Config { port: addr.port, threads: 1 }, Foo));
        unsafe { assert!(DROPPED); }
    }

    #[test]
    fn invokes() {
        struct Foo(Mutex<Sender<()>>);
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show>> {
                let Foo(ref tx) = *self;
                tx.lock().send(());
                Ok(response(200i, HashMap::new(), MemReader::new(vec![])))
            }
        }

        let addr = next_test_ip4();
        let (tx, rx) = channel();
        let handler = Foo(Mutex::new(tx));
        let _s = Server::start(Config { port: addr.port, threads: 1 }, handler);
        request(addr, r"
GET / HTTP/1.1

");
        rx.recv();
    }

    #[test]
    fn header_sent() {
        struct Foo(Mutex<Sender<String>>);
        impl Handler for Foo {
            fn call(&self, req: &mut Request) -> Result<Response, Box<Show>> {
                let Foo(ref tx) = *self;
                tx.lock().send(req.headers().find("Foo").unwrap().connect(""));
                Ok(response(200i, HashMap::new(), MemReader::new(vec![])))
            }
        }

        let addr = next_test_ip4();
        let (tx, rx) = channel();
        let handler = Foo(Mutex::new(tx));
        let _s = Server::start(Config { port: addr.port, threads: 1 }, handler);
        request(addr, r"
GET / HTTP/1.1
Foo: bar

");
        assert_eq!(rx.recv().as_slice(), "bar");
    }

    #[test]
    fn failing_handler() {
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show>> {
                fail!()
            }
        }

        let addr = next_test_ip4();
        let _s = Server::start(Config { port: addr.port, threads: 1 }, Foo);
        request(addr, r"
GET / HTTP/1.1
Foo: bar

");
    }

    #[test]
    fn failing_handler_is_500() {
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show>> {
                fail!()
            }
        }

        let addr = next_test_ip4();
        let _s = Server::start(Config { port: addr.port, threads: 1 }, Foo);
        let response = request(addr, r"
GET / HTTP/1.1
Foo: bar

");
        assert!(response.as_slice().contains("500 Internal"),
                "not a failing response: {}", response);
    }
}
<commit_msg>Update to conduit master<commit_after>#![crate_name="civet"]
#![crate_type="rlib"]
#![feature(unsafe_destructor)]

extern crate libc;
extern crate debug;
extern crate native;
extern crate collections;
extern crate semver;
extern crate conduit;

use std::io;
use std::io::net::ip::{IpAddr, Ipv4Addr};
use std::io::{IoResult, util, BufferedWriter};
use std::collections::HashMap;

use conduit::{Request, HeaderEntries, Handler, Extensions, TypeMap};

use raw::{RequestInfo,Header};
use raw::{get_header,get_headers,get_request_info};
use status::{ToStatusCode};

pub use raw::Config;

mod raw;
pub mod status;

pub struct Connection<'a> {
    request: CivetRequest<'a>,
    written: bool,
}

pub struct CivetRequest<'a> {
    conn: &'a raw::Connection,
    request_info: RequestInfo<'a>,
    headers: Headers<'a>,
    extensions: Extensions
}

fn ver(major: uint, minor: uint) -> semver::Version {
    semver::Version {
        major: major,
        minor: minor,
        patch: 0,
        pre: vec!(),
        build: vec!()
    }
}

impl<'a> conduit::Request for CivetRequest<'a> {
    fn http_version(&self) -> semver::Version {
        let version = self.request_info.http_version().unwrap();
        match version {
            "1.0" => ver(1, 0),
            "1.1" => ver(1, 1),
            _ => ver(1, 1)
        }
    }

    fn conduit_version(&self) -> semver::Version {
        ver(0, 1)
    }

    fn method(&self) -> conduit::Method {
        match self.request_info.method().unwrap() {
            "HEAD" => conduit::Head,
            "GET" => conduit::Get,
            "POST" => conduit::Post,
            "PUT" => conduit::Put,
            "DELETE" => conduit::Delete,
            "PATCH" => conduit::Patch,
            "PURGE" => conduit::Purge,
            "CONNECT" => conduit::Connect,
            "OPTIONS" => conduit::Options,
            "TRACE" => conduit::Trace,
            other @ _ => fail!("Civet does not support {} requests", other)
        }
    }

    fn scheme(&self) -> conduit::Scheme {
        if self.request_info.is_ssl() {
            conduit::Https
        } else {
            conduit::Http
        }
    }

    fn host<'a>(&'a self) -> conduit::Host<'a> {
        conduit::HostName(get_header(self.conn, "Host").unwrap())
    }

    fn virtual_root<'a>(&'a self) -> Option<&'a str> {
        None
    }

    fn path<'a>(&'a self) -> &'a str {
        self.request_info.url().unwrap()
    }

    fn query_string<'a>(&'a self) -> Option<&'a str> {
        self.request_info.query_string()
    }

    fn remote_ip(&self) -> IpAddr {
        let ip = self.request_info.remote_ip();
        Ipv4Addr((ip >> 24) as u8,
                 (ip >> 16) as u8,
                 (ip >>  8) as u8,
                 (ip >>  0) as u8)
    }

    fn content_length(&self) -> Option<uint> {
        get_header(self.conn, "Content-Length").and_then(from_str)
    }

    fn headers<'a>(&'a self) -> &'a conduit::Headers {
        &self.headers as &conduit::Headers
    }

    fn body<'a>(&'a mut self) -> &'a mut Reader {
        self as &mut Reader
    }

    fn extensions<'a>(&'a self) -> &'a Extensions {
        &self.extensions
    }

    fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
        &mut self.extensions
    }
}

pub fn response<S: ToStatusCode, R: Reader + Send>(status: S,
    headers: HashMap<String, Vec<String>>, body: R) -> conduit::Response
{
    conduit::Response {
        status: status.to_status().unwrap().to_code(),
        headers: headers,
        body: box body as Box<Reader + Send>
    }
}

impl<'a> Connection<'a> {
    fn new<'a>(conn: &'a raw::Connection) -> Result<Connection<'a>, String> {
        match request_info(conn) {
            Ok(info) => {
                let request = CivetRequest {
                    conn: conn,
                    request_info: info,
                    headers: Headers { conn: conn },
                    extensions: TypeMap::new()
                };

                Ok(Connection {
                    request: request,
                    written: false,
                })
            },
            Err(err) => Err(err)
        }
    }

}

impl<'a> Writer for Connection<'a> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.written = true;
        write_bytes(self.request.conn, buf).map_err(|_| {
            io::standard_error(io::IoUnavailable)
        })
    }
}

impl<'a> Reader for CivetRequest<'a> {
    fn read(&mut self, buf: &mut[u8]) -> IoResult<uint> {
        let ret = raw::read(self.conn, buf);

        if ret == 0 {
            Err(io::standard_error(io::EndOfFile))
        } else {
            Ok(ret as uint)
        }
    }
}

#[unsafe_destructor]
impl<'a> Drop for Connection<'a> {
    fn drop(&mut self) {
        if !self.written {
            let _ = writeln!(self, "HTTP/1.1 500 Internal Server Error");
        }
    }
}

pub struct Headers<'a> {
    conn: &'a raw::Connection
}

impl<'a> conduit::Headers for Headers<'a> {
    fn find<'a>(&'a self, string: &str) -> Option<Vec<&'a str>> {
        get_header(self.conn, string).map(|s| vec!(s))
    }

    fn has(&self, string: &str) -> bool {
        get_header(self.conn, string).is_some()
    }

    fn iter<'a>(&'a self) -> conduit::HeaderEntries<'a> {
        box HeaderIterator::new(self.conn) as conduit::HeaderEntries<'a>
    }
}

pub struct HeaderIterator<'a> {
    headers: Vec<Header<'a>>,
    position: uint
}

impl<'a> HeaderIterator<'a> {
    fn new<'b>(conn: &'b raw::Connection) -> HeaderIterator<'b> {
        HeaderIterator { headers: get_headers(conn), position: 0 }
    }
}

impl<'a> Iterator<(&'a str, Vec<&'a str>)> for HeaderIterator<'a> {
    fn next(&mut self) -> Option<(&'a str, Vec<&'a str>)> {
        let pos = self.position;
        let headers = &self.headers;

        if self.headers.len() <= pos {
            None
        } else {
            let header = &headers[pos];
            self.position += 1;
            header.name().map(|name| (name, vec!(header.value().unwrap())))
        }
    }
}

pub struct Server(raw::Server<Box<Handler + 'static + Sync>>);

impl Server {
    pub fn start<H: Handler + 'static + Sync>(options: Config, handler: H)
        -> IoResult<Server>
    {
        fn internal_handler(conn: &mut raw::Connection,
                            handler: &Box<Handler>) -> Result<(), ()> {
            let mut connection = Connection::new(conn).unwrap();
            let response = handler.call(&mut connection.request);
            let mut writer = BufferedWriter::new(connection);

            fn err<W: Writer>(writer: &mut W) {
                let _ = writeln!(writer, "HTTP/1.1 500 Internal Server Error");
            }

            let conduit::Response { status, headers, mut body } = match response {
                Ok(r) => r,
                Err(_) => return Err(err(&mut writer)),
            };
            let (code, string) = status;
            try!(write!(&mut writer, "HTTP/1.1 {:u} {:s}\r\n", code, string).map_err(|_| ()));

            for (key, value) in headers.iter() {
                for header in value.iter() {
                    try!(write!(&mut writer, "{:s}: {:s}\r\n", *key, *header).map_err(|_| ()));
                }
            }

            try!(write!(&mut writer, "\r\n").map_err(|_| ()));
            let mut body: &mut Reader = body;
            try!(util::copy(&mut body, &mut writer).map_err(|_| ()));

            Ok(())
        }

        let raw_callback = raw::ServerCallback::new(internal_handler,
                                                    box handler);
        Ok(Server(try!(raw::Server::start(options, raw_callback))))
    }
}

fn write_bytes(connection: &raw::Connection, bytes: &[u8]) -> Result<(), String> {
    let ret = raw::write(connection, bytes);

    if ret == -1 {
        return Err("Couldn't write bytes to the connection".to_string())
    }

    Ok(())
}

fn request_info<'a>(connection: &'a raw::Connection)
    -> Result<RequestInfo<'a>, String>
{
    match get_request_info(connection) {
        Some(info) => Ok(info),
        None => Err("Couldn't get request info for connection".to_string())
    }
}

#[cfg(test)]
mod test {
    use std::collections::HashMap;
    use std::io::net::ip::SocketAddr;
    use std::io::net::tcp::TcpStream;
    use std::io::test::next_test_ip4;
    use std::io::{IoResult, MemReader};
    use std::fmt::Show;
    use std::sync::Mutex;
    use super::{Server, Config, response};
    use conduit::{Request, Response, Handler};

    fn noop(_: &mut Request) -> IoResult<Response> { unreachable!() }

    fn request(addr: SocketAddr, req: &str) -> String {
        let mut s = TcpStream::connect(addr.ip.to_string().as_slice(),
                                       addr.port).unwrap();
        s.write_str(req.trim_left()).unwrap();
        s.read_to_string().unwrap()
    }

    #[test]
    fn smoke() {
        let addr = next_test_ip4();
        Server::start(Config { port: addr.port, threads: 1 }, noop).unwrap();
    }

    #[test]
    fn dupe_port() {
        let addr = next_test_ip4();
        let s1 = Server::start(Config { port: addr.port, threads: 1 }, noop);
        assert!(s1.is_ok());
        let s2 = Server::start(Config { port: addr.port, threads: 1 }, noop);
        assert!(s2.is_err());
    }

    #[test]
    fn drops_handler() {
        static mut DROPPED: bool = false;
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show>> {
                fail!()
            }
        }
        impl Drop for Foo {
            fn drop(&mut self) { unsafe { DROPPED = true; } }
        }

        let addr = next_test_ip4();
        drop(Server::start(Config { port: addr.port, threads: 1 }, Foo));
        unsafe { assert!(DROPPED); }
    }

    #[test]
    fn invokes() {
        struct Foo(Mutex<Sender<()>>);
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show>> {
                let Foo(ref tx) = *self;
                tx.lock().send(());
                Ok(response(200i, HashMap::new(), MemReader::new(vec![])))
            }
        }

        let addr = next_test_ip4();
        let (tx, rx) = channel();
        let handler = Foo(Mutex::new(tx));
        let _s = Server::start(Config { port: addr.port, threads: 1 }, handler);
        request(addr, r"
GET / HTTP/1.1

");
        rx.recv();
    }

    #[test]
    fn header_sent() {
        struct Foo(Mutex<Sender<String>>);
        impl Handler for Foo {
            fn call(&self, req: &mut Request) -> Result<Response, Box<Show>> {
                let Foo(ref tx) = *self;
                tx.lock().send(req.headers().find("Foo").unwrap().connect(""));
                Ok(response(200i, HashMap::new(), MemReader::new(vec![])))
            }
        }

        let addr = next_test_ip4();
        let (tx, rx) = channel();
        let handler = Foo(Mutex::new(tx));
        let _s = Server::start(Config { port: addr.port, threads: 1 }, handler);
        request(addr, r"
GET / HTTP/1.1
Foo: bar

");
        assert_eq!(rx.recv().as_slice(), "bar");
    }

    #[test]
    fn failing_handler() {
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show>> {
                fail!()
            }
        }

        let addr = next_test_ip4();
        let _s = Server::start(Config { port: addr.port, threads: 1 }, Foo);
        request(addr, r"
GET / HTTP/1.1
Foo: bar

");
    }

    #[test]
    fn failing_handler_is_500() {
        struct Foo;
        impl Handler for Foo {
            fn call(&self, _req: &mut Request) -> Result<Response, Box<Show>> {
                fail!()
            }
        }

        let addr = next_test_ip4();
        let _s = Server::start(Config { port: addr.port, threads: 1 }, Foo);
        let response = request(addr, r"
GET / HTTP/1.1
Foo: bar

");
        assert!(response.as_slice().contains("500 Internal"),
                "not a failing response: {}", response);
    }
}
<|endoftext|>


<commit_before>mod ffi;

use std::os::raw::c_int;
use std::fmt::Display;

pub struct SoundIo {
    context: *mut ffi::Struct_SoundIo,
}
impl SoundIo {
    pub fn new() -> Self {
        SoundIo { context: unsafe { ffi::soundio_create() } }
    }

    pub fn channel_layout_builtin_count() -> i32 {
        let cnt = unsafe { ffi::soundio_channel_layout_builtin_count() };
        if cnt < 0 {
            panic!("Negative # of builtin channel layouts!")
        } else {
            cnt as i32
        }
    }

    pub fn connect(&self) -> Option<ffi::Enum_SoundIoError> {
        match unsafe { ffi::soundio_connect(self.context) } {
            ffi::Enum_SoundIoError::SoundIoErrorNone => None,
            err @ _ => Some(err),
        }
    }

    pub fn connect_backend(&self,
                           backend: ffi::Enum_SoundIoBackend)
                           -> Option<ffi::Enum_SoundIoError> {
        match unsafe { ffi::soundio_connect_backend(self.context, backend) } {
            ffi::Enum_SoundIoError::SoundIoErrorNone => None,
            err @ _ => {
                println!("{:?}", err);
                Some(err)
            }
        }
    }

    pub fn backend_count(&self) -> i32 {
        let cnt = unsafe { ffi::soundio_backend_count(self.context) } as i32;
        if cnt < 0 {
            panic!("Negative backend count!");
        } else {
            cnt
        }
    }

    pub fn get_backend(&self, idx: i32) -> Option<ffi::Enum_SoundIoBackend> {
        match unsafe { ffi::soundio_get_backend(self.context, idx) } {
            ffi::Enum_SoundIoBackend::SoundIoBackendNone => None,
            backend @ _ => Some(backend),
        }
    }

    pub fn have_backend(&self, backend: ffi::Enum_SoundIoBackend) -> bool {
        unsafe { ffi::soundio_have_backend(backend) == 1u8 }
    }

    pub fn flush_events(&self) {
        unsafe { ffi::soundio_flush_events(self.context) }
    }

    pub fn wait_events(&self) {
        unsafe { ffi::soundio_wait_events(self.context) }
    }

    pub fn wakeup(&self) {
        unsafe { ffi::soundio_wakeup(self.context) }
    }

    pub fn force_device_scan(&self) {
        unsafe { ffi::soundio_force_device_scan(self.context) }
    }

    pub fn disconnect(&self) {
        unsafe { ffi::soundio_disconnect(self.context) }
    }
}
impl Drop for SoundIo {
    fn drop(&mut self) {
        unsafe {
            self.disconnect();
            ffi::soundio_destroy(self.context)
        }
    }
}

#[derive(Debug)]
struct ChannelLayout {
    layout: *const ffi::Struct_SoundIoChannelLayout,
}
impl ChannelLayout {
    fn new(raw_layout: *const ffi::Struct_SoundIoChannelLayout) -> Self {
        ChannelLayout { layout: raw_layout }
    }

    pub fn get_builtin(idx: i32) -> Option<Self> {
        if 0 <= idx && idx < SoundIo::channel_layout_builtin_count() {
            Some(ChannelLayout::new(unsafe {
                ffi::soundio_channel_layout_get_builtin(idx as c_int)
            }))
        } else {
            None
        }
    }

    pub fn get_default(channel_count: i32) -> Option<Self> {
        if channel_count < 0 {
            None
        } else {
            Some(ChannelLayout::new(unsafe {
                ffi::soundio_channel_layout_get_default(channel_count as i32)
            }))
        }
    }

    pub fn find_channel(&self, channel: ffi::Enum_SoundIoChannelId) -> Option<i32> {
        match unsafe { ffi::soundio_channel_layout_find_channel(self.layout, channel) } {
            -1 => None,
            idx @ _ => Some(idx),
        }
    }

    pub fn detect_builtin(&mut self) -> bool {
        // This is a hack because of the transmute.
        unsafe {
            let mut_layout: *mut ffi::Struct_SoundIoChannelLayout =
                ::std::mem::transmute(self.layout);
            ffi::soundio_channel_layout_detect_builtin(mut_layout) == 1
        }
    }

    pub fn best_matching_channel_layout(preferred_layouts: &[ChannelLayout],
                                        available_layouts: &[ChannelLayout])
                                        -> Option<ChannelLayout> {
        // do some magic with the slices
        let raw_preferred_layouts: Vec<_> = preferred_layouts.iter()
                                                             .map(|l| unsafe { (*l.layout) })
                                                             .collect();
        let raw_available_layouts: Vec<_> = available_layouts.iter()
                                                             .map(|l| unsafe { (*l.layout) })
                                                             .collect();
        let layout_ptr = unsafe {
            ffi::soundio_best_matching_channel_layout(raw_preferred_layouts.as_ptr(),
                                                      preferred_layouts.len() as c_int,
                                                      raw_available_layouts.as_ptr(),
                                                      available_layouts.len() as c_int)
        };
        if layout_ptr.is_null() {
            None
        } else {
            Some(ChannelLayout::new(layout_ptr))
        }
    }
}
impl PartialEq for ChannelLayout {
    fn eq(&self, other: &Self) -> bool {
        unsafe { ffi::soundio_channel_layout_equal(self.layout, other.layout) == 1u8 }
    }

    fn ne(&self, other: &Self) -> bool {
        !self.eq(other)
    }
}
impl Display for ChannelLayout {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let str_ptr = unsafe { (*self.layout).name };
        write!(f, "{}", ffi::ptr_to_string(str_ptr).unwrap())
    }
}

#[test]
fn test_soundio() {
    let sio = SoundIo::new();
    assert!(sio.backend_count() > 0);
    assert!(sio.get_backend(0).is_some());
    assert!(sio.get_backend(-1).is_none());
    assert!(sio.connect().is_none());
    sio.disconnect();
    if sio.have_backend(ffi::Enum_SoundIoBackend::SoundIoBackendAlsa) {
        assert!(sio.connect_backend(ffi::Enum_SoundIoBackend::SoundIoBackendAlsa).is_none());
        sio.disconnect();
    }
    assert!(SoundIo::channel_layout_builtin_count() >= 0);
}

#[test]
fn test_channel_layout() {
    let cnt = SoundIo::channel_layout_builtin_count();
    assert!(cnt > 0);
    assert!(ChannelLayout::get_builtin(-1).is_none());
    assert_eq!(ChannelLayout::get_builtin(0), ChannelLayout::get_builtin(0));
    let mut layout = ChannelLayout::get_default(2).unwrap();
    assert!(layout.detect_builtin());
    assert!(layout.find_channel(ffi::Enum_SoundIoChannelId::SoundIoChannelIdFrontLeft).is_some());
    assert!(layout.find_channel(ffi::Enum_SoundIoChannelId::SoundIoChannelIdLfe2).is_none());
    assert!(cnt > 2);
    let preferred = [ChannelLayout::get_builtin(0).unwrap(),
                     ChannelLayout::get_builtin(1).unwrap()];
    let available = [ChannelLayout::get_builtin(1).unwrap(),
                     ChannelLayout::get_builtin(2).unwrap()];
    let best_match = ChannelLayout::best_matching_channel_layout(&preferred, &available);
    assert_eq!(ChannelLayout::get_builtin(1).unwrap(), best_match.unwrap());

}

#[test]
fn test_enums() {
    assert_eq!("(no error)",
               format!("{}", ffi::Enum_SoundIoError::SoundIoErrorNone));
    assert_eq!("ALSA",
               format!("{}", ffi::Enum_SoundIoBackend::SoundIoBackendAlsa));
    assert_eq!("Front Left",
               format!("{}", ffi::Enum_SoundIoChannelId::SoundIoChannelIdFrontLeft));
    assert_eq!(ffi::Enum_SoundIoChannelId::from("Front Left".to_string()),
               ffi::Enum_SoundIoChannelId::SoundIoChannelIdFrontLeft);
    assert!(ffi::Enum_SoundIoChannelId::from("SomeInvalidBoredom".to_string()) !=
            ffi::Enum_SoundIoChannelId::SoundIoChannelIdFrontLeft);
    assert_eq!("unsigned 8-bit", format!("{}", ffi::Enum_SoundIoFormat::SoundIoFormatU8));
    assert_eq!(1, ffi::Enum_SoundIoFormat::SoundIoFormatU8.get_bytes_per_sample());
    assert_eq!(4, ffi::Enum_SoundIoFormat::SoundIoFormatU32LE.get_bytes_per_sample());
}
<commit_msg>Implement `{in,out}put_device_count` for `SoundIo` struct<commit_after>mod ffi;

use std::os::raw::c_int;
use std::fmt::Display;

pub struct SoundIo {
    context: *mut ffi::Struct_SoundIo,
}
impl SoundIo {
    pub fn new() -> Self {
        SoundIo { context: unsafe { ffi::soundio_create() } }
    }

    pub fn channel_layout_builtin_count() -> i32 {
        let cnt = unsafe { ffi::soundio_channel_layout_builtin_count() };
        if cnt < 0 {
            panic!("Negative # of builtin channel layouts!")
        } else {
            cnt as i32
        }
    }

    pub fn connect(&self) -> Option<ffi::Enum_SoundIoError> {
        match unsafe { ffi::soundio_connect(self.context) } {
            ffi::Enum_SoundIoError::SoundIoErrorNone => None,
            err @ _ => Some(err),
        }
    }

    pub fn connect_backend(&self,
                           backend: ffi::Enum_SoundIoBackend)
                           -> Option<ffi::Enum_SoundIoError> {
        match unsafe { ffi::soundio_connect_backend(self.context, backend) } {
            ffi::Enum_SoundIoError::SoundIoErrorNone => None,
            err @ _ => {
                println!("{:?}", err);
                Some(err)
            }
        }
    }

    pub fn backend_count(&self) -> i32 {
        let cnt = unsafe { ffi::soundio_backend_count(self.context) } as i32;
        if cnt < 0 {
            panic!("Negative backend count!");
        } else {
            cnt
        }
    }

    pub fn get_backend(&self, idx: i32) -> Option<ffi::Enum_SoundIoBackend> {
        match unsafe { ffi::soundio_get_backend(self.context, idx) } {
            ffi::Enum_SoundIoBackend::SoundIoBackendNone => None,
            backend @ _ => Some(backend),
        }
    }

    pub fn have_backend(&self, backend: ffi::Enum_SoundIoBackend) -> bool {
        unsafe { ffi::soundio_have_backend(backend) == 1u8 }
    }

    pub fn flush_events(&self) {
        unsafe { ffi::soundio_flush_events(self.context) }
    }

    pub fn wait_events(&self) {
        unsafe { ffi::soundio_wait_events(self.context) }
    }

    pub fn wakeup(&self) {
        unsafe { ffi::soundio_wakeup(self.context) }
    }

    pub fn force_device_scan(&self) {
        unsafe { ffi::soundio_force_device_scan(self.context) }
    }

    pub fn disconnect(&self) {
        unsafe { ffi::soundio_disconnect(self.context) }
    }

    pub fn input_device_count(&self) -> Option<i32> {
        let cnt = unsafe { ffi::soundio_input_device_count(self.context) };
        if cnt < 0 {
            None
        } else {
            Some(cnt as i32)
        }
    }

    pub fn output_device_count(&self) -> Option<i32> {
        let cnt = unsafe { ffi::soundio_output_device_count(self.context) };
        if cnt < 0 {
            None
        } else {
            Some(cnt as i32)
        }
    }
}
impl Drop for SoundIo {
    fn drop(&mut self) {
        unsafe {
            self.disconnect();
            ffi::soundio_destroy(self.context)
        }
    }
}

#[derive(Debug)]
struct ChannelLayout {
    layout: *const ffi::Struct_SoundIoChannelLayout,
}
impl ChannelLayout {
    fn new(raw_layout: *const ffi::Struct_SoundIoChannelLayout) -> Self {
        ChannelLayout { layout: raw_layout }
    }

    pub fn get_builtin(idx: i32) -> Option<Self> {
        if 0 <= idx && idx < SoundIo::channel_layout_builtin_count() {
            Some(ChannelLayout::new(unsafe {
                ffi::soundio_channel_layout_get_builtin(idx as c_int)
            }))
        } else {
            None
        }
    }

    pub fn get_default(channel_count: i32) -> Option<Self> {
        if channel_count < 0 {
            None
        } else {
            Some(ChannelLayout::new(unsafe {
                ffi::soundio_channel_layout_get_default(channel_count as i32)
            }))
        }
    }

    pub fn find_channel(&self, channel: ffi::Enum_SoundIoChannelId) -> Option<i32> {
        match unsafe { ffi::soundio_channel_layout_find_channel(self.layout, channel) } {
            -1 => None,
            idx @ _ => Some(idx),
        }
    }

    pub fn detect_builtin(&mut self) -> bool {
        // This is a hack because of the transmute.
        unsafe {
            let mut_layout: *mut ffi::Struct_SoundIoChannelLayout =
                ::std::mem::transmute(self.layout);
            ffi::soundio_channel_layout_detect_builtin(mut_layout) == 1
        }
    }

    pub fn best_matching_channel_layout(preferred_layouts: &[ChannelLayout],
                                        available_layouts: &[ChannelLayout])
                                        -> Option<ChannelLayout> {
        // do some magic with the slices
        let raw_preferred_layouts: Vec<_> = preferred_layouts.iter()
                                                             .map(|l| unsafe { (*l.layout) })
                                                             .collect();
        let raw_available_layouts: Vec<_> = available_layouts.iter()
                                                             .map(|l| unsafe { (*l.layout) })
                                                             .collect();
        let layout_ptr = unsafe {
            ffi::soundio_best_matching_channel_layout(raw_preferred_layouts.as_ptr(),
                                                      preferred_layouts.len() as c_int,
                                                      raw_available_layouts.as_ptr(),
                                                      available_layouts.len() as c_int)
        };
        if layout_ptr.is_null() {
            None
        } else {
            Some(ChannelLayout::new(layout_ptr))
        }
    }
}
impl PartialEq for ChannelLayout {
    fn eq(&self, other: &Self) -> bool {
        unsafe { ffi::soundio_channel_layout_equal(self.layout, other.layout) == 1u8 }
    }

    fn ne(&self, other: &Self) -> bool {
        !self.eq(other)
    }
}
impl Display for ChannelLayout {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let str_ptr = unsafe { (*self.layout).name };
        write!(f, "{}", ffi::ptr_to_string(str_ptr).unwrap())
    }
}

#[test]
fn test_soundio() {
    let sio = SoundIo::new();
    assert!(sio.backend_count() > 0);
    assert!(sio.get_backend(0).is_some());
    assert!(sio.get_backend(-1).is_none());
    assert!(sio.connect().is_none());
    sio.disconnect();
    if sio.have_backend(ffi::Enum_SoundIoBackend::SoundIoBackendAlsa) {
        assert!(sio.connect_backend(ffi::Enum_SoundIoBackend::SoundIoBackendAlsa).is_none());
        sio.disconnect();
    }
    assert!(SoundIo::channel_layout_builtin_count() >= 0);
    assert!(sio.connect().is_none());
    sio.flush_events();
    assert!(sio.output_device_count().unwrap() > 0);
    assert!(sio.input_device_count().unwrap() > 0);
}

#[test]
fn test_channel_layout() {
    let cnt = SoundIo::channel_layout_builtin_count();
    assert!(cnt > 0);
    assert!(ChannelLayout::get_builtin(-1).is_none());
    assert_eq!(ChannelLayout::get_builtin(0), ChannelLayout::get_builtin(0));
    let mut layout = ChannelLayout::get_default(2).unwrap();
    assert!(layout.detect_builtin());
    assert!(layout.find_channel(ffi::Enum_SoundIoChannelId::SoundIoChannelIdFrontLeft).is_some());
    assert!(layout.find_channel(ffi::Enum_SoundIoChannelId::SoundIoChannelIdLfe2).is_none());
    assert!(cnt > 2);
    let preferred = [ChannelLayout::get_builtin(0).unwrap(),
                     ChannelLayout::get_builtin(1).unwrap()];
    let available = [ChannelLayout::get_builtin(1).unwrap(),
                     ChannelLayout::get_builtin(2).unwrap()];
    let best_match = ChannelLayout::best_matching_channel_layout(&preferred, &available);
    assert_eq!(ChannelLayout::get_builtin(1).unwrap(), best_match.unwrap());

}

#[test]
fn test_enums() {
    assert_eq!("(no error)",
               format!("{}", ffi::Enum_SoundIoError::SoundIoErrorNone));
    assert_eq!("ALSA",
               format!("{}", ffi::Enum_SoundIoBackend::SoundIoBackendAlsa));
    assert_eq!("Front Left",
               format!("{}", ffi::Enum_SoundIoChannelId::SoundIoChannelIdFrontLeft));
    assert_eq!(ffi::Enum_SoundIoChannelId::from("Front Left".to_string()),
               ffi::Enum_SoundIoChannelId::SoundIoChannelIdFrontLeft);
    assert!(ffi::Enum_SoundIoChannelId::from("SomeInvalidBoredom".to_string()) !=
            ffi::Enum_SoundIoChannelId::SoundIoChannelIdFrontLeft);
    assert_eq!("unsigned 8-bit", format!("{}", ffi::Enum_SoundIoFormat::SoundIoFormatU8));
    assert_eq!(1, ffi::Enum_SoundIoFormat::SoundIoFormatU8.get_bytes_per_sample());
    assert_eq!(4, ffi::Enum_SoundIoFormat::SoundIoFormatU32LE.get_bytes_per_sample());
}
<|endoftext|>


<commit_before>/* Copyright 2015 Jordan Miner
 *
 * Licensed under the MIT license <LICENSE or
 * http://opensource.org/licenses/MIT>. This file may not be copied,
 * modified, or distributed except according to those terms.
 */

#![feature(coerce_unsized)]

extern crate libc;
extern crate iup_sys;
extern crate kernel32;
extern crate winapi;
extern crate smallvec;

#[cfg(windows)]
fn get_thread_id() -> isize {
    use kernel32::GetCurrentThreadId;
    unsafe { GetCurrentThreadId() as isize }
}

macro_rules! impl_control_traits {
    ($control:ident) => {
        unsafe impl Control for ::$control {
            fn handle(&self) -> *mut Ihandle {
                assert!(!self.0.get().is_null(), "attempted to use destroyed control");
                ::check_thread();
                self.0.get()
            }
        }

        unsafe impl UnwrapHandle for ::$control {
            fn try_unwrap_handle(self) -> Result<*mut Ihandle, Self> {
                assert!(!self.0.get().is_null(), "attempted to use destroyed control");
                self.0.try_unwrap().map_err(|handle_rc| ::$control(handle_rc))
            }
        }
    };
}

#[macro_use]
mod callbacks;
#[macro_use]
mod containers;

mod control_prelude;

mod alarm_builder;
mod attributes;
mod button;
mod canvas;
mod frame;
mod label;
mod line_graph;
mod menu;
mod tabs;
mod text;
mod toggle;
mod dialog;
mod file_dlg;
mod handle_rc;
mod extra_refs;

pub use dialog::{Dialog, ShowCallbackToken, ShowState};
pub use file_dlg::{FileDlg, FileDialogType, FileExtFilter};
pub use alarm_builder::{AlarmResult, AlarmBuilder};
pub use button::Button;
pub use canvas::{Canvas};
pub use frame::Frame;
pub use label::Label;
pub use tabs::{Tabs, TabInfo};
pub use text::{Text, CaretArgs};
pub use toggle::Toggle;
pub use menu::{Menu, MenuSubitem, Item, Separator, Submenu};
pub use containers::{Container, Fill, Hbox, Vbox, NumDiv, GridBox};
pub use callbacks::{CallbackAction, Event, CanvasActionArgs};

// With this layout, you can glob import this module's contents but selectively import the
// above types if you want.
pub mod common_attrs_cbs {
    pub use attributes::{
        ActiveAttribute,
        CanFocusAttribute,
        Cursor,
        CursorAttribute,
        MinMaxSizeAttribute,
        ScrollbarAttribute,
        TipAttribute,
        TitleAttribute,
        VisibleAttribute,
    };
    pub use callbacks::{
        MenuCommonCallbacks,
        GetKillFocusCallbacks,
        EnterLeaveWindowCallbacks,
        ButtonArgs,
        ButtonCallback,
        ValueChangedCallback,
        CanvasActionArgs,
        MotionArgs,
        WheelArgs,
        CanvasCallbacks,
        ResizeCallback,
    };
}

use std::ptr;
use std::sync::atomic::{AtomicIsize, Ordering, ATOMIC_ISIZE_INIT};
use libc::{c_char, c_int};
use iup_sys::*;

// returns false if a panic is pending, but cannot be propagated because the main loop level is too high
fn propagate_panic() -> bool {
    if callbacks::is_panic_pending() && main_loop_level() > 0 {
        exit_loop();
        return false;
    }
    if let Some(payload) = callbacks::take_panic_payload() {
        // TODO: once a new nightly is released, use this
        //::std::panic::propagate(payload);
        panic!(payload.downcast_ref::<String>().unwrap_or(&String::new()).clone());
    }
    true
}

/// Executes the user interaction until `exit_loop` is called or the last visible dialog is hidden.
///
/// If you cascade many calls to `main_loop`, there must be a `exit_loop` call for each cascade
/// level, as hiding all dialogs will close only one level. Call `main_loop_level` to obtain the
/// current level.
///
/// If `main_loop` is called without any visible dialogs and no active timers, the application will
/// hang, and it will not be possible to close the main loop. The process will have to be
/// interrupted by the system.
///
/// When the last visible dialog is hidden, the `exit_loop` function is automatically called,
/// causing the `main_loop` to return. To avoid that, call `set_lock_loop(true)` before hiding the
/// last dialog.
pub fn main_loop() {
    unsafe {
        iup_open();

        // Callbacks can be called before main_loop() ever is. If they have been and have
        // panicked, we need to panic without calling IupMainLoop(). (IupMainLoopLevel() will
        // be 0 in a callback if it is running before IupMainLoop() has been called.)
        if !propagate_panic() { return; }
        IupMainLoop();
        propagate_panic();
    }
}

/// Returns the current cascade level of `main_loop`.
///
/// When no calls were done, return value is 0. Each time `main_loop` is called, the level
/// increases by one, and each time `main_loop` returns, the level decreases by one. You can use
/// this function to check if `main_loop` was already called and avoid calling it again.
///
/// A call to `Popup::popup` will increase the level by one.
pub fn main_loop_level() -> i32 {
    unsafe {
        IupMainLoopLevel()
    }
}

pub fn exit_loop() {
    unsafe {
        IupExitLoop();
    }
}

/// If this setting is set to false and the last visible dialog is closed, the `exit_loop`
/// function is called.
///
/// To avoid `exit_loop` being called, call `set_lock_loop(true)` before hiding the last dialog.
///
/// The default is false.
pub fn lock_loop() -> bool {
    unsafe {
        attributes::get_str_attribute_slice(ptr::null_mut(), "LOCKLOOP\0") == "YES"
    }
}

/// See `lock_loop`
pub fn set_lock_loop(lock: bool) {
    attributes::set_str_attribute(ptr::null_mut(), "LOCKLOOP\0", if lock { "YES\0" } else { "NO\0" });
}

fn iup_open() {
    check_thread();
    unsafe {
        if IupOpen(ptr::null_mut(), ptr::null_mut()) == IUP_OPENED {
            return;
        }
        attributes::set_str_attribute(ptr::null_mut(), "UTF8MODE", "YES");
        attributes::set_str_attribute(ptr::null_mut(), "UTF8MODE_FILE", "YES");
    }
}

static THREAD_ID: AtomicIsize = ATOMIC_ISIZE_INIT;

fn check_thread() {
    let thread_id = get_thread_id();
    let prev = THREAD_ID.compare_and_swap(0, thread_id, Ordering::SeqCst);
    assert!(prev == 0 || prev == thread_id, "IUP/Clear Coat functions must be called from a single thread");
}

// Part of the contract of implementing this trait is that no invalid handle
// is returned. Either the handle will stay valid for the life of the object or
// the method will panic.
pub unsafe trait Control {
    fn handle(&self) -> *mut Ihandle;

    /// Warning: Since children are stored as a linked list, detaching a control is O(n) where
    /// n is the number of siblings before this control.
    fn detach(&self) {
        unsafe { IupDetach(self.handle()); }
    }

    fn reparent(&self, new_parent: &Container, ref_child: Option<&Control>) -> Result<(), ()> {
        unsafe {
            let ref_child = ref_child.map(|c| c.handle()).unwrap_or(ptr::null_mut());
            if IupReparent(self.handle(), new_parent.handle(), ref_child) == IUP_NOERROR {
                Ok(())
            } else {
                Err(())
            }
        }
    }

    fn get_dialog(&self) -> Option<Dialog> {
        unsafe {
            let handle = IupGetDialog(self.handle());
            if handle == ptr::null_mut() {
                None
            } else {
                Some(Dialog::from_handle(handle))
            }
        }
    }

    /// Marks the control to be redrawn on a future main loop iteration.
    fn update(&self) {
        unsafe {
            IupUpdate(self.handle());
        }
    }

    /// Immediately redraws the control and, if `include_children` is `true`, its children as well
    /// (they will be redrawn before this method returns). Usually, it's better to use `update`
    /// because it will batch redraws together, avoiding unnecessary work.
    fn redraw(&self, include_children: bool) {
        unsafe {
            IupRedraw(self.handle(), if include_children { 1 } else { 0 });
        }
    }
}

// If this wrapper has the only reference, it gives up shared ownership of the *mut Ihandle.
pub unsafe trait UnwrapHandle : Sized {
    fn try_unwrap_handle(self) -> Result<*mut Ihandle, Self>;
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ScreenPosition { // This is the name IUP uses: SCREENPOSITION attribute
    Absolute(i32),
    Left,
    Right,
    Top,
    Bottom,
    Center,
    MousePos,
    CenterParent,
    Current,
}

impl ScreenPosition {
    #[allow(dead_code)]
    fn from_int_x(i: c_int) -> ScreenPosition {
       match i {
           IUP_LEFT => ScreenPosition::Left,
           IUP_RIGHT => ScreenPosition::Right,
           IUP_CENTER => ScreenPosition::Center,
           IUP_MOUSEPOS => ScreenPosition::MousePos,
           IUP_CENTERPARENT => ScreenPosition::CenterParent,
           IUP_CURRENT => ScreenPosition::Current,
           _ => ScreenPosition::Absolute(i),
       }
    }

    #[allow(dead_code)]
    fn from_int_y(i: c_int) -> ScreenPosition {
       match i {
           IUP_TOP => ScreenPosition::Top,
           IUP_BOTTOM => ScreenPosition::Bottom,
           _ => Self::from_int_x(i),
       }
    }

    fn to_int(self) -> c_int {
        match self {
            ScreenPosition::Absolute(i) => i,
            ScreenPosition::Left => IUP_LEFT,
            ScreenPosition::Right => IUP_RIGHT,
            ScreenPosition::Top => IUP_TOP,
            ScreenPosition::Bottom => IUP_BOTTOM,
            ScreenPosition::Center => IUP_CENTER,
            ScreenPosition::MousePos => IUP_MOUSEPOS,
            ScreenPosition::CenterParent => IUP_CENTERPARENT,
            ScreenPosition::Current => IUP_CURRENT,
        }
    }
}

pub trait Popup : Control {
    fn popup(&self, x: ScreenPosition, y: ScreenPosition) -> Result<(), ()> {
        unsafe {
            if IupPopup(self.handle(), x.to_int(), y.to_int()) == IUP_NOERROR {
                Ok(())
            } else {
                Err(())
            }
        }
    }
}

#[derive(Copy,Clone)]
pub enum MouseButton {
    Button1,
    Button2,
    Button3,
    Button4,
    Button5,
}

impl MouseButton {
    fn from_int(i: c_int) -> MouseButton {
        match i {
            IUP_BUTTON1 => MouseButton::Button1,
            IUP_BUTTON2 => MouseButton::Button2,
            IUP_BUTTON3 => MouseButton::Button3,
            IUP_BUTTON4 => MouseButton::Button4,
            IUP_BUTTON5 => MouseButton::Button5,
            _ => panic!("unknown mouse button"),
        }
    }

    #[allow(dead_code)]
    fn to_int(self) -> c_int {
        match self {
            MouseButton::Button1 => IUP_BUTTON1,
            MouseButton::Button2 => IUP_BUTTON2,
            MouseButton::Button3 => IUP_BUTTON3,
            MouseButton::Button4 => IUP_BUTTON4,
            MouseButton::Button5 => IUP_BUTTON5,
        }
    }
}

#[derive(Clone)]
pub struct KeyboardMouseStatus {
    shift_pressed: bool,
    control_pressed: bool,
    alt_pressed: bool,
    sys_pressed: bool,
    button1_pressed: bool,
    button2_pressed: bool,
    button3_pressed: bool,
    button4_pressed: bool,
    button5_pressed: bool,
}

impl KeyboardMouseStatus {
    unsafe fn from_cstr(s: *const c_char) -> KeyboardMouseStatus {
        KeyboardMouseStatus {
            shift_pressed: iup_isshift(s),
            control_pressed: iup_iscontrol(s),
            alt_pressed: iup_isalt(s),
            sys_pressed: iup_issys(s),
            button1_pressed: iup_isbutton1(s),
            button2_pressed: iup_isbutton2(s),
            button3_pressed: iup_isbutton3(s),
            button4_pressed: iup_isbutton4(s),
            button5_pressed: iup_isbutton5(s),
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum VAlignment {
    Top,
    Center,
    Bottom,
}

impl VAlignment {
    fn from_str(s: &[u8]) -> VAlignment {
        match s {
            b"ATOP" => VAlignment::Top,
            b"ACENTER" => VAlignment::Center,
            b"ABOTTOM" => VAlignment::Bottom,
            _ => panic!("unknown VAlignment"),
        }
    }

    fn to_str(self) -> &'static str {
        match self {
            VAlignment::Top => "ATOP",
            VAlignment::Center => "ACENTER",
            VAlignment::Bottom => "ABOTTOM",
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum HAlignment {
    Left,
    Center,
    Right,
}

impl HAlignment {
    fn from_str(s: &[u8]) -> HAlignment {
        match s {
            b"ALEFT" => HAlignment::Left,
            b"ACENTER" => HAlignment::Center,
            b"ARIGHT" => HAlignment::Right,
            _ => panic!("unknown HAlignment"),
        }
    }

    fn to_str(self) -> &'static str {
        match self {
            HAlignment::Left => "ALEFT",
            HAlignment::Center => "ACENTER",
            HAlignment::Right => "ARIGHT",
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Orientation {
    Horizontal,
    Vertical,
}

impl Orientation {
    fn from_str(s: &[u8]) -> Orientation {
        match s {
            b"HORIZONTAL" => Orientation::Horizontal,
            b"VERTICAL" => Orientation::Vertical,
            _ => panic!("unknown Orientation"),
        }
    }

    fn to_str(self) -> &'static str {
        match self {
            Orientation::Horizontal => "HORIZONTAL",
            Orientation::Vertical => "VERTICAL",
        }
    }
}
<commit_msg>Clean up imports and fix a compile error with Rust 1.18<commit_after>/* Copyright 2015 Jordan Miner
 *
 * Licensed under the MIT license <LICENSE or
 * http://opensource.org/licenses/MIT>. This file may not be copied,
 * modified, or distributed except according to those terms.
 */

#![feature(coerce_unsized)]

extern crate libc;
extern crate iup_sys;
extern crate kernel32;
extern crate winapi;
extern crate smallvec;

#[cfg(windows)]
fn get_thread_id() -> isize {
    use kernel32::GetCurrentThreadId;
    unsafe { GetCurrentThreadId() as isize }
}

macro_rules! impl_control_traits {
    ($control:ident) => {
        unsafe impl Control for ::$control {
            fn handle(&self) -> *mut Ihandle {
                assert!(!self.0.get().is_null(), "attempted to use destroyed control");
                ::check_thread();
                self.0.get()
            }
        }

        unsafe impl UnwrapHandle for ::$control {
            fn try_unwrap_handle(self) -> Result<*mut Ihandle, Self> {
                assert!(!self.0.get().is_null(), "attempted to use destroyed control");
                self.0.try_unwrap().map_err(|handle_rc| ::$control(handle_rc))
            }
        }
    };
}

#[macro_use]
mod callbacks;
#[macro_use]
mod containers;

mod control_prelude;

mod alarm_builder;
mod attributes;
mod button;
mod canvas;
mod frame;
mod label;
mod line_graph;
mod menu;
mod tabs;
mod text;
mod toggle;
mod dialog;
mod file_dlg;
mod handle_rc;
mod extra_refs;

pub use dialog::{Dialog, ShowCallbackToken, ShowState};
pub use file_dlg::{FileDlg, FileDialogType, FileExtFilter};
pub use alarm_builder::{AlarmResult, AlarmBuilder};
pub use button::Button;
pub use canvas::{Canvas};
pub use frame::Frame;
pub use label::Label;
pub use tabs::{Tabs, TabInfo};
pub use text::{Text, CaretArgs};
pub use toggle::Toggle;
pub use menu::{Menu, MenuSubitem, Item, Separator, Submenu};
pub use containers::{Container, Fill, Hbox, Vbox, NumDiv, GridBox};
pub use callbacks::{CallbackAction, Event, ButtonArgs, CanvasActionArgs};

// With this layout, you can glob import this module's contents but selectively import the
// above types if you want.
pub mod common_attrs_cbs {
    pub use attributes::{
        ActiveAttribute,
        CanFocusAttribute,
        Cursor,
        CursorAttribute,
        MinMaxSizeAttribute,
        ScrollbarAttribute,
        TipAttribute,
        TitleAttribute,
        VisibleAttribute,
    };
    pub use callbacks::{
        MenuCommonCallbacks,
        GetKillFocusCallbacks,
        EnterLeaveWindowCallbacks,
        ButtonCallback,
        ValueChangedCallback,
        MotionArgs,
        WheelArgs,
        CanvasCallbacks,
        ResizeCallback,
    };
}

use std::ptr;
use std::sync::atomic::{AtomicIsize, Ordering, ATOMIC_ISIZE_INIT};
use libc::{c_char, c_int};
use iup_sys::*;

// returns false if a panic is pending, but cannot be propagated because the main loop level is too high
fn propagate_panic() -> bool {
    if callbacks::is_panic_pending() && main_loop_level() > 0 {
        exit_loop();
        return false;
    }
    if let Some(payload) = callbacks::take_panic_payload() {
        // TODO: once a new nightly is released, use this
        //::std::panic::propagate(payload);
        panic!(payload.downcast_ref::<String>().unwrap_or(&String::new()).clone());
    }
    true
}

/// Executes the user interaction until `exit_loop` is called or the last visible dialog is hidden.
///
/// If you cascade many calls to `main_loop`, there must be a `exit_loop` call for each cascade
/// level, as hiding all dialogs will close only one level. Call `main_loop_level` to obtain the
/// current level.
///
/// If `main_loop` is called without any visible dialogs and no active timers, the application will
/// hang, and it will not be possible to close the main loop. The process will have to be
/// interrupted by the system.
///
/// When the last visible dialog is hidden, the `exit_loop` function is automatically called,
/// causing the `main_loop` to return. To avoid that, call `set_lock_loop(true)` before hiding the
/// last dialog.
pub fn main_loop() {
    unsafe {
        iup_open();

        // Callbacks can be called before main_loop() ever is. If they have been and have
        // panicked, we need to panic without calling IupMainLoop(). (IupMainLoopLevel() will
        // be 0 in a callback if it is running before IupMainLoop() has been called.)
        if !propagate_panic() { return; }
        IupMainLoop();
        propagate_panic();
    }
}

/// Returns the current cascade level of `main_loop`.
///
/// When no calls were done, return value is 0. Each time `main_loop` is called, the level
/// increases by one, and each time `main_loop` returns, the level decreases by one. You can use
/// this function to check if `main_loop` was already called and avoid calling it again.
///
/// A call to `Popup::popup` will increase the level by one.
pub fn main_loop_level() -> i32 {
    unsafe {
        IupMainLoopLevel()
    }
}

pub fn exit_loop() {
    unsafe {
        IupExitLoop();
    }
}

/// If this setting is set to false and the last visible dialog is closed, the `exit_loop`
/// function is called.
///
/// To avoid `exit_loop` being called, call `set_lock_loop(true)` before hiding the last dialog.
///
/// The default is false.
pub fn lock_loop() -> bool {
    unsafe {
        attributes::get_str_attribute_slice(ptr::null_mut(), "LOCKLOOP\0") == "YES"
    }
}

/// See `lock_loop`
pub fn set_lock_loop(lock: bool) {
    attributes::set_str_attribute(ptr::null_mut(), "LOCKLOOP\0", if lock { "YES\0" } else { "NO\0" });
}

fn iup_open() {
    check_thread();
    unsafe {
        if IupOpen(ptr::null_mut(), ptr::null_mut()) == IUP_OPENED {
            return;
        }
        attributes::set_str_attribute(ptr::null_mut(), "UTF8MODE", "YES");
        attributes::set_str_attribute(ptr::null_mut(), "UTF8MODE_FILE", "YES");
    }
}

static THREAD_ID: AtomicIsize = ATOMIC_ISIZE_INIT;

fn check_thread() {
    let thread_id = get_thread_id();
    let prev = THREAD_ID.compare_and_swap(0, thread_id, Ordering::SeqCst);
    assert!(prev == 0 || prev == thread_id, "IUP/Clear Coat functions must be called from a single thread");
}

// Part of the contract of implementing this trait is that no invalid handle
// is returned. Either the handle will stay valid for the life of the object or
// the method will panic.
pub unsafe trait Control {
    fn handle(&self) -> *mut Ihandle;

    /// Warning: Since children are stored as a linked list, detaching a control is O(n) where
    /// n is the number of siblings before this control.
    fn detach(&self) {
        unsafe { IupDetach(self.handle()); }
    }

    fn reparent(&self, new_parent: &Container, ref_child: Option<&Control>) -> Result<(), ()> {
        unsafe {
            let ref_child = ref_child.map(|c| c.handle()).unwrap_or(ptr::null_mut());
            if IupReparent(self.handle(), new_parent.handle(), ref_child) == IUP_NOERROR {
                Ok(())
            } else {
                Err(())
            }
        }
    }

    fn get_dialog(&self) -> Option<Dialog> {
        unsafe {
            let handle = IupGetDialog(self.handle());
            if handle == ptr::null_mut() {
                None
            } else {
                Some(Dialog::from_handle(handle))
            }
        }
    }

    /// Marks the control to be redrawn on a future main loop iteration.
    fn update(&self) {
        unsafe {
            IupUpdate(self.handle());
        }
    }

    /// Immediately redraws the control and, if `include_children` is `true`, its children as well
    /// (they will be redrawn before this method returns). Usually, it's better to use `update`
    /// because it will batch redraws together, avoiding unnecessary work.
    fn redraw(&self, include_children: bool) {
        unsafe {
            IupRedraw(self.handle(), if include_children { 1 } else { 0 });
        }
    }
}

// If this wrapper has the only reference, it gives up shared ownership of the *mut Ihandle.
pub unsafe trait UnwrapHandle : Sized {
    fn try_unwrap_handle(self) -> Result<*mut Ihandle, Self>;
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ScreenPosition { // This is the name IUP uses: SCREENPOSITION attribute
    Absolute(i32),
    Left,
    Right,
    Top,
    Bottom,
    Center,
    MousePos,
    CenterParent,
    Current,
}

impl ScreenPosition {
    #[allow(dead_code)]
    fn from_int_x(i: c_int) -> ScreenPosition {
       match i {
           IUP_LEFT => ScreenPosition::Left,
           IUP_RIGHT => ScreenPosition::Right,
           IUP_CENTER => ScreenPosition::Center,
           IUP_MOUSEPOS => ScreenPosition::MousePos,
           IUP_CENTERPARENT => ScreenPosition::CenterParent,
           IUP_CURRENT => ScreenPosition::Current,
           _ => ScreenPosition::Absolute(i),
       }
    }

    #[allow(dead_code)]
    fn from_int_y(i: c_int) -> ScreenPosition {
       match i {
           IUP_TOP => ScreenPosition::Top,
           IUP_BOTTOM => ScreenPosition::Bottom,
           _ => Self::from_int_x(i),
       }
    }

    fn to_int(self) -> c_int {
        match self {
            ScreenPosition::Absolute(i) => i,
            ScreenPosition::Left => IUP_LEFT,
            ScreenPosition::Right => IUP_RIGHT,
            ScreenPosition::Top => IUP_TOP,
            ScreenPosition::Bottom => IUP_BOTTOM,
            ScreenPosition::Center => IUP_CENTER,
            ScreenPosition::MousePos => IUP_MOUSEPOS,
            ScreenPosition::CenterParent => IUP_CENTERPARENT,
            ScreenPosition::Current => IUP_CURRENT,
        }
    }
}

pub trait Popup : Control {
    fn popup(&self, x: ScreenPosition, y: ScreenPosition) -> Result<(), ()> {
        unsafe {
            if IupPopup(self.handle(), x.to_int(), y.to_int()) == IUP_NOERROR {
                Ok(())
            } else {
                Err(())
            }
        }
    }
}

#[derive(Copy,Clone)]
pub enum MouseButton {
    Button1,
    Button2,
    Button3,
    Button4,
    Button5,
}

impl MouseButton {
    fn from_int(i: c_int) -> MouseButton {
        match i {
            IUP_BUTTON1 => MouseButton::Button1,
            IUP_BUTTON2 => MouseButton::Button2,
            IUP_BUTTON3 => MouseButton::Button3,
            IUP_BUTTON4 => MouseButton::Button4,
            IUP_BUTTON5 => MouseButton::Button5,
            _ => panic!("unknown mouse button"),
        }
    }

    #[allow(dead_code)]
    fn to_int(self) -> c_int {
        match self {
            MouseButton::Button1 => IUP_BUTTON1,
            MouseButton::Button2 => IUP_BUTTON2,
            MouseButton::Button3 => IUP_BUTTON3,
            MouseButton::Button4 => IUP_BUTTON4,
            MouseButton::Button5 => IUP_BUTTON5,
        }
    }
}

#[derive(Clone)]
pub struct KeyboardMouseStatus {
    shift_pressed: bool,
    control_pressed: bool,
    alt_pressed: bool,
    sys_pressed: bool,
    button1_pressed: bool,
    button2_pressed: bool,
    button3_pressed: bool,
    button4_pressed: bool,
    button5_pressed: bool,
}

impl KeyboardMouseStatus {
    unsafe fn from_cstr(s: *const c_char) -> KeyboardMouseStatus {
        KeyboardMouseStatus {
            shift_pressed: iup_isshift(s),
            control_pressed: iup_iscontrol(s),
            alt_pressed: iup_isalt(s),
            sys_pressed: iup_issys(s),
            button1_pressed: iup_isbutton1(s),
            button2_pressed: iup_isbutton2(s),
            button3_pressed: iup_isbutton3(s),
            button4_pressed: iup_isbutton4(s),
            button5_pressed: iup_isbutton5(s),
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum VAlignment {
    Top,
    Center,
    Bottom,
}

impl VAlignment {
    fn from_str(s: &[u8]) -> VAlignment {
        match s {
            b"ATOP" => VAlignment::Top,
            b"ACENTER" => VAlignment::Center,
            b"ABOTTOM" => VAlignment::Bottom,
            _ => panic!("unknown VAlignment"),
        }
    }

    fn to_str(self) -> &'static str {
        match self {
            VAlignment::Top => "ATOP",
            VAlignment::Center => "ACENTER",
            VAlignment::Bottom => "ABOTTOM",
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum HAlignment {
    Left,
    Center,
    Right,
}

impl HAlignment {
    fn from_str(s: &[u8]) -> HAlignment {
        match s {
            b"ALEFT" => HAlignment::Left,
            b"ACENTER" => HAlignment::Center,
            b"ARIGHT" => HAlignment::Right,
            _ => panic!("unknown HAlignment"),
        }
    }

    fn to_str(self) -> &'static str {
        match self {
            HAlignment::Left => "ALEFT",
            HAlignment::Center => "ACENTER",
            HAlignment::Right => "ARIGHT",
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Orientation {
    Horizontal,
    Vertical,
}

impl Orientation {
    fn from_str(s: &[u8]) -> Orientation {
        match s {
            b"HORIZONTAL" => Orientation::Horizontal,
            b"VERTICAL" => Orientation::Vertical,
            _ => panic!("unknown Orientation"),
        }
    }

    fn to_str(self) -> &'static str {
        match self {
            Orientation::Horizontal => "HORIZONTAL",
            Orientation::Vertical => "VERTICAL",
        }
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]
#![crate_type = "lib"]
#[allow(dead_code)]

use std::fmt;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::str::FromStr;

const IPV4_BITS: u8 = 32;
const IPV6_BITS: u8 = 128;

// A network
#[derive(Debug,Clone,Copy,Hash,PartialEq,Eq)]
pub enum IpNetwork {
    V4(Ipv4Network),
    V6(Ipv6Network),
}

#[derive(Debug,Clone,Copy,Hash,PartialEq,Eq)]
pub struct Ipv4Network {
    addr: Ipv4Addr,
    prefix: u8,
}

#[derive(Debug,Clone,Copy,Hash,PartialEq,Eq)]
pub struct Ipv6Network {
    addr: Ipv6Addr,
    prefix: u8,
}

#[derive(Debug,Clone,PartialEq,Eq)]
pub enum IpNetworkError {
    InvalidAddr(String),
    InvalidPrefix,
    InvalidCidrFormat(String),
}

pub struct Ipv4NetworkIterator {
    next: u64,
    end: u64,
}

impl Iterator for Ipv4NetworkIterator {
    type Item = Ipv4Addr;

    fn next(&mut self) -> Option<Ipv4Addr> {
        if self.next < self.end {
            let next = Ipv4Addr::from(self.next as u32);
            self.next += 1;
            Some(next)
        } else {
            None
        }
    }
}

impl Ipv4Network {
    /// Constructs a new `Ipv4Network` from any `Ipv4Addr` and a prefix denoting the network size.
    /// If the prefix is larger than 32 this will return an `IpNetworkError::InvalidPrefix`.
    pub fn new(addr: Ipv4Addr, prefix: u8) -> Result<Ipv4Network, IpNetworkError> {
        if prefix > IPV4_BITS {
            Err(IpNetworkError::InvalidPrefix)
        } else {
            Ok(Ipv4Network {
                addr: addr,
                prefix: prefix,
            })
        }
    }

    /// Returns an iterator over `Ipv4Network`. Each call to `next` will return the next
    /// `Ipv4Addr` in the given network. `None` will be returned when there are no more
    /// addresses.
    pub fn iter(&self) -> Ipv4NetworkIterator {
        let (_, start) = self.network();
        let end = start as u64 + self.size();
        Ipv4NetworkIterator {
            next: start as u64,
            end: end,
        }
    }

    pub fn from_cidr(cidr: &str) -> Result<Ipv4Network, IpNetworkError> {
        let (addr_str, prefix_str) = try!(cidr_parts(cidr));
        let addr = try!(Self::parse_addr(addr_str));
        let prefix = try!(parse_prefix(prefix_str, IPV4_BITS));
        Self::new(addr, prefix)
    }

    pub fn ip(&self) -> Ipv4Addr {
        self.addr
    }

    pub fn prefix(&self) -> u8 {
        self.prefix
    }

    pub fn mask(&self) -> (Ipv4Addr, u32) {
        let prefix = self.prefix;
        let mask = !(0xffffffff as u64 >> prefix) as u32;
        (Ipv4Addr::from(mask), mask)
    }

    pub fn network(&self) -> (Ipv4Addr, u32) {
        let (_, mask) = self.mask();
        let ip = u32::from(self.addr) & mask;
        (Ipv4Addr::from(ip), ip)
    }

    pub fn broadcast(&self) -> (Ipv4Addr, u32) {
        let (_, network) = self.network();
        let (_, mask) = self.mask();
        let broadcast = network | !mask;
        (Ipv4Addr::from(broadcast), broadcast)
    }

    pub fn contains(&self, ip: Ipv4Addr) -> bool {
        let (_, net) = self.network();
        let (_, mask) = self.mask();
        (u32::from(ip) & mask) == net
    }

    /// Returns number of possible host addresses in this `Ipv4Network`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::net::Ipv4Addr;
    /// use ipnetwork::Ipv4Network;
    ///
    /// let net = Ipv4Network::from_cidr("10.1.0.0/16").unwrap();
    /// assert_eq!(net.size(), 65536);
    ///
    /// let tinynet = Ipv4Network::from_cidr("0.0.0.0/32").unwrap();
    /// assert_eq!(tinynet.size(), 1);
    /// ```
    pub fn size(&self) -> u64 {
        let host_bits = (IPV4_BITS - self.prefix) as u32;
        (2 as u64).pow(host_bits)
    }

    /// Returns the `n`:th address within this network.
    /// The adresses are indexed from 0 and `n` must be smaller than the size of the network.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::net::Ipv4Addr;
    /// use ipnetwork::Ipv4Network;
    ///
    /// let net = Ipv4Network::from_cidr("192.168.0.0/24").unwrap();
    /// assert_eq!(net.nth(0).unwrap(), Ipv4Addr::new(192, 168, 0, 0));
    /// assert_eq!(net.nth(15).unwrap(), Ipv4Addr::new(192, 168, 0, 15));
    /// assert!(net.nth(256).is_none());
    ///
    /// let net2 = Ipv4Network::from_cidr("10.0.0.0/16").unwrap();
    /// assert_eq!(net2.nth(256).unwrap(), Ipv4Addr::new(10, 0, 1, 0));
    /// ```
    pub fn nth(&self, n: u32) -> Option<Ipv4Addr> {
        if (n as u64) < self.size() {
            let (_, net) = self.network();
            Some(Ipv4Addr::from(net + n))
        } else {
            None
        }
    }

    fn parse_addr(addr: &str) -> Result<Ipv4Addr, IpNetworkError> {
        let addr_parts = addr.split('.').map(|b| b.parse::<u8>());
        let mut bytes = [0; 4];
        for (i, byte) in addr_parts.enumerate() {
            if i >= 4 {
                return Err(IpNetworkError::InvalidAddr(format!("More than 4 bytes: {}", addr)));
            }
            bytes[i] = try!(byte.map_err(|_| {
                IpNetworkError::InvalidAddr(format!("All bytes not 0-255: {}", addr))
            }));
        }
        Ok(Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3]))
    }
}

impl Ipv6Network {
    /// Constructs a new `Ipv6Network` from any `Ipv6Addr` and a prefix denoting the network size.
    /// If the prefix is larger than 128 this will return an `IpNetworkError::InvalidPrefix`.
    pub fn new(addr: Ipv6Addr, prefix: u8) -> Result<Ipv6Network, IpNetworkError> {
        if prefix > IPV6_BITS {
            Err(IpNetworkError::InvalidPrefix)
        } else {
            Ok(Ipv6Network {
                addr: addr,
                prefix: prefix,
            })
        }
    }

    pub fn from_cidr(cidr: &str) -> Result<Ipv6Network, IpNetworkError> {
        let (addr_str, prefix_str) = try!(cidr_parts(cidr));
        let addr = try!(Ipv6Addr::from_str(addr_str)
                            .map_err(|_| IpNetworkError::InvalidAddr(format!("{}", addr_str))));
        let prefix = try!(parse_prefix(prefix_str, IPV6_BITS));
        Self::new(addr, prefix)
    }

    pub fn ip(&self) -> Ipv6Addr {
        self.addr
    }

    pub fn prefix(&self) -> u8 {
        self.prefix
    }
}

impl IpNetwork {
    pub fn new(ip: IpAddr, prefix: u8) -> Result<IpNetwork, IpNetworkError> {
        match ip {
            IpAddr::V4(a) => Ok(IpNetwork::V4(try!(Ipv4Network::new(a, prefix)))),
            IpAddr::V6(a) => Ok(IpNetwork::V6(try!(Ipv6Network::new(a, prefix)))),
        }
    }

    pub fn ip(&self) -> IpAddr {
        match *self {
            IpNetwork::V4(ref a) => IpAddr::V4(a.ip()),
            IpNetwork::V6(ref a) => IpAddr::V6(a.ip()),
        }
    }

    pub fn prefix(&self) -> u8 {
        match *self {
            IpNetwork::V4(ref a) => a.prefix(),
            IpNetwork::V6(ref a) => a.prefix(),
        }
    }
}

impl fmt::Display for Ipv4Network {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}/{}", self.ip(), self.prefix())
    }
}

impl fmt::Display for Ipv6Network {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}/{}", self.ip(), self.prefix())
    }
}

fn cidr_parts<'a>(cidr: &'a str) -> Result<(&'a str, &'a str), IpNetworkError> {
    let parts = cidr.split('/').collect::<Vec<&str>>();
    if parts.len() == 2 {
        Ok((parts[0], parts[1]))
    } else {
        Err(IpNetworkError::InvalidCidrFormat(format!("CIDR must contain '/': {}", cidr)))
    }
}

fn parse_prefix(prefix: &str, max: u8) -> Result<u8, IpNetworkError> {
    let mask = try!(prefix.parse::<u8>().map_err(|_| IpNetworkError::InvalidPrefix));
    if mask > max {
        Err(IpNetworkError::InvalidPrefix)
    } else {
        Ok(mask)
    }
}

#[cfg(test)]
mod test {
    use std::mem;
    use std::collections::HashMap;
    use std::net::{Ipv4Addr, Ipv6Addr};
    use super::*;

    #[test]
    fn create_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(77, 88, 21, 11), 24).unwrap();
        assert_eq!(cidr.prefix(), 24);
    }

    #[test]
    fn create_v4_invalid_prefix() {
        let net = Ipv4Network::new(Ipv4Addr::new(0, 0, 0, 0), 33);
        assert!(net.is_err());
    }

    #[test]
    fn parse_v4_0bit() {
        let cidr = Ipv4Network::from_cidr("0/0").unwrap();
        assert_eq!(cidr.ip(), Ipv4Addr::new(0, 0, 0, 0));
        assert_eq!(cidr.prefix(), 0);
    }

    #[test]
    fn parse_v4_24bit() {
        let cidr = Ipv4Network::from_cidr("127.1.0.0/24").unwrap();
        assert_eq!(cidr.ip(), Ipv4Addr::new(127, 1, 0, 0));
        assert_eq!(cidr.prefix(), 24);
    }

    #[test]
    fn parse_v4_32bit() {
        let cidr = Ipv4Network::from_cidr("127.0.0.0/32").unwrap();
        assert_eq!(cidr.ip(), Ipv4Addr::new(127, 0, 0, 0));
        assert_eq!(cidr.prefix(), 32);
    }

    #[test]
    fn parse_v4_fail_addr() {
        let cidr = Ipv4Network::from_cidr("10.a.b/8");
        assert!(cidr.is_err());
    }

    #[test]
    fn parse_v4_fail_addr2() {
        let cidr = Ipv4Network::from_cidr("10.1.1.1.0/8");
        assert!(cidr.is_err());
    }

    #[test]
    fn parse_v4_fail_addr3() {
        let cidr = Ipv4Network::from_cidr("256/8");
        assert!(cidr.is_err());
    }

    #[test]
    fn parse_v4_non_zero_host_bits() {
        let cidr = Ipv4Network::from_cidr("10.1.1.1/24").unwrap();
        assert_eq!(cidr.ip(), Ipv4Addr::new(10, 1, 1, 1));
        assert_eq!(cidr.prefix(), 24);
    }

    #[test]
    fn parse_v4_fail_prefix() {
        let cidr = Ipv4Network::from_cidr("0/39");
        assert!(cidr.is_err());
    }

    #[test]
    fn size_v4_24bit() {
        let net = Ipv4Network::from_cidr("0/24").unwrap();
        assert_eq!(net.size(), 256);
    }

    #[test]
    fn size_v4_1bit() {
        let net = Ipv4Network::from_cidr("0/31").unwrap();
        assert_eq!(net.size(), 2);
    }

    #[test]
    fn size_v4_max() {
        let net = Ipv4Network::from_cidr("0/0").unwrap();
        assert_eq!(net.size(), 4_294_967_296);
    }

    #[test]
    fn size_v4_min() {
        let net = Ipv4Network::from_cidr("0/32").unwrap();
        assert_eq!(net.size(), 1);
    }

    #[test]
    fn nth_v4() {
        let net = Ipv4Network::new(Ipv4Addr::new(127, 0, 0, 0), 24).unwrap();
        assert_eq!(net.nth(0).unwrap(), Ipv4Addr::new(127, 0, 0, 0));
        assert_eq!(net.nth(1).unwrap(), Ipv4Addr::new(127, 0, 0, 1));
        assert_eq!(net.nth(255).unwrap(), Ipv4Addr::new(127, 0, 0, 255));
        assert!(net.nth(256).is_none());
    }

    #[test]
    fn nth_v4_fail() {
        let net = Ipv4Network::new(Ipv4Addr::new(10, 0, 0, 0), 32).unwrap();
        assert!(net.nth(1).is_none());
    }

    #[test]
    fn hash_eq_compatibility_v4() {
        let mut map = HashMap::new();
        let net = Ipv4Network::new(Ipv4Addr::new(127, 0, 0, 1), 16).unwrap();
        map.insert(net, 137);
        let out = map.get(&net).unwrap();
        assert_eq!(137, *out);
    }

    #[test]
    fn copy_compatibility_v4() {
        let net = Ipv4Network::new(Ipv4Addr::new(127, 0, 0, 1), 16).unwrap();
        mem::drop(net);
        assert_eq!(16, net.prefix());
    }

    #[test]
    fn create_v6() {
        let cidr = Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 24).unwrap();
        assert_eq!(cidr.prefix(), 24);
    }

    #[test]
    fn create_v6_invalid_prefix() {
        let cidr = Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 129);
        assert!(cidr.is_err());
    }

    #[test]
    fn parse_v6() {
        let cidr = Ipv6Network::from_cidr("::1/0").unwrap();
        assert_eq!(cidr.ip(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
        assert_eq!(cidr.prefix(), 0);
    }

    #[test]
    fn parse_v6_2() {
        let cidr = Ipv6Network::from_cidr("FF01:0:0:17:0:0:0:2/64").unwrap();
        assert_eq!(cidr.ip(), Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2));
        assert_eq!(cidr.prefix(), 64);
    }

    #[test]
    fn parse_v6_fail_addr() {
        let cidr = Ipv6Network::from_cidr("2001::1::/8");
        assert!(cidr.is_err());
    }

    #[test]
    fn parse_v6_fail_prefix() {
        let cidr = Ipv6Network::from_cidr("::1/129");
        assert!(cidr.is_err());
    }

    #[test]
    fn mask_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(74, 125, 227, 0), 29).unwrap();
        let (ip, int) = cidr.mask();
        assert_eq!(ip, Ipv4Addr::new(255, 255, 255, 248));
        assert_eq!(int, 4294967288);
    }

    #[test]
    fn network_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(10, 10, 1, 97), 23).unwrap();
        let (ip, int) = cidr.network();
        assert_eq!(ip, Ipv4Addr::new(10, 10, 0, 0));
        assert_eq!(int, 168427520);
    }

    #[test]
    fn broadcast_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(10, 10, 1, 97), 23).unwrap();
        let (ip, int) = cidr.broadcast();
        assert_eq!(ip, Ipv4Addr::new(10, 10, 1, 255));
        assert_eq!(int, 168428031);
    }

    #[test]
    fn contains_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(74, 125, 227, 0), 25).unwrap();
        let ip = Ipv4Addr::new(74, 125, 227, 4);
        assert!(cidr.contains(ip));
    }

    #[test]
    fn not_contains_v4() {
        let cidr = Ipv4Network::new(Ipv4Addr::new(10, 0, 0, 50), 24).unwrap();
        let ip = Ipv4Addr::new(10, 1, 0, 1);
        assert!(!cidr.contains(ip));
    }

    #[test]
    fn iterator_v4() {
        let cidr = Ipv4Network::from_cidr("192.168.122.0/30").unwrap();
        let mut iter = cidr.iter();
        assert_eq!(Ipv4Addr::new(192, 168, 122, 0), iter.next().unwrap());
        assert_eq!(Ipv4Addr::new(192, 168, 122, 1), iter.next().unwrap());
        assert_eq!(Ipv4Addr::new(192, 168, 122, 2), iter.next().unwrap());
        assert_eq!(Ipv4Addr::new(192, 168, 122, 3), iter.next().unwrap());
        assert_eq!(None, iter.next());
    }

    #[test]
    fn iterator_v4_tiny() {
        let cidr = Ipv4Network::from_cidr("10/32").unwrap();
        let mut iter = cidr.iter();
        assert_eq!(Ipv4Addr::new(10, 0, 0, 0), iter.next().unwrap());
        assert_eq!(None, iter.next());
    }

    // Tests the entire IPv4 space to see if the iterator will stop at the correct place
    // and not overflow or wrap around. Ignored since it takes a long time to run.
    #[test]
    #[ignore]
    fn iterator_v4_huge() {
        let cidr = Ipv4Network::from_cidr("0/0").unwrap();
        let mut iter = cidr.iter();
        for i in 0..(u32::max_value() as u64 + 1) {
            assert_eq!(i as u32, u32::from(iter.next().unwrap()));
        }
        assert_eq!(None, iter.next());
    }
}
<commit_msg>Remove code from lib.rs and import from submodules<commit_after>#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]
#![crate_type = "lib"]
#[allow(dead_code)]

use std::net::IpAddr;

mod ipv4;
mod ipv6;
mod common;

pub use ipv4::Ipv4Network;
pub use ipv6::Ipv6Network;
pub use common::IpNetworkError;

// A network
#[derive(Debug,Clone,Copy,Hash,PartialEq,Eq)]
pub enum IpNetwork {
    V4(Ipv4Network),
    V6(Ipv6Network),
}

impl IpNetwork {
    pub fn new(ip: IpAddr, prefix: u8) -> Result<IpNetwork, IpNetworkError> {
        match ip {
            IpAddr::V4(a) => Ok(IpNetwork::V4(try!(Ipv4Network::new(a, prefix)))),
            IpAddr::V6(a) => Ok(IpNetwork::V6(try!(Ipv6Network::new(a, prefix)))),
        }
    }

    pub fn ip(&self) -> IpAddr {
        match *self {
            IpNetwork::V4(ref a) => IpAddr::V4(a.ip()),
            IpNetwork::V6(ref a) => IpAddr::V6(a.ip()),
        }
    }

    pub fn prefix(&self) -> u8 {
        match *self {
            IpNetwork::V4(ref a) => a.prefix(),
            IpNetwork::V6(ref a) => a.prefix(),
        }
    }
}
<|endoftext|>


<commit_before>extern crate rand;
use HaltCondition::{ Epochs, MSE };
use UpdateRule::{ Stochastic, Batch };
use std::iter::{Zip, Enumerate};
use std::slice;

#[test]
fn it_works() {
}

type Node = Vec<f64>;
type Layer = Vec<Node>;

#[derive(Debug)]
pub enum HaltCondition {
    Epochs(usize),
    MSE(f64),
}

#[derive(Debug)]
pub enum UpdateRule {
    Stochastic,
    Batch
}

#[derive(Debug)]
struct Trainer {
    rate: f64,
    momentum: f64,
    log_interval: Option<usize>,
    halt_condition: HaltCondition,
    update_rule: UpdateRule,
    threads: usize,
}

#[derive(Debug)]
#[derive(Clone)]
pub struct NN {
    layers: Vec<Layer>,
    num_inputs: usize,
}

impl NN {
    fn train(&self) -> Trainer {
        unimplemented!()
    }

    // returns a results with ok being the error rate of the network found at the end and
    // Err is a string with an explaination
    fn train_option(&mut self, examples: &[(&[f64], &[f64])], rate: f64, momentum: f64, log_interval: Option<usize>,
                    halt_condition: HaltCondition, update_rule: UpdateRule, threads: usize) -> Result<usize, &str> {

        let mut epochs = 0;
        let mut error_rate = 0.0;

        loop {

            let mut prev_deltas = make_weights_tracker(&self.layers, 0.0f64);
            let mut batch_data = make_weights_tracker(&self.layers, 0.0f64);
            let mut error_sum: f64 = 0.0;

            for &(inputs, targets) in examples.iter() {
                let results = do_run(self, inputs);
                let weight_updates = calculate_weight_update_info(self, &results, &targets);
                error_sum += calculate_error(&results, targets);
                match update_rule {
                    Batch => update_batch_data(&mut batch_data, &weight_updates),
                    Stochastic => update_weights(self, &weight_updates, &mut prev_deltas),
                }
            }

            // if we're in batch mode, update the weights now
            match update_rule {
                Batch => update_weights(self, &batch_data, &mut prev_deltas),
                Stochastic => (),
            }

            epochs += 1;

            // log error rate if neccessary
            match log_interval {
                Some(interval) if epochs % interval == 0 => {
                    println!("error rate: {}", error_rate);
                },
                _ => (),
            }

            // check if we've met the halt condition yet
            match halt_condition {
                Epochs(epochs_halt) => {
                    if epochs == epochs_halt { break; }
                },
                MSE(target_error) => {
                    if target_error == error_rate { break; }
                }
            }
        }

        unimplemented!();
    }

    fn run(&self, inputs: &[f64]) -> &[f64]{
        unimplemented!()
    }
}

fn do_run(nn: &NN, inputs: &[f64]) -> Vec<Vec<f64>>{
    unimplemented!()
}

fn update_batch_data(batch_data: &mut Vec<Vec<Vec<f64>>> , weight_updates: &Vec<Vec<Vec<f64>>>) {
    unimplemented!()
}

fn update_weights(nn: &mut NN, weight_updates: &Vec<Vec<Vec<f64>>>, prev_deltas: &mut Vec<Vec<Vec<f64>>>) {
    unimplemented!()
}

fn calculate_weight_update_info(nn: &NN, results: &Vec<Vec<f64>>, targets: &[f64]) -> Vec<Vec<Vec<f64>>> {
    let mut network_errors = Vec::new();
    let mut network_weight_updates = Vec::new();

    let mut next_layer_errors: Vec<f64> = Vec::new(); // TODO: find a way to not do this

    let layers = &nn.layers;
    let network_results = &results[1..]; // skip the input layer

    for (layer_index, (layer_nodes, layer_results)) in iterZipEnum(layers, network_results) {
        let prev_layer_results = &results[layer_index];
        let mut layer_errors = Vec::new();
        let mut layer_weight_updates = Vec::new();

        let next_layer_nodes: &Layer = &&layers[layer_index+1];

        for (node_index, (node, &result)) in iterZipEnum(layer_nodes, layer_results) {
            let mut node_weight_updates = Vec::new();
            let mut node_error = 0f64;

            // calculate error for this node
            if layer_index == layers.len() - 1 {
                node_error = result * (1f64 - result) * (targets[node_index] - result);
            } else {
                let mut sum = 0f64;
                for (next_node, &next_node_error_data) in next_layer_nodes.iter().zip(next_layer_errors.iter()) {
                    sum += next_node[node_index+1] * next_node_error_data; // +1 because the 0th weight is the threshold
                }
                node_error = result * (1f64 - result) * sum;
            }

            // calculate weight updates for this node
            for weight_index in 0..node.len() {
                let mut prev_layer_result = 1f64;
                if weight_index == 0 {
                    prev_layer_result = 1.0; // theshold
                } else {
                    prev_layer_result = prev_layer_results[weight_index-1];
                }
                let weight_update = node_error * prev_layer_result;
                node_weight_updates.push(weight_update);
            }

            layer_errors.push(node_error);
            layer_weight_updates.push(node_weight_updates);
        }

        next_layer_errors = layer_errors.clone();

        network_errors.push(layer_errors);
        network_weight_updates.push(layer_weight_updates);
    }

    // updates were build by backpropagation so reverse them
    network_weight_updates.reverse();

    network_weight_updates
}

fn iterZipEnum<'s, 't, S: 's, T: 't>(s: &'s [S], t: &'t [T]) ->
    Enumerate<Zip<slice::Iter<'s, S>, slice::Iter<'t, T>>>  {
    s.iter().zip(t.iter()).enumerate()
}

fn calculate_error(results: &Vec<Vec<f64>>, targets: &[f64]) -> f64 {
    unimplemented!()
}

fn make_weights_tracker<T: Clone>(layers: &Vec<Layer>, place_holder: T) -> Vec<Vec<Vec<T>>> {
    let mut network_level = Vec::new();
    for layer in layers.iter() {
        let mut layer_level = Vec::new();
        for node in layer.iter() {
            let mut node_level = Vec::new();
            for weight in node.iter() {
                node_level.push(place_holder.clone());
            }
            layer_level.push(node_level);
        }
        network_level.push(layer_level);
    }

    network_level
}

fn new_nn(layers_sizes: &[usize]) -> NN {
        if layers_sizes.len() < 2 {
            panic!("must have at least two layers");
        }
        let mut layers = Vec::new();
        let mut it = layers_sizes.iter();
        // get the first layer size
        let first_layer_size = *it.next().unwrap();

        // setup the rest of the layers
        let mut prev_layer_size = first_layer_size;
        for &layer_size in it {
            let mut layer: Layer = Vec::new();
            for _ in 0..layer_size {
                let mut node: Node = vec![rand::random(); prev_layer_size];
                node.shrink_to_fit();
                layer.push(node)
            }
            layer.shrink_to_fit();
            layers.push(layer);
            prev_layer_size = layer_size;
        }
        layers.shrink_to_fit();
        NN { layers: layers, num_inputs: first_layer_size }
    }<commit_msg>weight updating written<commit_after>extern crate rand;
use HaltCondition::{ Epochs, MSE };
use UpdateRule::{ Stochastic, Batch };
use std::iter::{Zip, Enumerate};
use std::slice;

#[test]
fn it_works() {
}

type Node = Vec<f64>;
type Layer = Vec<Node>;

#[derive(Debug)]
pub enum HaltCondition {
    Epochs(usize),
    MSE(f64),
}

#[derive(Debug)]
pub enum UpdateRule {
    Stochastic,
    Batch
}

#[derive(Debug)]
struct Trainer {
    rate: f64,
    momentum: f64,
    log_interval: Option<usize>,
    halt_condition: HaltCondition,
    update_rule: UpdateRule,
    threads: usize,
}

#[derive(Debug)]
#[derive(Clone)]
pub struct NN {
    layers: Vec<Layer>,
    num_inputs: usize,
}

impl NN {
    fn train(&self) -> Trainer {
        unimplemented!()
    }

    // returns a results with ok being the error rate of the network found at the end and
    // Err is a string with an explaination
    fn train_option(&mut self, examples: &[(&[f64], &[f64])], rate: f64, momentum: f64, log_interval: Option<usize>,
                    halt_condition: HaltCondition, update_rule: UpdateRule, threads: usize) -> Result<usize, &str> {

        let mut epochs = 0;
        let mut error_rate = 0.0;

        loop {

            let mut prev_deltas = make_weights_tracker(&self.layers, 0.0f64);
            let mut batch_data = make_weights_tracker(&self.layers, 0.0f64);
            let mut error_sum: f64 = 0.0;

            for &(inputs, targets) in examples.iter() {
                let results = do_run(self, inputs);
                let weight_updates = calculate_weight_update_info(self, &results, &targets);
                error_sum += calculate_error(&results, targets);
                match update_rule {
                    Batch => update_batch_data(&mut batch_data, &weight_updates),
                    Stochastic => update_weights(self, &weight_updates, &mut prev_deltas, rate, momentum),
                }
            }

            // if we're in batch mode, update the weights now
            match update_rule {
                Batch => update_weights(self, &batch_data, &mut prev_deltas, rate, momentum),
                Stochastic => (),
            }

            epochs += 1;

            // log error rate if neccessary
            match log_interval {
                Some(interval) if epochs % interval == 0 => {
                    println!("error rate: {}", error_rate);
                },
                _ => (),
            }

            // check if we've met the halt condition yet
            match halt_condition {
                Epochs(epochs_halt) => {
                    if epochs == epochs_halt { break; }
                },
                MSE(target_error) => {
                    if target_error == error_rate { break; }
                }
            }
        }

        unimplemented!();
    }

    fn run(&self, inputs: &[f64]) -> &[f64]{
        unimplemented!()
    }
}

fn do_run(nn: &NN, inputs: &[f64]) -> Vec<Vec<f64>>{
    unimplemented!()
}

fn update_batch_data(batch_data: &mut Vec<Vec<Vec<f64>>> , weight_updates: &Vec<Vec<Vec<f64>>>) {
    unimplemented!()
}

fn update_weights(nn: &mut NN, network_weight_updates: &Vec<Vec<Vec<f64>>>, prev_deltas: &mut Vec<Vec<Vec<f64>>>, rate: f64, momentum: f64) {
    for layer_index in 0..nn.layers.len() {
        let mut layer = &mut nn.layers[layer_index];
        let layer_weight_updates = &network_weight_updates[layer_index];
        for node_index in 0..layer.len() {
            let mut node = &mut layer[node_index];
            let node_weight_updates = &layer_weight_updates[node_index];
            for weight_index in 0..node.len() {
                let weight = node[weight_index];
                let weight_update = node_weight_updates[weight_index];
                let prev_delta = prev_deltas[layer_index][node_index][weight_index];
                let delta = (rate * weight_update) + (momentum * prev_delta);
                node[weight_index] += delta;
                prev_deltas[layer_index][node_index][weight_index] = delta;
            }
        }
    }
}

fn calculate_weight_update_info(nn: &NN, results: &Vec<Vec<f64>>, targets: &[f64]) -> Vec<Vec<Vec<f64>>> {
    let mut network_errors = Vec::new();
    let mut network_weight_updates = Vec::new();

    let mut next_layer_errors: Vec<f64> = Vec::new(); // TODO: find a way to not do this

    let layers = &nn.layers;
    let network_results = &results[1..]; // skip the input layer

    for (layer_index, (layer_nodes, layer_results)) in iterZipEnum(layers, network_results) {
        let prev_layer_results = &results[layer_index];
        let mut layer_errors = Vec::new();
        let mut layer_weight_updates = Vec::new();

        let next_layer_nodes: &Layer = &&layers[layer_index+1];

        for (node_index, (node, &result)) in iterZipEnum(layer_nodes, layer_results) {
            let mut node_weight_updates = Vec::new();
            let mut node_error = 0f64;

            // calculate error for this node
            if layer_index == layers.len() - 1 {
                node_error = result * (1f64 - result) * (targets[node_index] - result);
            } else {
                let mut sum = 0f64;
                for (next_node, &next_node_error_data) in next_layer_nodes.iter().zip(next_layer_errors.iter()) {
                    sum += next_node[node_index+1] * next_node_error_data; // +1 because the 0th weight is the threshold
                }
                node_error = result * (1f64 - result) * sum;
            }

            // calculate weight updates for this node
            for weight_index in 0..node.len() {
                let mut prev_layer_result = 1f64;
                if weight_index == 0 {
                    prev_layer_result = 1.0; // theshold
                } else {
                    prev_layer_result = prev_layer_results[weight_index-1];
                }
                let weight_update = node_error * prev_layer_result;
                node_weight_updates.push(weight_update);
            }

            layer_errors.push(node_error);
            layer_weight_updates.push(node_weight_updates);
        }

        next_layer_errors = layer_errors.clone();

        network_errors.push(layer_errors);
        network_weight_updates.push(layer_weight_updates);
    }

    // updates were build by backpropagation so reverse them
    network_weight_updates.reverse();

    network_weight_updates
}

fn iterZipEnum<'s, 't, S: 's, T: 't>(s: &'s [S], t: &'t [T]) ->
    Enumerate<Zip<slice::Iter<'s, S>, slice::Iter<'t, T>>>  {
    s.iter().zip(t.iter()).enumerate()
}

fn calculate_error(results: &Vec<Vec<f64>>, targets: &[f64]) -> f64 {
    unimplemented!()
}

fn make_weights_tracker<T: Clone>(layers: &Vec<Layer>, place_holder: T) -> Vec<Vec<Vec<T>>> {
    let mut network_level = Vec::new();
    for layer in layers.iter() {
        let mut layer_level = Vec::new();
        for node in layer.iter() {
            let mut node_level = Vec::new();
            for weight in node.iter() {
                node_level.push(place_holder.clone());
            }
            layer_level.push(node_level);
        }
        network_level.push(layer_level);
    }

    network_level
}

fn new_nn(layers_sizes: &[usize]) -> NN {
        if layers_sizes.len() < 2 {
            panic!("must have at least two layers");
        }
        let mut layers = Vec::new();
        let mut it = layers_sizes.iter();
        // get the first layer size
        let first_layer_size = *it.next().unwrap();

        // setup the rest of the layers
        let mut prev_layer_size = first_layer_size;
        for &layer_size in it {
            let mut layer: Layer = Vec::new();
            for _ in 0..layer_size {
                let mut node: Node = vec![rand::random(); prev_layer_size];
                node.shrink_to_fit();
                layer.push(node)
            }
            layer.shrink_to_fit();
            layers.push(layer);
            prev_layer_size = layer_size;
        }
        layers.shrink_to_fit();
        NN { layers: layers, num_inputs: first_layer_size }
    }<|endoftext|>