<commit_before>//! The main entry point for the SpaceAPi server.
//!
//! Running this code starts a HTTP server instance. The default port is 3000, but you can set your
//! own favorite port by exporting the `PORT` environment variable.

extern crate rustc_serialize;
extern crate iron;
extern crate spaceapi;

mod utils;

use std::io::Write;
use std::net::Ipv4Addr;

use rustc_serialize::json::ToJson;
use iron::{Chain, Request, Response, IronResult, IronError, Iron};
use iron::status;

use spaceapi::datastore::DataStore;
use spaceapi::redis_store::RedisStore;
use spaceapi::Optional::{Value, Absent};

fn build_response_json(people_present: Option<u32>, raspi_temperature: Option<f32>) -> String {
    let people_present_sensor = match people_present {
        Some(count) => Value(vec![
            spaceapi::PeopleNowPresentSensor {
                value: count,
                location: Value("Hackerspace".to_string()),
                name: Absent,
                description: Absent,
                names: Absent,
            }
        ]),
        None => Absent,
    };

    let temperature_sensor = match raspi_temperature {
        Some(degrees) => Value(vec![
            spaceapi::TemperatureSensor {
                value: degrees,
                unit: "°C".to_string(),
                location: "Hackerspace".to_string(),
                name: Value("Raspberry CPU".to_string()),
                description: Absent,
            }
        ]),
        None => Absent,
    };

    let status = spaceapi::Status {

        // Hackerspace properties
        api: "0.13".to_string(),
        space: "coredump".to_string(),
        logo: "https://www.coredump.ch/logo.png".to_string(),
        url: "https://www.coredump.ch/".to_string(),
        location: spaceapi::Location {
            address: Value("Spinnereistrasse 2, 8640 Rapperswil, Switzerland".to_string()),
            lat: 47.22936,
            lon: 8.82949,
        },
        contact: spaceapi::Contact {
            irc: Value("irc://freenode.net/#coredump".to_string()),
            twitter: Value("@coredump_ch".to_string()),
            foursquare: Value("525c20e5498e875d8231b1e5".to_string()),
            email: Value("danilo@coredump.ch".to_string()),
        },

        // Hackerspace features / projects
        spacefed: Value(spaceapi::Spacefed {
            spacenet: false,
            spacesaml: false,
            spacephone: false,
        }),
        projects: Value(vec![
            "https://www.coredump.ch/projekte/".to_string(),
            "https://discourse.coredump.ch/c/projects".to_string(),
            "https://github.com/coredump-ch/".to_string(),
        ]),
        cam: Absent,
        feeds: Value(spaceapi::Feeds {
            blog: Value(spaceapi::Feed {
                _type: Value("rss".to_string()),
                url: "https://www.coredump.ch/feed/".to_string(),
            }),
            wiki: Absent,
            calendar: Absent,
            flickr: Absent,
        }),
        events: Absent,
        radio_show: Absent,

        // SpaceAPI internal usage
        cache: Value(spaceapi::Cache {
            schedule: "m.02".to_string(),
        }),
        issue_report_channels: vec![
            "email".to_string(),
            "twitter".to_string(),
        ],

        // Mutable data
        state: spaceapi::State {
            open: Some(false),
            message: Value("Open every Monday from 20:00".to_string()),
            lastchange: Absent,
            trigger_person: Absent,
            icon: Absent,
        },
        sensors: Value(spaceapi::Sensors {
            people_now_present: people_present_sensor,
            temperature: temperature_sensor,
        }),

    };
    status.to_json().to_string()
}

fn status_endpoint(_: &mut Request) -> IronResult<Response> {
    // Fetch data from datastore
    let datastore = RedisStore::new().unwrap();
    let people_present: Option<u32> = match datastore.retrieve("people_present") {
        Ok(v) => match v.parse::<u32>() {
            Ok(i) => Some(i),
            Err(_) => None,
        },
        Err(_) => None,
    };
    let raspi_temperature: Option<f32> = match datastore.retrieve("raspi_temperature") {
        Ok(v) => match v.parse::<f32>() {
            Ok(i) => Some(i),
            Err(_) => None,
        },
        Err(_) => None,
    };

    // Get response body
    let body = build_response_json(people_present, raspi_temperature);

    // Set headers
    // A new scope is used here because of the mutable borrow.
    /*
    {
        let mut headers = res.headers_mut();
        headers.set(header::ContentLength(body_bytes.len() as u64));
        headers.set(header::ContentType("application/json; charset=utf-8".parse().unwrap()));
        headers.set(header::CacheControl(vec![header::CacheDirective::NoCache]));
        headers.set(header::AccessControlAllowOrigin::Any);
    }
    */

    // Write response body
    Ok(Response::with((status::Ok, body)))
}

pub struct SpaceapiServer {
    host: Ipv4Addr,
    port: u16,
    status: spaceapi::Status,
}

impl SpaceapiServer {

    pub fn new(host: Ipv4Addr, status: spaceapi::Status) -> SpaceapiServer {
        SpaceapiServer {
            host: host,
            port: utils::get_port(),
            status: status,
        }
    }

    pub fn serve(&self) {
        println!("Starting HTTP server on {}:{}...", self.host, self.port);
        Iron::new(status_endpoint).http((self.host, self.port)).unwrap();
    }

}

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

    #[test]
    /// Verify that the response JSON looks OK.
    fn verify_response_json() {
        let people_present = Some(23);
        let temperature = Some(42.5);
        let json = build_response_json(people_present, temperature);
        assert_eq!(json, "{\
            \"api\":\"0.13\",\
            \"cache\":{\"schedule\":\"m.02\"},\
            \"contact\":{\
                \"email\":\"danilo@coredump.ch\",\
                \"foursquare\":\"525c20e5498e875d8231b1e5\",\
                \"irc\":\"irc://freenode.net/#coredump\",\
                \"twitter\":\"@coredump_ch\"\
            },\
            \"feeds\":{\
                \"blog\":{\"type\":\"rss\",\"url\":\"https://www.coredump.ch/feed/\"}\
            },\
            \"issue_report_channels\":[\"email\",\"twitter\"],\
            \"location\":{\
                \"address\":\"Spinnereistrasse 2, 8640 Rapperswil, Switzerland\",\
                \"lat\":47.22936,\"lon\":8.82949\
            },\
            \"logo\":\"https://www.coredump.ch/logo.png\",\
            \"projects\":[\
                \"https://www.coredump.ch/projekte/\",\
                \"https://discourse.coredump.ch/c/projects\",\
                \"https://github.com/coredump-ch/\"\
            ],\
            \"sensors\":{\
                \"people_now_present\":[{\
                    \"location\":\"Hackerspace\",\"value\":23\
                }],\
                \"temperature\":[{\
                    \"location\":\"Hackerspace\",\"name\":\"Raspberry CPU\",\
                    \"unit\":\"°C\",\"value\":42.5\
                }]\
            },\
            \"space\":\"coredump\",\
            \"spacefed\":{\"spacenet\":false,\"spacephone\":false,\"spacesaml\":false},\
            \"state\":{\"message\":\"Open every Monday from 20:00\",\"open\":false},\
            \"url\":\"https://www.coredump.ch/\"\
        }");
    }
}
<commit_msg>Set headers, the iron way<commit_after>//! The main entry point for the SpaceAPi server.
//!
//! Running this code starts a HTTP server instance. The default port is 3000, but you can set your
//! own favorite port by exporting the `PORT` environment variable.

extern crate rustc_serialize;
extern crate iron;
extern crate spaceapi;

mod utils;

use std::io::Write;
use std::net::Ipv4Addr;

use rustc_serialize::json::ToJson;
use iron::{Chain, Request, Response, IronResult, IronError, Iron, Set};
use iron::{status, headers};
use iron::modifiers::Header;

use spaceapi::datastore::DataStore;
use spaceapi::redis_store::RedisStore;
use spaceapi::Optional::{Value, Absent};

fn build_response_json(people_present: Option<u32>, raspi_temperature: Option<f32>) -> String {
    let people_present_sensor = match people_present {
        Some(count) => Value(vec![
            spaceapi::PeopleNowPresentSensor {
                value: count,
                location: Value("Hackerspace".to_string()),
                name: Absent,
                description: Absent,
                names: Absent,
            }
        ]),
        None => Absent,
    };

    let temperature_sensor = match raspi_temperature {
        Some(degrees) => Value(vec![
            spaceapi::TemperatureSensor {
                value: degrees,
                unit: "°C".to_string(),
                location: "Hackerspace".to_string(),
                name: Value("Raspberry CPU".to_string()),
                description: Absent,
            }
        ]),
        None => Absent,
    };

    let status = spaceapi::Status {

        // Hackerspace properties
        api: "0.13".to_string(),
        space: "coredump".to_string(),
        logo: "https://www.coredump.ch/logo.png".to_string(),
        url: "https://www.coredump.ch/".to_string(),
        location: spaceapi::Location {
            address: Value("Spinnereistrasse 2, 8640 Rapperswil, Switzerland".to_string()),
            lat: 47.22936,
            lon: 8.82949,
        },
        contact: spaceapi::Contact {
            irc: Value("irc://freenode.net/#coredump".to_string()),
            twitter: Value("@coredump_ch".to_string()),
            foursquare: Value("525c20e5498e875d8231b1e5".to_string()),
            email: Value("danilo@coredump.ch".to_string()),
        },

        // Hackerspace features / projects
        spacefed: Value(spaceapi::Spacefed {
            spacenet: false,
            spacesaml: false,
            spacephone: false,
        }),
        projects: Value(vec![
            "https://www.coredump.ch/projekte/".to_string(),
            "https://discourse.coredump.ch/c/projects".to_string(),
            "https://github.com/coredump-ch/".to_string(),
        ]),
        cam: Absent,
        feeds: Value(spaceapi::Feeds {
            blog: Value(spaceapi::Feed {
                _type: Value("rss".to_string()),
                url: "https://www.coredump.ch/feed/".to_string(),
            }),
            wiki: Absent,
            calendar: Absent,
            flickr: Absent,
        }),
        events: Absent,
        radio_show: Absent,

        // SpaceAPI internal usage
        cache: Value(spaceapi::Cache {
            schedule: "m.02".to_string(),
        }),
        issue_report_channels: vec![
            "email".to_string(),
            "twitter".to_string(),
        ],

        // Mutable data
        state: spaceapi::State {
            open: Some(false),
            message: Value("Open every Monday from 20:00".to_string()),
            lastchange: Absent,
            trigger_person: Absent,
            icon: Absent,
        },
        sensors: Value(spaceapi::Sensors {
            people_now_present: people_present_sensor,
            temperature: temperature_sensor,
        }),

    };
    status.to_json().to_string()
}

fn status_endpoint(_: &mut Request) -> IronResult<Response> {
    // Fetch data from datastore
    let datastore = RedisStore::new().unwrap();
    let people_present: Option<u32> = match datastore.retrieve("people_present") {
        Ok(v) => match v.parse::<u32>() {
            Ok(i) => Some(i),
            Err(_) => None,
        },
        Err(_) => None,
    };
    let raspi_temperature: Option<f32> = match datastore.retrieve("raspi_temperature") {
        Ok(v) => match v.parse::<f32>() {
            Ok(i) => Some(i),
            Err(_) => None,
        },
        Err(_) => None,
    };

    // Get response body
    let body = build_response_json(people_present, raspi_temperature);

    // Create response
    let mut response = Response::with((status::Ok, body));

    // Set headers
    response.set_mut(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())));
    response.set_mut(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])));
    response.set_mut(Header(headers::AccessControlAllowOrigin::Any));

    Ok(response)
}

pub struct SpaceapiServer {
    host: Ipv4Addr,
    port: u16,
    status: spaceapi::Status,
}

impl SpaceapiServer {

    pub fn new(host: Ipv4Addr, status: spaceapi::Status) -> SpaceapiServer {
        SpaceapiServer {
            host: host,
            port: utils::get_port(),
            status: status,
        }
    }

    pub fn serve(&self) {
        println!("Starting HTTP server on {}:{}...", self.host, self.port);
        Iron::new(status_endpoint).http((self.host, self.port)).unwrap();
    }

}

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

    #[test]
    /// Verify that the response JSON looks OK.
    fn verify_response_json() {
        let people_present = Some(23);
        let temperature = Some(42.5);
        let json = build_response_json(people_present, temperature);
        assert_eq!(json, "{\
            \"api\":\"0.13\",\
            \"cache\":{\"schedule\":\"m.02\"},\
            \"contact\":{\
                \"email\":\"danilo@coredump.ch\",\
                \"foursquare\":\"525c20e5498e875d8231b1e5\",\
                \"irc\":\"irc://freenode.net/#coredump\",\
                \"twitter\":\"@coredump_ch\"\
            },\
            \"feeds\":{\
                \"blog\":{\"type\":\"rss\",\"url\":\"https://www.coredump.ch/feed/\"}\
            },\
            \"issue_report_channels\":[\"email\",\"twitter\"],\
            \"location\":{\
                \"address\":\"Spinnereistrasse 2, 8640 Rapperswil, Switzerland\",\
                \"lat\":47.22936,\"lon\":8.82949\
            },\
            \"logo\":\"https://www.coredump.ch/logo.png\",\
            \"projects\":[\
                \"https://www.coredump.ch/projekte/\",\
                \"https://discourse.coredump.ch/c/projects\",\
                \"https://github.com/coredump-ch/\"\
            ],\
            \"sensors\":{\
                \"people_now_present\":[{\
                    \"location\":\"Hackerspace\",\"value\":23\
                }],\
                \"temperature\":[{\
                    \"location\":\"Hackerspace\",\"name\":\"Raspberry CPU\",\
                    \"unit\":\"°C\",\"value\":42.5\
                }]\
            },\
            \"space\":\"coredump\",\
            \"spacefed\":{\"spacenet\":false,\"spacephone\":false,\"spacesaml\":false},\
            \"state\":{\"message\":\"Open every Monday from 20:00\",\"open\":false},\
            \"url\":\"https://www.coredump.ch/\"\
        }");
    }
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate chrono;
extern crate uuid;

use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Receiver, Sender, SendError};
use std::thread::{Builder, JoinHandle};

use rustc_serialize::json::{Json, ToJson};
use uuid::Uuid;

pub struct Supervisor {
    name: String,
    actor_mailboxes: HashMap<Uuid, Sender<Json>>,
    actor_handles: HashMap<Uuid, JoinHandle<()>>,
}

impl Supervisor {
    fn new(name: &str) -> Supervisor {
        Supervisor {
            name: name.to_string(),
            actor_mailboxes: HashMap::new(),
            actor_handles: HashMap::new(),
        }
    }

    fn join(&mut self, pid : Uuid) -> Result<(), String> {
        match self.actor_handles.remove(&pid) {
            Some(actor_handle) => {
                self.actor_mailboxes.remove(&pid).unwrap();

                match actor_handle.join() {
                    Ok(_) => Ok(()),
                    Err(e) => Err("you really messed up".to_string()),
                }
            },
            None => Err(format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    fn send_message(&self, pid: Uuid, message: Json) -> Result<(), String> {
        match self.actor_mailboxes.get(&pid) {
            Some(actor_mailbox) => {
                match actor_mailbox.send(message) {
                    Ok(_) => Ok(()),
                    Err(e) => { Err(e.to_string()) },
                }
            },
            None => Err(format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    fn spawn<F>(&mut self, actor_name: &str, body: F) -> Result<Uuid, &str>
        where F : 'static + Send + Fn(Receiver<Json>) -> () {
        let pid = Uuid::new_v4();
        let (mailbox_sender, mailbox_receiver) = channel();
        let arc_body = Arc::new(Mutex::new(body));

        self.actor_mailboxes.insert(pid, mailbox_sender);
        let actor_handle_result = Builder::new().name(pid.to_string()).spawn(move || {
            arc_body.lock().unwrap()(mailbox_receiver);
        });

        match actor_handle_result {
            Ok(actor_handle) => self.actor_handles.insert(pid, actor_handle),
            Err(e) => return Err("boom"), // sigh
        };

        return Ok(pid);
    }
}

#[cfg(test)]
mod tests {
    use std::fs::{remove_file, File};
    use std::io::prelude::*;
    use std::sync::mpsc::{channel, Receiver, Sender};
    use std::thread;
    use chrono::*;
    use rustc_serialize::json::{Json, ToJson};
    use uuid::Uuid;
    use super::*;

    // spawn tests
    #[test]
    fn the_body_actor_callback_is_executed() {
        let mut supervisor = Supervisor::new("folks");
        let json_msg = "{\"hi\": \"friend\"}".to_json();
        let json_clone = json_msg.clone();
        let pid_bob: Uuid = supervisor.spawn(
            "Bob",
            |receiver| {
                let mut message_output_file = File::create("/tmp/bob-test.json").unwrap();
                message_output_file.write_all(receiver.recv().unwrap().to_string().as_bytes()).unwrap();
                ()
            }
        ).unwrap();

        supervisor.send_message(pid_bob, json_msg).unwrap();

        thread::sleep_ms(1001);
        let mut message_output_file = File::open("/tmp/bob-test.json").unwrap();
        let mut message_output = String::new();
        message_output_file.read_to_string(&mut message_output).unwrap();
        remove_file("/tmp/bob-test.json").unwrap();

        let actual_json = Json::from_str(&message_output).unwrap();
        assert_eq!(json_clone, actual_json);
    }

    // send_message tests
    #[test]
    fn error_is_returned_if_message_sent_for_pid_that_does_not_exist() {
        let mut supervisor = Supervisor::new("folks");
        let pid = Uuid::new_v4();

        let send_result = supervisor.send_message(pid, "{}".to_json());

        match send_result {
            Ok(_) => panic!("Message sent to non-existent PID"),
            Err(e) => assert_eq!(e, format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    #[test]
    fn pid_can_be_used_to_send_message() {
        let mut supervisor = Supervisor::new("folks");
        let pid: Uuid = supervisor.spawn(
            "Bob",
            |r| { r.recv().unwrap(); () }
        ).unwrap();

        supervisor.send_message(pid, "{}".to_json()).unwrap();
    }

    // join tests
    #[test]
    fn pid_can_be_used_to_join_actor() {
        let mut supervisor = Supervisor::new("folks");
        let start_time = UTC::now();
        let pid: Uuid = supervisor.spawn(
            "Bob",
            |r| { thread::sleep_ms(1000); () }
        ).unwrap();
        assert!((start_time + Duration::milliseconds(1000)) > UTC::now());

        supervisor.join(pid).unwrap();

        assert!((start_time + Duration::milliseconds(1000)) < UTC::now());
    }

    #[test]
    fn joining_actor_makes_it_unreachable() {
        let mut supervisor = Supervisor::new("folks");
        let pid: Uuid = supervisor.spawn(
            "Bob",
            |r| { () }
        ).unwrap();
        supervisor.join(pid).unwrap();

        let send_result = supervisor.send_message(pid, "{}".to_json());

        match send_result {
            Ok(_) => panic!("Message sent to non-existent PID"),
            Err(e) => assert_eq!(e, format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    #[test]
    fn error_is_returned_if_joining_actor_that_does_not_exist() {
        let mut supervisor = Supervisor::new("folks");
        let pid = Uuid::new_v4();

        let join_result = supervisor.join(pid);

        match join_result {
            Ok(_) => panic!("Actor joined for non-existent PID"),
            Err(e) => assert_eq!(e, format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }
}
<commit_msg>Use Actor struct to hold all references to single actor<commit_after>extern crate rustc_serialize;
extern crate chrono;
extern crate uuid;

use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Receiver, Sender, SendError};
use std::thread::{Builder, JoinHandle};

use rustc_serialize::json::{Json, ToJson};
use uuid::Uuid;

pub struct Actor {
    join_handle: JoinHandle<()>,
    mailbox: Sender<Json>,
    name: String,
    uuid: Uuid,
}

impl Actor {
    fn new(
        join_handle: JoinHandle<()>,
        mailbox: Sender<Json>,
        name: String,
        uuid: Uuid,
    ) -> Actor {
        Actor {
            join_handle: join_handle,
            mailbox: mailbox,
            name: name,
            uuid: uuid,
        }
    }
}

pub struct Supervisor {
    actors: HashMap<Uuid, Actor>,
    name: String,
}

impl Supervisor {
    fn new(name: &str) -> Supervisor {
        Supervisor {
            actors: HashMap::new(),
            name: name.to_string(),
        }
    }

    fn join(&mut self, pid : Uuid) -> Result<(), String> {
        match self.actors.remove(&pid) {
            Some(actor) => {
                match actor.join_handle.join() {
                    Ok(_) => Ok(()),
                    Err(e) => Err("you really messed up".to_string()),
                }
            },
            None => Err(format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    fn send_message(&self, pid: Uuid, message: Json) -> Result<(), String> {
        match self.actors.get(&pid) {
            Some(actor) => {
                match actor.mailbox.send(message) {
                    Ok(_) => Ok(()),
                    Err(e) => { Err(e.to_string()) },
                }
            },
            None => Err(format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    fn spawn<F>(&mut self, actor_name: &str, body: F) -> Result<Uuid, &str>
        where F : 'static + Send + Fn(Receiver<Json>) -> () {
        let pid = Uuid::new_v4();
        let (mailbox_sender, mailbox_receiver) = channel();
        let arc_body = Arc::new(Mutex::new(body));

        let actor_handle_result = Builder::new().name(pid.to_string()).spawn(move || {
            arc_body.lock().unwrap()(mailbox_receiver);
        });

        match actor_handle_result {
            Ok(actor_handle) => {
                self.actors.insert(pid, Actor::new(
                    actor_handle,
                    mailbox_sender,
                    actor_name.to_string(),
                    pid,
                ))
            }
            Err(e) => return Err("boom"), // sigh
        };

        return Ok(pid);
    }
}

#[cfg(test)]
mod tests {
    use std::fs::{remove_file, File};
    use std::io::prelude::*;
    use std::sync::mpsc::{channel, Receiver, Sender};
    use std::thread;
    use chrono::*;
    use rustc_serialize::json::{Json, ToJson};
    use uuid::Uuid;
    use super::*;

    // spawn tests
    #[test]
    fn the_body_actor_callback_is_executed() {
        let mut supervisor = Supervisor::new("folks");
        let json_msg = "{\"hi\": \"friend\"}".to_json();
        let json_clone = json_msg.clone();
        let pid_bob: Uuid = supervisor.spawn(
            "Bob",
            |receiver| {
                let mut message_output_file = File::create("/tmp/bob-test.json").unwrap();
                message_output_file.write_all(receiver.recv().unwrap().to_string().as_bytes()).unwrap();
                ()
            }
        ).unwrap();

        supervisor.send_message(pid_bob, json_msg).unwrap();

        thread::sleep_ms(1001);
        let mut message_output_file = File::open("/tmp/bob-test.json").unwrap();
        let mut message_output = String::new();
        message_output_file.read_to_string(&mut message_output).unwrap();
        remove_file("/tmp/bob-test.json").unwrap();

        let actual_json = Json::from_str(&message_output).unwrap();
        assert_eq!(json_clone, actual_json);
    }

    // send_message tests
    #[test]
    fn error_is_returned_if_message_sent_for_pid_that_does_not_exist() {
        let mut supervisor = Supervisor::new("folks");
        let pid = Uuid::new_v4();

        let send_result = supervisor.send_message(pid, "{}".to_json());

        match send_result {
            Ok(_) => panic!("Message sent to non-existent PID"),
            Err(e) => assert_eq!(e, format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    #[test]
    fn pid_can_be_used_to_send_message() {
        let mut supervisor = Supervisor::new("folks");
        let pid: Uuid = supervisor.spawn(
            "Bob",
            |r| { r.recv().unwrap(); () }
        ).unwrap();

        supervisor.send_message(pid, "{}".to_json()).unwrap();
    }

    // join tests
    #[test]
    fn pid_can_be_used_to_join_actor() {
        let mut supervisor = Supervisor::new("folks");
        let start_time = UTC::now();
        let pid: Uuid = supervisor.spawn(
            "Bob",
            |r| { thread::sleep_ms(1000); () }
        ).unwrap();
        assert!((start_time + Duration::milliseconds(1000)) > UTC::now());

        supervisor.join(pid).unwrap();

        assert!((start_time + Duration::milliseconds(1000)) < UTC::now());
    }

    #[test]
    fn joining_actor_makes_it_unreachable() {
        let mut supervisor = Supervisor::new("folks");
        let pid: Uuid = supervisor.spawn(
            "Bob",
            |r| { () }
        ).unwrap();
        supervisor.join(pid).unwrap();

        let send_result = supervisor.send_message(pid, "{}".to_json());

        match send_result {
            Ok(_) => panic!("Message sent to non-existent PID"),
            Err(e) => assert_eq!(e, format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }

    #[test]
    fn error_is_returned_if_joining_actor_that_does_not_exist() {
        let mut supervisor = Supervisor::new("folks");
        let pid = Uuid::new_v4();

        let join_result = supervisor.join(pid);

        match join_result {
            Ok(_) => panic!("Actor joined for non-existent PID"),
            Err(e) => assert_eq!(e, format!("PID {} does not map to a spawned actor", pid.to_string())),
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate bitflags;
extern crate gl as gl_lib;

#[macro_use] mod macros;
mod context;
mod buffer;
mod shader;
mod program;
mod framebuffer;
mod renderbuffer;
mod texture;
mod texture_units;
mod image_data;
mod vertex_data;
mod vertex_buffer;
mod index_data;
mod uniform_data;
mod types;

pub use gl_lib as gl;

pub use context::*;
pub use buffer::*;
pub use shader::*;
pub use program::*;
pub use framebuffer::*;
pub use renderbuffer::*;
pub use texture::*;
pub use texture_units::*;
pub use image_data::*;
pub use vertex_data::*;
pub use vertex_buffer::*;
pub use index_data::*;
pub use uniform_data::*;
pub use types::*;
<commit_msg>Add a `prelude` module<commit_after>#[macro_use] extern crate bitflags;
extern crate gl as gl_lib;

#[macro_use] mod macros;
mod context;
mod buffer;
mod shader;
mod program;
mod framebuffer;
mod renderbuffer;
mod texture;
mod texture_units;
mod image_data;
mod vertex_data;
mod vertex_buffer;
mod index_data;
mod uniform_data;
mod types;

pub use gl_lib as gl;

pub use context::*;
pub use buffer::*;
pub use shader::*;
pub use program::*;
pub use framebuffer::*;
pub use renderbuffer::*;
pub use texture::*;
pub use texture_units::*;
pub use image_data::*;
pub use vertex_data::*;
pub use vertex_buffer::*;
pub use index_data::*;
pub use uniform_data::*;
pub use types::*;

pub mod prelude {
    pub use buffer::BufferBinding;
    pub use texture_units::TextureUnit;
    pub use texture::TextureBinding;
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Mark Lee
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Low-level bindings to OSX/macOS/iOS's `CommonCrypto` library.

#![warn(missing_docs)]

extern crate hex;
extern crate libc;

use libc::{c_int, c_uint, c_ulong, c_ulonglong};

/// Total number of operations.
const MD5_CBLOCK: usize = 64;
/// Number of operations per round.
const MD5_LBLOCK: usize = MD5_CBLOCK / 4;
/// Number of bytes for an MD5 hash.
pub const MD5_DIGEST_LENGTH: usize = 16;

const SHA_LBLOCK: usize = 16;
/// Number of bytes for an SHA1 hash.
pub const SHA1_DIGEST_LENGTH: usize = 20;
/// Number of bytes for an SHA256 hash.
pub const SHA256_DIGEST_LENGTH: usize = 32;
/// Number of bytes for an SHA512 hash.
pub const SHA512_DIGEST_LENGTH: usize = 64;

/// Struct used to generate MD5 hashes.
#[allow(non_camel_case_types, non_snake_case)]
#[derive(Clone, Debug, Default, PartialEq)]
#[repr(C)]
pub struct CC_MD5_CTX {
    A: c_uint,
    B: c_uint,
    C: c_uint,
    D: c_uint,
    Nl: c_uint,
    Nh: c_uint,
    data: [c_uint; MD5_LBLOCK],
    num: c_uint,
}

/// Struct used to generate SHA1 hashes.
#[allow(non_camel_case_types, non_snake_case)]
#[derive(Clone, Debug, Default, PartialEq)]
#[repr(C)]
pub struct CC_SHA_CTX {
    h0: c_uint,
    h1: c_uint,
    h2: c_uint,
    h3: c_uint,
    h4: c_uint,
    Nl: c_uint,
    Nh: c_uint,
    data: [c_uint; SHA_LBLOCK],
    num: c_uint,
}

/// Struct used to generate SHA256 hashes.
#[allow(non_camel_case_types, non_snake_case)]
#[derive(Clone, Debug, Default, PartialEq)]
#[repr(C)]
pub struct CC_SHA256_CTX {
    h: [c_ulong; 8],
    Nl: c_ulong,
    Nh: c_ulong,
    data: [c_ulong; SHA_LBLOCK],
    num: c_uint,
    md_len: c_uint,
}

/// Struct used to generate SHA512 hashes.
#[allow(non_camel_case_types, non_snake_case)]
#[derive(Clone, Debug, Default, PartialEq)]
#[repr(C)]
pub struct CC_SHA512_CTX {
    h: [c_ulonglong; 8],
    Nl: c_ulonglong,
    Nh: c_ulonglong,
    data: [c_ulonglong; SHA_LBLOCK],
    num: c_uint,
    md_len: c_uint,
}

extern "C" {
    /// Initializes MD5 hasher. See `man 3cc CC_MD5` for details.
    pub fn CC_MD5_Init(ctx: *mut CC_MD5_CTX) -> c_int;
    /// Appends data to be hashed. See `man 3cc CC_MD5` for details.
    pub fn CC_MD5_Update(ctx: *mut CC_MD5_CTX, data: *const u8, n: usize) -> c_int;
    /// Generates MD5 hash. See `man 3cc CC_MD5` for details.
    pub fn CC_MD5_Final(md: *mut u8, ctx: *mut CC_MD5_CTX) -> c_int;
    /// Initializes SHA1 hasher. See `man 3cc CC_SHA1` for details.
    pub fn CC_SHA1_Init(ctx: *mut CC_SHA_CTX) -> c_int;
    /// Appends data to be hashed. See `man 3cc CC_SHA1` for details.
    pub fn CC_SHA1_Update(ctx: *mut CC_SHA_CTX, data: *const u8, n: usize) -> c_int;
    /// Generates SHA1 hash. See `man 3cc CC_SHA1` for details.
    pub fn CC_SHA1_Final(md: *mut u8, ctx: *mut CC_SHA_CTX) -> c_int;
    /// Initializes SHA256 hasher. See `man 3cc CC_SHA256` for details.
    pub fn CC_SHA256_Init(ctx: *mut CC_SHA256_CTX) -> c_int;
    /// Appends data to be hashed. See `man 3cc CC_SHA256` for details.
    pub fn CC_SHA256_Update(ctx: *mut CC_SHA256_CTX, data: *const u8, n: usize) -> c_int;
    /// Generates SHA256 hash. See `man 3cc CC_SHA256` for details.
    pub fn CC_SHA256_Final(md: *mut u8, ctx: *mut CC_SHA256_CTX) -> c_int;
    /// Initializes SHA512 hasher. See `man 3cc CC_SHA512` for details.
    pub fn CC_SHA512_Init(ctx: *mut CC_SHA512_CTX) -> c_int;
    /// Appends data to be hashed. See `man 3cc CC_SHA512` for details.
    pub fn CC_SHA512_Update(ctx: *mut CC_SHA512_CTX, data: *const u8, n: usize) -> c_int;
    /// Generates SHA512 hash. See `man 3cc CC_SHA512` for details.
    pub fn CC_SHA512_Final(md: *mut u8, ctx: *mut CC_SHA512_CTX) -> c_int;
}

#[cfg(test)]
mod test {
    use hex::ToHex;

    const TO_HASH: &'static str = "The quick brown fox jumps over the lazy dog";
    const TO_HASH_MD5: &'static str = "9e107d9d372bb6826bd81d3542a419d6";
    const TO_HASH_SHA1: &'static str = "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12";
    const TO_HASH_SHA256: &'static str = "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592";
    const TO_HASH_SHA512: &'static str = "07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6";

    macro_rules! test_hash {
        (
            $test_name: ident,
            $ctx_ty: ident,
            $digest_len: ident,
            $init_func: ident,
            $update_func: ident,
            $final_func: ident,
            $expected_hash: ident
        ) => {
            #[test]
            fn $test_name() {
                let mut ctx = super::$ctx_ty::default();
                let mut md = [0u8; super::$digest_len];
                unsafe {
                    assert_eq!(super::$init_func(&mut ctx), 1);
                    assert_eq!(super::$update_func(&mut ctx, TO_HASH.as_ptr(), TO_HASH.len()), 1);
                    assert_eq!(super::$final_func(md.as_mut_ptr(), &mut ctx), 1);
                }
                assert_eq!(md.to_vec().to_hex(), $expected_hash);
            }
        }
    }

    test_hash!(md5_hash,
               CC_MD5_CTX,
               MD5_DIGEST_LENGTH,
               CC_MD5_Init,
               CC_MD5_Update,
               CC_MD5_Final,
               TO_HASH_MD5);
    test_hash!(sha1_hash,
               CC_SHA_CTX,
               SHA1_DIGEST_LENGTH,
               CC_SHA1_Init,
               CC_SHA1_Update,
               CC_SHA1_Final,
               TO_HASH_SHA1);
    test_hash!(sha256_hash,
               CC_SHA256_CTX,
               SHA256_DIGEST_LENGTH,
               CC_SHA256_Init,
               CC_SHA256_Update,
               CC_SHA256_Final,
               TO_HASH_SHA256);
    test_hash!(sha512_hash,
               CC_SHA512_CTX,
               SHA512_DIGEST_LENGTH,
               CC_SHA512_Init,
               CC_SHA512_Update,
               CC_SHA512_Final,
               TO_HASH_SHA512);
}
<commit_msg>Add SHA384 support<commit_after>// Copyright (c) 2016 Mark Lee
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Low-level bindings to OSX/macOS/iOS's `CommonCrypto` library.

#![warn(missing_docs)]

extern crate hex;
extern crate libc;

use libc::{c_int, c_uint};

/// Total number of operations.
const MD5_CBLOCK: usize = 64;
/// Number of operations per round.
const MD5_LBLOCK: usize = MD5_CBLOCK / 4;
/// Number of bytes for an MD5 hash.
pub const MD5_DIGEST_LENGTH: usize = 16;

const SHA_LBLOCK: usize = 16;
/// Number of bytes for an SHA1 hash.
pub const SHA1_DIGEST_LENGTH: usize = 20;
/// Number of bytes for an SHA256 hash.
pub const SHA256_DIGEST_LENGTH: usize = 32;
/// Number of bytes for an SHA384 hash.
pub const SHA384_DIGEST_LENGTH: usize = 48;
/// Number of bytes for an SHA512 hash.
pub const SHA512_DIGEST_LENGTH: usize = 64;

/// Struct used to generate MD5 hashes.
#[allow(non_camel_case_types, non_snake_case)]
#[derive(Clone, Debug, Default, PartialEq)]
#[repr(C)]
pub struct CC_MD5_CTX {
    A: c_uint,
    B: c_uint,
    C: c_uint,
    D: c_uint,
    Nl: c_uint,
    Nh: c_uint,
    data: [c_uint; MD5_LBLOCK],
    num: c_uint,
}

/// Struct used to generate SHA1 hashes.
#[allow(non_camel_case_types, non_snake_case)]
#[derive(Clone, Debug, Default, PartialEq)]
#[repr(C)]
pub struct CC_SHA_CTX {
    h0: c_uint,
    h1: c_uint,
    h2: c_uint,
    h3: c_uint,
    h4: c_uint,
    Nl: c_uint,
    Nh: c_uint,
    data: [c_uint; SHA_LBLOCK],
    num: c_uint,
}

macro_rules! sha2_struct {
    ($ctx_name: ident, $ty: ty) => {
        /// Struct used to generate SHA2 hashes with the given bits.
        #[allow(non_camel_case_types, non_snake_case)]
        #[derive(Clone, Debug, Default, PartialEq)]
        #[repr(C)]
        pub struct $ctx_name {
            count: [$ty; 2],
            hash: [$ty; 8],
            wbuf: [$ty; 16],
        }
    }
}

sha2_struct!(CC_SHA256_CTX, u32);
sha2_struct!(CC_SHA512_CTX, u64);

extern "C" {
    /// Initializes MD5 hasher. See `man 3cc CC_MD5` for details.
    pub fn CC_MD5_Init(ctx: *mut CC_MD5_CTX) -> c_int;
    /// Appends data to be hashed. See `man 3cc CC_MD5` for details.
    pub fn CC_MD5_Update(ctx: *mut CC_MD5_CTX, data: *const u8, n: usize) -> c_int;
    /// Generates MD5 hash. See `man 3cc CC_MD5` for details.
    pub fn CC_MD5_Final(md: *mut u8, ctx: *mut CC_MD5_CTX) -> c_int;
    /// Initializes SHA1 hasher. See `man 3cc CC_SHA` for details.
    pub fn CC_SHA1_Init(ctx: *mut CC_SHA_CTX) -> c_int;
    /// Appends data to be hashed. See `man 3cc CC_SHA` for details.
    pub fn CC_SHA1_Update(ctx: *mut CC_SHA_CTX, data: *const u8, n: usize) -> c_int;
    /// Generates SHA1 hash. See `man 3cc CC_SHA` for details.
    pub fn CC_SHA1_Final(md: *mut u8, ctx: *mut CC_SHA_CTX) -> c_int;
    /// Initializes SHA256 hasher. See `man 3cc CC_SHA` for details.
    pub fn CC_SHA256_Init(ctx: *mut CC_SHA256_CTX) -> c_int;
    /// Appends data to be hashed. See `man 3cc CC_SHA` for details.
    pub fn CC_SHA256_Update(ctx: *mut CC_SHA256_CTX, data: *const u8, n: usize) -> c_int;
    /// Generates SHA256 hash. See `man 3cc CC_SHA` for details.
    pub fn CC_SHA256_Final(md: *mut u8, ctx: *mut CC_SHA256_CTX) -> c_int;
    /// Initializes SHA384 hasher. See `man 3cc CC_SHA` for details.
    pub fn CC_SHA384_Init(ctx: *mut CC_SHA512_CTX) -> c_int;
    /// Appends data to be hashed. See `man 3cc CC_SHA` for details.
    pub fn CC_SHA384_Update(ctx: *mut CC_SHA512_CTX, data: *const u8, n: usize) -> c_int;
    /// Generates SHA384 hash. See `man 3cc CC_SHA` for details.
    pub fn CC_SHA384_Final(md: *mut u8, ctx: *mut CC_SHA512_CTX) -> c_int;
    /// Initializes SHA512 hasher. See `man 3cc CC_SHA` for details.
    pub fn CC_SHA512_Init(ctx: *mut CC_SHA512_CTX) -> c_int;
    /// Appends data to be hashed. See `man 3cc CC_SHA` for details.
    pub fn CC_SHA512_Update(ctx: *mut CC_SHA512_CTX, data: *const u8, n: usize) -> c_int;
    /// Generates SHA512 hash. See `man 3cc CC_SHA` for details.
    pub fn CC_SHA512_Final(md: *mut u8, ctx: *mut CC_SHA512_CTX) -> c_int;
}

#[cfg(test)]
mod test {
    use hex::ToHex;

    const TO_HASH: &'static str = "The quick brown fox jumps over the lazy dog";
    const TO_HASH_MD5: &'static str = "9e107d9d372bb6826bd81d3542a419d6";
    const TO_HASH_SHA1: &'static str = "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12";
    const TO_HASH_SHA256: &'static str = "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592";
    const TO_HASH_SHA384: &'static str = "ca737f1014a48f4c0b6dd43cb177b0afd9e5169367544c494011e3317dbf9a509cb1e5dc1e85a941bbee3d7f2afbc9b1";
    const TO_HASH_SHA512: &'static str = "07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6";

    macro_rules! test_hash {
        (
            $test_name: ident,
            $ctx_ty: ident,
            $digest_len: ident,
            $init_func: ident,
            $update_func: ident,
            $final_func: ident,
            $expected_hash: ident
        ) => {
            #[test]
            fn $test_name() {
                let mut ctx = super::$ctx_ty::default();
                let mut md = [0u8; super::$digest_len];
                unsafe {
                    assert_eq!(super::$init_func(&mut ctx), 1);
                    assert_eq!(super::$update_func(&mut ctx, TO_HASH.as_ptr(), TO_HASH.len()), 1);
                    assert_eq!(super::$final_func(md.as_mut_ptr(), &mut ctx), 1);
                }
                assert_eq!(md.to_vec().to_hex(), $expected_hash);
            }
        }
    }

    test_hash!(md5_hash,
               CC_MD5_CTX,
               MD5_DIGEST_LENGTH,
               CC_MD5_Init,
               CC_MD5_Update,
               CC_MD5_Final,
               TO_HASH_MD5);
    test_hash!(sha1_hash,
               CC_SHA_CTX,
               SHA1_DIGEST_LENGTH,
               CC_SHA1_Init,
               CC_SHA1_Update,
               CC_SHA1_Final,
               TO_HASH_SHA1);
    test_hash!(sha256_hash,
               CC_SHA256_CTX,
               SHA256_DIGEST_LENGTH,
               CC_SHA256_Init,
               CC_SHA256_Update,
               CC_SHA256_Final,
               TO_HASH_SHA256);
    test_hash!(sha384_hash,
               CC_SHA512_CTX,
               SHA384_DIGEST_LENGTH,
               CC_SHA384_Init,
               CC_SHA384_Update,
               CC_SHA384_Final,
               TO_HASH_SHA384);
    test_hash!(sha512_hash,
               CC_SHA512_CTX,
               SHA512_DIGEST_LENGTH,
               CC_SHA512_Init,
               CC_SHA512_Update,
               CC_SHA512_Final,
               TO_HASH_SHA512);
}
<|endoftext|>


<commit_before>//! The `lonlat_bng` crate provides a function that converts decimal longitude
//! and latitude coordinates into British National Grid Coordinates
//!
//! Examples
//!
//!```
//! assert_eq!((516276, 173141), lonlat_bng::convert(-0.32824866, 51.44533267));
//!```

#[allow(non_snake_case)]
use std::f32::consts;
use std::mem;

// http://stackoverflow.com/a/28124775/155423
fn round(x: f32) -> f32 {
    let y = x.floor();
    if x == y {
        x
    } else {
        let z = (2.0*x-y).floor();
        z * x.signum() // Should use copysign, but not stably-available
    }
}

/// This function performs lon, lat to BNG conversion
///
/// Examples
///
/// ```
/// use lonlat_bng::convert;
/// assert_eq!((516276, 173141), convert(-0.32824866, 51.44533267));
#[no_mangle]
pub extern fn convert(input_lon: f32, input_lat: f32) -> (i32, i32) {
    let pi: f32 = consts::PI;
    //Convert input to degrees
    let lat_1: f32 = input_lat * pi / 180.;
    let lon_1: f32 = input_lon * pi / 180.;
    // The GSR80 semi-major and semi-minor axes used for WGS84 (m)
    let a_1: f32 = 6378137.;
    let b_1: f32 = 6356752.3141;
    // The eccentricity (squared) of the GRS80 ellipsoid
    let e2_1: f32 = 1. - (b_1.powf(2.)) / (a_1.powf(2.));
    // Transverse radius of curvature
    let nu_1: f32 = a_1 / (1. - e2_1 * lat_1.sin().powf(2.)).sqrt();
    // Third spherical coordinate is 0, in this case
    let H: f32 = 0.;
    let x_1: f32 = (nu_1 + H) * lat_1.cos() * lon_1.cos();
    let y_1: f32 = (nu_1 + H) * lat_1.cos() * lon_1.sin();
    let z_1: f32 = ((1. - e2_1) * nu_1 + H) * lat_1.sin();

    // Perform Helmert transform (to go between Airy 1830 (_1) and GRS80 (_2))
    let small: f32 = 10.;
    let cst: f32 = 20.4894;
    let s: f32 =  cst * small.powf(-6.);
    // The translations along x, y, z axes respectively
    let tx: f32 = -446.448;
    let ty: f32 = 125.157;
    let tz: f32 = -542.060;
    // The rotations along x, y, z respectively, in seconds
    let rxs: f32 = -0.1502;
    let rys: f32 = -0.2470;
    let rzs: f32 = -0.8421;
    // In radians
    let rx: f32 = rxs * pi / (180. * 3600.);
    let ry: f32 = rys * pi / (180. * 3600.);
    let rz: f32 = rzs * pi / (180. * 3600.);
    // panic begins on line 46
    let x_2: f32 = tx + (1. + s) * x_1 + -rz * y_1 + ry * z_1;
    let y_2: f32 = ty + rz * x_1 + (1. + s) * y_1 + -rx * z_1;
    let z_2: f32 = tz + -ry * x_1 + rx * y_1 + (1. + s) * z_1;

    // The GSR80 semi-major and semi-minor axes used for WGS84 (m)
    let a: f32 = 6377563.396;
    let b: f32 = 6356256.909;
    // The eccentricity of the Airy 1830 ellipsoid
    let e2: f32 = 1. - b.powf(2.) / a.powf(2.);
    let p: f32 = (x_2.powf(2.) + y_2.powf(2.)).sqrt();
    // Initial value
    let mut lat: f32 = z_2.atan2((p * (1. - e2)));
    let mut latold: f32 = 2. * pi;
    // this is cheating, but not sure how else to initialise nu
    let mut nu: f32 = 1.;
    // Latitude is obtained by iterative procedure
    while (lat - latold).abs() > small.powf(-16.) {
        mem::swap(&mut lat, &mut latold);
        nu = a / (1. - e2 * latold.sin().powf(2.)).sqrt();
        lat = (z_2 + e2 * nu * latold.sin()).atan2(p);
    };
    let lon: f32 = y_2.atan2(x_2);
    // Scale factor on the central meridian
    let F0: f32 = 0.9996012717;
    // Latitude of true origin (radians)
    let lat0: f32 = 49. * pi / 180.;
    // Longtitude of true origin and central meridian (radians)
    let lon0: f32 = -2. * pi / 180.;
    // Northing & easting of true origin (m)
    let N0: f32 = -100000.;
    let E0: f32 = 400000.;
    let n: f32 = (a - b) / (a + b);
    // Meridional radius of curvature
    let rho: f32 = a * F0 * (1. - e2) * (1. - e2 * lat.sin().powf(2.)).powf(-1.5);
    let eta2: f32 = nu * F0 / rho - 1.;

    let M1: f32 = (1. + n + (5. / 4.) * n.powf(2.) + (5. / 4.) * n.powf(3.)) * (lat - lat0);
    let M2: f32 = (3. * n + 3. * n.powf(2.) + (21. / 8.) * n.powf(3.)) * (lat - lat0).sin() * (lat + lat0).cos();
    let M3: f32 = ((15. / 8.) * n.powf(2.) + (15. / 8.) * n.powf(3.)) * (2. * (lat-lat0)).sin() * (2. * (lat + lat0)).cos();
    let M4: f32 = (35. / 24.) * n.powf(3.) * (3. * (lat - lat0)).sin() * (3. * (lat + lat0)).cos();
    let M: f32 = b * F0 * (M1 - M2 + M3 - M4);

    let I: f32 = M + N0;
    let II: f32 = nu * F0 * lat.sin() * lat.cos() / 2.;
    let III: f32 = nu * F0 * lat.sin() * lat.cos().powf(3.) * (5. - lat.tan().powf(2.) + 9. * eta2) / 24.;
    let IIIA: f32 = nu * F0 * lat.sin() * lat.cos().powf(5.) * (61. - 58. * lat.tan().powf(2.) + lat.tan().powf(4.)) / 720.;
    let IV: f32 = nu * F0 * lat.cos();
    let V: f32 = nu * F0 * lat.cos().powf(3.) * (nu / rho - lat.tan().powf(2.)) / 6.;
    let VI: f32 = nu * F0 * lat.cos().powf(5.) * (5. - 18. * lat.tan().powf(2.) + lat.tan().powf(4.) + 14. * eta2 - 58. * eta2 * lat.tan().powf(2.)) / 120.;
    let N: f32 = I + II * (lon - lon0).powf(2.) + III * (lon - lon0).powf(4.) + IIIA * (lon - lon0).powf(6.);
    let E: f32 = E0 + IV * (lon - lon0) + V * (lon - lon0).powf(3.) + VI * (lon - lon0).powf(5.);
    return (round(E) as i32, round(N) as i32);
}

#[test]
fn test_conversion() {
    // verified to be correct at http://www.bgs.ac.uk/data/webservices/convertForm.cfm
    assert_eq!((516276, 173141), convert(-0.32824866, 51.44533267));
}
<commit_msg>Add bounds check for longitude and latitude input<commit_after>//! The `lonlat_bng` crate provides a function that converts decimal longitude
//! and latitude coordinates into British National Grid Coordinates
//!
//! Examples
//!
//!```
//! assert_eq!((516276, 173141), lonlat_bng::convert(-0.32824866, 51.44533267));
//!```

#[allow(non_snake_case)]
use std::f32::consts;
use std::mem;

// http://stackoverflow.com/a/28124775/155423
fn round(x: f32) -> f32 {
    let y = x.floor();
    if x == y {
        x
    } else {
        let z = (2.0*x-y).floor();
        z * x.signum() // Should use copysign, but not stably-available
    }
}

/// This function performs lon, lat to BNG conversion
///
/// Examples
///
/// ```
/// use lonlat_bng::convert;
/// assert_eq!((516276, 173141), convert(-0.32824866, 51.44533267));
#[no_mangle]
pub extern fn convert(input_lon: f32, input_lat: f32) -> (i32, i32) {

    // if not all([0 <= input_lat <= 90, -180 <= input_lon <= 180]):
    match input_lon {
        -180.0...180.0 => input_lon,
        _ => panic!("Out of bounds! Longitude must be between -180 and 180.")
    };
      match input_lat {
        -90.0...90.0 => input_lat,
        _ => panic!("Out of bounds! Latitude must be between -90 and 90.")
    };
    let pi: f32 = consts::PI;
    //Convert input to degrees
    let lat_1: f32 = input_lat * pi / 180.;
    let lon_1: f32 = input_lon * pi / 180.;
    // The GSR80 semi-major and semi-minor axes used for WGS84 (m)
    let a_1: f32 = 6378137.;
    let b_1: f32 = 6356752.3141;
    // The eccentricity (squared) of the GRS80 ellipsoid
    let e2_1: f32 = 1. - (b_1.powf(2.)) / (a_1.powf(2.));
    // Transverse radius of curvature
    let nu_1: f32 = a_1 / (1. - e2_1 * lat_1.sin().powf(2.)).sqrt();
    // Third spherical coordinate is 0, in this case
    let H: f32 = 0.;
    let x_1: f32 = (nu_1 + H) * lat_1.cos() * lon_1.cos();
    let y_1: f32 = (nu_1 + H) * lat_1.cos() * lon_1.sin();
    let z_1: f32 = ((1. - e2_1) * nu_1 + H) * lat_1.sin();

    // Perform Helmert transform (to go between Airy 1830 (_1) and GRS80 (_2))
    let small: f32 = 10.;
    let cst: f32 = 20.4894;
    let s: f32 =  cst * small.powf(-6.);
    // The translations along x, y, z axes respectively
    let tx: f32 = -446.448;
    let ty: f32 = 125.157;
    let tz: f32 = -542.060;
    // The rotations along x, y, z respectively, in seconds
    let rxs: f32 = -0.1502;
    let rys: f32 = -0.2470;
    let rzs: f32 = -0.8421;
    // In radians
    let rx: f32 = rxs * pi / (180. * 3600.);
    let ry: f32 = rys * pi / (180. * 3600.);
    let rz: f32 = rzs * pi / (180. * 3600.);
    // panic begins on line 46
    let x_2: f32 = tx + (1. + s) * x_1 + -rz * y_1 + ry * z_1;
    let y_2: f32 = ty + rz * x_1 + (1. + s) * y_1 + -rx * z_1;
    let z_2: f32 = tz + -ry * x_1 + rx * y_1 + (1. + s) * z_1;

    // The GSR80 semi-major and semi-minor axes used for WGS84 (m)
    let a: f32 = 6377563.396;
    let b: f32 = 6356256.909;
    // The eccentricity of the Airy 1830 ellipsoid
    let e2: f32 = 1. - b.powf(2.) / a.powf(2.);
    let p: f32 = (x_2.powf(2.) + y_2.powf(2.)).sqrt();
    // Initial value
    let mut lat: f32 = z_2.atan2((p * (1. - e2)));
    let mut latold: f32 = 2. * pi;
    // this is cheating, but not sure how else to initialise nu
    let mut nu: f32 = 1.;
    // Latitude is obtained by iterative procedure
    while (lat - latold).abs() > small.powf(-16.) {
        mem::swap(&mut lat, &mut latold);
        nu = a / (1. - e2 * latold.sin().powf(2.)).sqrt();
        lat = (z_2 + e2 * nu * latold.sin()).atan2(p);
    };
    let lon: f32 = y_2.atan2(x_2);
    // Scale factor on the central meridian
    let F0: f32 = 0.9996012717;
    // Latitude of true origin (radians)
    let lat0: f32 = 49. * pi / 180.;
    // Longtitude of true origin and central meridian (radians)
    let lon0: f32 = -2. * pi / 180.;
    // Northing & easting of true origin (m)
    let N0: f32 = -100000.;
    let E0: f32 = 400000.;
    let n: f32 = (a - b) / (a + b);
    // Meridional radius of curvature
    let rho: f32 = a * F0 * (1. - e2) * (1. - e2 * lat.sin().powf(2.)).powf(-1.5);
    let eta2: f32 = nu * F0 / rho - 1.;

    let M1: f32 = (1. + n + (5. / 4.) * n.powf(2.) + (5. / 4.) * n.powf(3.)) * (lat - lat0);
    let M2: f32 = (3. * n + 3. * n.powf(2.) + (21. / 8.) * n.powf(3.)) * (lat - lat0).sin() * (lat + lat0).cos();
    let M3: f32 = ((15. / 8.) * n.powf(2.) + (15. / 8.) * n.powf(3.)) * (2. * (lat-lat0)).sin() * (2. * (lat + lat0)).cos();
    let M4: f32 = (35. / 24.) * n.powf(3.) * (3. * (lat - lat0)).sin() * (3. * (lat + lat0)).cos();
    let M: f32 = b * F0 * (M1 - M2 + M3 - M4);

    let I: f32 = M + N0;
    let II: f32 = nu * F0 * lat.sin() * lat.cos() / 2.;
    let III: f32 = nu * F0 * lat.sin() * lat.cos().powf(3.) * (5. - lat.tan().powf(2.) + 9. * eta2) / 24.;
    let IIIA: f32 = nu * F0 * lat.sin() * lat.cos().powf(5.) * (61. - 58. * lat.tan().powf(2.) + lat.tan().powf(4.)) / 720.;
    let IV: f32 = nu * F0 * lat.cos();
    let V: f32 = nu * F0 * lat.cos().powf(3.) * (nu / rho - lat.tan().powf(2.)) / 6.;
    let VI: f32 = nu * F0 * lat.cos().powf(5.) * (5. - 18. * lat.tan().powf(2.) + lat.tan().powf(4.) + 14. * eta2 - 58. * eta2 * lat.tan().powf(2.)) / 120.;
    let N: f32 = I + II * (lon - lon0).powf(2.) + III * (lon - lon0).powf(4.) + IIIA * (lon - lon0).powf(6.);
    let E: f32 = E0 + IV * (lon - lon0) + V * (lon - lon0).powf(3.) + VI * (lon - lon0).powf(5.);
    return (round(E) as i32, round(N) as i32);
}

#[test]
fn test_conversion() {
    // verified to be correct at http://www.bgs.ac.uk/data/webservices/convertForm.cfm
    assert_eq!((516276, 173141), convert(-0.32824866, 51.44533267));
}

#[test]
#[should_panic]
fn test_bad_lon() {
    assert_eq!((516276, 173141), convert(181., 51.44533267));
}

#[test]
#[should_panic]
fn test_bad_lat() {
    assert_eq!((516276, 173141), convert(-0.32824866, -90.01));
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A (mostly) lock-free concurrent work-stealing deque
//!
//! This module contains an implementation of the Chase-Lev work stealing deque
//! described in "Dynamic Circular Work-Stealing Deque". The implementation is
//! heavily based on the pseudocode found in the paper.
//!
//! This implementation does not want to have the restriction of a garbage
//! collector for reclamation of buffers, and instead it uses a shared pool of
//! buffers. This shared pool is required for correctness in this
//! implementation.
//!
//! The only lock-synchronized portions of this deque are the buffer allocation
//! and deallocation portions. Otherwise all operations are lock-free.
//!
//! # Example
//!
//!     use deque::BufferPool;
//!
//!     let mut pool = BufferPool::new();
//!     let (mut worker, mut stealer) = pool.deque();
//!
//!     // Only the worker may push/pop
//!     worker.push(1i);
//!     worker.pop();
//!
//!     // Stealers take data from the other end of the deque
//!     worker.push(1i);
//!     stealer.steal();
//!
//!     // Stealers can be cloned to have many stealers stealing in parallel
//!     worker.push(1i);
//!     let mut stealer2 = stealer.clone();
//!     stealer2.steal();

#![feature(alloc)]
#![feature(core)]
#![feature(unsafe_destructor)]

extern crate alloc;
extern crate core;

// NB: the "buffer pool" strategy is not done for speed, but rather for
//     correctness. For more info, see the comment on `swap_buffer`

// FIXME: all atomic operations in this module use a SeqCst ordering. That is
//      probably overkill

pub use self::Stolen::*;

use std::sync::{Arc, Mutex};
use alloc::heap::{allocate, deallocate};
use std::boxed::Box;
use std::vec::Vec;
use std::mem::{forget, min_align_of, size_of, transmute};
use core::ptr;

use std::sync::atomic::{AtomicIsize, AtomicPtr};
use std::sync::atomic::Ordering::SeqCst;

// Once the queue is less than 1/K full, then it will be downsized. Note that
// the deque requires that this number be less than 2.
static K: isize = 4;

// Minimum number of bits that a buffer size should be. No buffer will resize to
// under this value, and all deques will initially contain a buffer of this
// size.
//
// The size in question is 1 << MIN_BITS
static MIN_BITS: usize = 7;

struct Deque<T> {
    bottom: AtomicIsize,
    top: AtomicIsize,
    array: AtomicPtr<Buffer<T>>,
    pool: BufferPool<T>,
}

/// Worker half of the work-stealing deque. This worker has exclusive access to
/// one side of the deque, and uses `push` and `pop` method to manipulate it.
///
/// There may only be one worker per deque.
pub struct Worker<T> {
    deque: Arc<Deque<T>>,
}

/// The stealing half of the work-stealing deque. Stealers have access to the
/// opposite end of the deque from the worker, and they only have access to the
/// `steal` method.
pub struct Stealer<T> {
    deque: Arc<Deque<T>>,
}

/// When stealing some data, this is an enumeration of the possible outcomes.
#[derive(PartialEq, Debug)]
pub enum Stolen<T> {
    /// The deque was empty at the time of stealing
    Empty,
    /// The stealer lost the race for stealing data, and a retry may return more
    /// data.
    Abort,
    /// The stealer has successfully stolen some data.
    Data(T),
}

/// The allocation pool for buffers used by work-stealing deques. Right now this
/// structure is used for reclamation of memory after it is no longer in use by
/// deques.
///
/// This data structure is protected by a mutex, but it is rarely used. Deques
/// will only use this structure when allocating a new buffer or deallocating a
/// previous one.
pub struct BufferPool<T> {
    pool: Arc<Mutex<Vec<Box<Buffer<T>>>>>,
}

/// An internal buffer used by the chase-lev deque. This structure is actually
/// implemented as a circular buffer, and is used as the intermediate storage of
/// the data in the deque.
///
/// This type is implemented with *T instead of Vec<T> for two reasons:
///
///   1. There is nothing safe about using this buffer. This easily allows the
///      same value to be read twice in to rust, and there is nothing to
///      prevent this. The usage by the deque must ensure that one of the
///      values is forgotten. Furthermore, we only ever want to manually run
///      destructors for values in this buffer (on drop) because the bounds
///      are defined by the deque it's owned by.
///
///   2. We can certainly avoid bounds checks using *T instead of Vec<T>, although
///      LLVM is probably pretty good at doing this already.
struct Buffer<T> {
    storage: *const T,
    log_size: usize,
}

unsafe impl<T: Send> Send for Buffer<T> { }

impl<T: Send + 'static> BufferPool<T> {
    /// Allocates a new buffer pool which in turn can be used to allocate new
    /// deques.
    pub fn new() -> BufferPool<T> {
        BufferPool { pool: Arc::new(Mutex::new(Vec::new())) }
    }

    /// Allocates a new work-stealing deque which will send/receiving memory to
    /// and from this buffer pool.
    pub fn deque(&self) -> (Worker<T>, Stealer<T>) {
        let a = Arc::new(Deque::new(self.clone()));
        let b = a.clone();
        (Worker { deque: a }, Stealer { deque: b })
    }

    fn alloc(&mut self, bits: usize) -> Box<Buffer<T>> {
        unsafe {
            let mut pool = self.pool.lock().unwrap();
            match pool.iter().position(|x| x.size() >= (1 << bits)) {
                Some(i) => pool.remove(i),
                None => Box::new(Buffer::new(bits))
            }
        }
    }

    fn free(&self, buf: Box<Buffer<T>>) {
        let mut pool = self.pool.lock().unwrap();
        match pool.iter().position(|v| v.size() > buf.size()) {
            Some(i) => pool.insert(i, buf),
            None => pool.push(buf),
        }
    }
}

impl<T: Send> Clone for BufferPool<T> {
    fn clone(&self) -> BufferPool<T> { BufferPool { pool: self.pool.clone() } }
}

impl<T: Send + 'static> Worker<T> {
    /// Pushes data onto the front of this work queue.
    pub fn push(&self, t: T) {
        unsafe { self.deque.push(t) }
    }
    /// Pops data off the front of the work queue, returning `None` on an empty
    /// queue.
    pub fn pop(&self) -> Option<T> {
        unsafe { self.deque.pop() }
    }

    /// Gets access to the buffer pool that this worker is attached to. This can
    /// be used to create more deques which share the same buffer pool as this
    /// deque.
    pub fn pool<'a>(&'a self) -> &'a BufferPool<T> {
        &self.deque.pool
    }
}

impl<T: Send + 'static> Stealer<T> {
    /// Steals work off the end of the queue (opposite of the worker's end)
    pub fn steal(&self) -> Stolen<T> {
        unsafe { self.deque.steal() }
    }

    /// Gets access to the buffer pool that this stealer is attached to. This
    /// can be used to create more deques which share the same buffer pool as
    /// this deque.
    pub fn pool<'a>(&'a self) -> &'a BufferPool<T> {
        &self.deque.pool
    }
}

impl<T: Send> Clone for Stealer<T> {
    fn clone(&self) -> Stealer<T> {
        Stealer { deque: self.deque.clone() }
    }
}

// Almost all of this code can be found directly in the paper so I'm not
// personally going to heavily comment what's going on here.

impl<T: Send + 'static> Deque<T> {
    fn new(mut pool: BufferPool<T>) -> Deque<T> {
        let buf = pool.alloc(MIN_BITS);
        Deque {
            bottom: AtomicIsize::new(0),
            top: AtomicIsize::new(0),
            array: AtomicPtr::new(unsafe { transmute(buf) }),
            pool: pool,
        }
    }

    unsafe fn push(&self, data: T) {
        let mut b = self.bottom.load(SeqCst);
        let t = self.top.load(SeqCst);
        let mut a = self.array.load(SeqCst);
        let size = b - t;
        if size >= (*a).size() - 1 {
            // You won't find this code in the chase-lev deque paper. This is
            // alluded to in a small footnote, however. We always free a buffer
            // when growing in order to prevent leaks.
            a = self.swap_buffer(b, a, (*a).resize(b, t, 1));
            b = self.bottom.load(SeqCst);
        }
        (*a).put(b, data);
        self.bottom.store(b + 1, SeqCst);
    }

    unsafe fn pop(&self) -> Option<T> {
        let b = self.bottom.load(SeqCst);
        let a = self.array.load(SeqCst);
        let b = b - 1;
        self.bottom.store(b, SeqCst);
        let t = self.top.load(SeqCst);
        let size = b - t;
        if size < 0 {
            self.bottom.store(t, SeqCst);
            return None;
        }
        let data = (*a).get(b);
        if size > 0 {
            self.maybe_shrink(b, t);
            return Some(data);
        }
        if self.top.compare_and_swap(t, t + 1, SeqCst) == t {
            self.bottom.store(t + 1, SeqCst);
            return Some(data);
        } else {
            self.bottom.store(t + 1, SeqCst);
            forget(data); // someone else stole this value
            return None;
        }
    }

    unsafe fn steal(&self) -> Stolen<T> {
        let t = self.top.load(SeqCst);
        let old = self.array.load(SeqCst);
        let b = self.bottom.load(SeqCst);
        let a = self.array.load(SeqCst);
        let size = b - t;
        if size <= 0 { return Empty }
        if size % (*a).size() == 0 {
            if a == old && t == self.top.load(SeqCst) {
                return Empty
            }
            return Abort
        }
        let data = (*a).get(t);
        if self.top.compare_and_swap(t, t + 1, SeqCst) == t {
            Data(data)
        } else {
            forget(data); // someone else stole this value
            Abort
        }
    }

    unsafe fn maybe_shrink(&self, b: isize, t: isize) {
        let a = self.array.load(SeqCst);
        if b - t < (*a).size() / K && b - t > (1 << MIN_BITS) {
            self.swap_buffer(b, a, (*a).resize(b, t, -1));
        }
    }

    // Helper routine not mentioned in the paper which is used in growing and
    // shrinking buffers to swap in a new buffer into place. As a bit of a
    // recap, the whole point that we need a buffer pool rather than just
    // calling malloc/free directly is that stealers can continue using buffers
    // after this method has called 'free' on it. The continued usage is simply
    // a read followed by a forget, but we must make sure that the memory can
    // continue to be read after we flag this buffer for reclamation.
    unsafe fn swap_buffer(&self, b: isize, old: *mut Buffer<T>,
                          buf: Buffer<T>) -> *mut Buffer<T> {
        let newbuf: *mut Buffer<T> = transmute(Box::new(buf));
        self.array.store(newbuf, SeqCst);
        let ss = (*newbuf).size();
        self.bottom.store(b + ss, SeqCst);
        let t = self.top.load(SeqCst);
        if self.top.compare_and_swap(t, t + ss, SeqCst) != t {
            self.bottom.store(b, SeqCst);
        }
        self.pool.free(transmute(old));
        return newbuf;
    }
}

#[unsafe_destructor]
impl<T: Send + 'static> Drop for Deque<T> {
    fn drop(&mut self) {
        let t = self.top.load(SeqCst);
        let b = self.bottom.load(SeqCst);
        let a = self.array.load(SeqCst);
        // Free whatever is leftover in the dequeue, and then move the buffer
        // back into the pool.
        for i in range(t, b) {
            let _: T = unsafe { (*a).get(i) };
        }
        self.pool.free(unsafe { transmute(a) });
    }
}

#[inline]
fn buffer_alloc_size<T>(log_size: usize) -> usize {
    (1 << log_size) * size_of::<T>()
}

impl<T: Send> Buffer<T> {
    unsafe fn new(log_size: usize) -> Buffer<T> {
        let size = buffer_alloc_size::<T>(log_size);
        let buffer = allocate(size, min_align_of::<T>());
        if buffer.is_null() { ::alloc::oom() }
        Buffer {
            storage: buffer as *const T,
            log_size: log_size,
        }
    }

    fn size(&self) -> isize { 1 << self.log_size }

    // Apparently LLVM cannot optimize (foo % (1 << bar)) into this implicitly
    fn mask(&self) -> isize { (1 << self.log_size) - 1 }

    unsafe fn elem(&self, i: isize) -> *const T {
        self.storage.offset(i & self.mask())
    }

    // This does not protect against loading duplicate values of the same cell,
    // nor does this clear out the contents contained within. Hence, this is a
    // very unsafe method which the caller needs to treat specially in case a
    // race is lost.
    unsafe fn get(&self, i: isize) -> T {
        ptr::read(self.elem(i))
    }

    // Unsafe because this unsafely overwrites possibly uninitialized or
    // initialized data.
    unsafe fn put(&self, i: isize, t: T) {
        ptr::write(self.elem(i) as *mut T, t);
    }

    // Again, unsafe because this has incredibly dubious ownership violations.
    // It is assumed that this buffer is immediately dropped.
    unsafe fn resize(&self, b: isize, t: isize, delta: isize) -> Buffer<T> {
        // NB: not entirely obvious, but thanks to 2's complement,
        // casting delta to usize and then adding gives the desired
        // effect.
        let buf = Buffer::new(self.log_size + delta as usize);
        for i in range(t, b) {
            buf.put(i, self.get(i));
        }
        return buf;
    }
}

#[unsafe_destructor]
impl<T: Send> Drop for Buffer<T> {
    fn drop(&mut self) {
        // It is assumed that all buffers are empty on drop.
        let size = buffer_alloc_size::<T>(self.log_size);
        unsafe { deallocate(self.storage as *mut u8, size, min_align_of::<T>()) }
    }
}
<commit_msg>Remove now-unneeded 'static constraints.<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A (mostly) lock-free concurrent work-stealing deque
//!
//! This module contains an implementation of the Chase-Lev work stealing deque
//! described in "Dynamic Circular Work-Stealing Deque". The implementation is
//! heavily based on the pseudocode found in the paper.
//!
//! This implementation does not want to have the restriction of a garbage
//! collector for reclamation of buffers, and instead it uses a shared pool of
//! buffers. This shared pool is required for correctness in this
//! implementation.
//!
//! The only lock-synchronized portions of this deque are the buffer allocation
//! and deallocation portions. Otherwise all operations are lock-free.
//!
//! # Example
//!
//!     use deque::BufferPool;
//!
//!     let mut pool = BufferPool::new();
//!     let (mut worker, mut stealer) = pool.deque();
//!
//!     // Only the worker may push/pop
//!     worker.push(1i);
//!     worker.pop();
//!
//!     // Stealers take data from the other end of the deque
//!     worker.push(1i);
//!     stealer.steal();
//!
//!     // Stealers can be cloned to have many stealers stealing in parallel
//!     worker.push(1i);
//!     let mut stealer2 = stealer.clone();
//!     stealer2.steal();

#![feature(alloc)]
#![feature(core)]
#![feature(unsafe_destructor)]

extern crate alloc;
extern crate core;

// NB: the "buffer pool" strategy is not done for speed, but rather for
//     correctness. For more info, see the comment on `swap_buffer`

// FIXME: all atomic operations in this module use a SeqCst ordering. That is
//      probably overkill

pub use self::Stolen::*;

use std::sync::{Arc, Mutex};
use alloc::heap::{allocate, deallocate};
use std::boxed::Box;
use std::vec::Vec;
use std::mem::{forget, min_align_of, size_of, transmute};
use core::ptr;

use std::sync::atomic::{AtomicIsize, AtomicPtr};
use std::sync::atomic::Ordering::SeqCst;

// Once the queue is less than 1/K full, then it will be downsized. Note that
// the deque requires that this number be less than 2.
static K: isize = 4;

// Minimum number of bits that a buffer size should be. No buffer will resize to
// under this value, and all deques will initially contain a buffer of this
// size.
//
// The size in question is 1 << MIN_BITS
static MIN_BITS: usize = 7;

struct Deque<T> {
    bottom: AtomicIsize,
    top: AtomicIsize,
    array: AtomicPtr<Buffer<T>>,
    pool: BufferPool<T>,
}

/// Worker half of the work-stealing deque. This worker has exclusive access to
/// one side of the deque, and uses `push` and `pop` method to manipulate it.
///
/// There may only be one worker per deque.
pub struct Worker<T> {
    deque: Arc<Deque<T>>,
}

/// The stealing half of the work-stealing deque. Stealers have access to the
/// opposite end of the deque from the worker, and they only have access to the
/// `steal` method.
pub struct Stealer<T> {
    deque: Arc<Deque<T>>,
}

/// When stealing some data, this is an enumeration of the possible outcomes.
#[derive(PartialEq, Debug)]
pub enum Stolen<T> {
    /// The deque was empty at the time of stealing
    Empty,
    /// The stealer lost the race for stealing data, and a retry may return more
    /// data.
    Abort,
    /// The stealer has successfully stolen some data.
    Data(T),
}

/// The allocation pool for buffers used by work-stealing deques. Right now this
/// structure is used for reclamation of memory after it is no longer in use by
/// deques.
///
/// This data structure is protected by a mutex, but it is rarely used. Deques
/// will only use this structure when allocating a new buffer or deallocating a
/// previous one.
pub struct BufferPool<T> {
    pool: Arc<Mutex<Vec<Box<Buffer<T>>>>>,
}

/// An internal buffer used by the chase-lev deque. This structure is actually
/// implemented as a circular buffer, and is used as the intermediate storage of
/// the data in the deque.
///
/// This type is implemented with *T instead of Vec<T> for two reasons:
///
///   1. There is nothing safe about using this buffer. This easily allows the
///      same value to be read twice in to rust, and there is nothing to
///      prevent this. The usage by the deque must ensure that one of the
///      values is forgotten. Furthermore, we only ever want to manually run
///      destructors for values in this buffer (on drop) because the bounds
///      are defined by the deque it's owned by.
///
///   2. We can certainly avoid bounds checks using *T instead of Vec<T>, although
///      LLVM is probably pretty good at doing this already.
struct Buffer<T> {
    storage: *const T,
    log_size: usize,
}

unsafe impl<T: Send> Send for Buffer<T> { }

impl<T: Send> BufferPool<T> {
    /// Allocates a new buffer pool which in turn can be used to allocate new
    /// deques.
    pub fn new() -> BufferPool<T> {
        BufferPool { pool: Arc::new(Mutex::new(Vec::new())) }
    }

    /// Allocates a new work-stealing deque which will send/receiving memory to
    /// and from this buffer pool.
    pub fn deque(&self) -> (Worker<T>, Stealer<T>) {
        let a = Arc::new(Deque::new(self.clone()));
        let b = a.clone();
        (Worker { deque: a }, Stealer { deque: b })
    }

    fn alloc(&mut self, bits: usize) -> Box<Buffer<T>> {
        unsafe {
            let mut pool = self.pool.lock().unwrap();
            match pool.iter().position(|x| x.size() >= (1 << bits)) {
                Some(i) => pool.remove(i),
                None => Box::new(Buffer::new(bits))
            }
        }
    }

    fn free(&self, buf: Box<Buffer<T>>) {
        let mut pool = self.pool.lock().unwrap();
        match pool.iter().position(|v| v.size() > buf.size()) {
            Some(i) => pool.insert(i, buf),
            None => pool.push(buf),
        }
    }
}

impl<T: Send> Clone for BufferPool<T> {
    fn clone(&self) -> BufferPool<T> { BufferPool { pool: self.pool.clone() } }
}

impl<T: Send> Worker<T> {
    /// Pushes data onto the front of this work queue.
    pub fn push(&self, t: T) {
        unsafe { self.deque.push(t) }
    }
    /// Pops data off the front of the work queue, returning `None` on an empty
    /// queue.
    pub fn pop(&self) -> Option<T> {
        unsafe { self.deque.pop() }
    }

    /// Gets access to the buffer pool that this worker is attached to. This can
    /// be used to create more deques which share the same buffer pool as this
    /// deque.
    pub fn pool<'a>(&'a self) -> &'a BufferPool<T> {
        &self.deque.pool
    }
}

impl<T: Send> Stealer<T> {
    /// Steals work off the end of the queue (opposite of the worker's end)
    pub fn steal(&self) -> Stolen<T> {
        unsafe { self.deque.steal() }
    }

    /// Gets access to the buffer pool that this stealer is attached to. This
    /// can be used to create more deques which share the same buffer pool as
    /// this deque.
    pub fn pool<'a>(&'a self) -> &'a BufferPool<T> {
        &self.deque.pool
    }
}

impl<T: Send> Clone for Stealer<T> {
    fn clone(&self) -> Stealer<T> {
        Stealer { deque: self.deque.clone() }
    }
}

// Almost all of this code can be found directly in the paper so I'm not
// personally going to heavily comment what's going on here.

impl<T: Send> Deque<T> {
    fn new(mut pool: BufferPool<T>) -> Deque<T> {
        let buf = pool.alloc(MIN_BITS);
        Deque {
            bottom: AtomicIsize::new(0),
            top: AtomicIsize::new(0),
            array: AtomicPtr::new(unsafe { transmute(buf) }),
            pool: pool,
        }
    }

    unsafe fn push(&self, data: T) {
        let mut b = self.bottom.load(SeqCst);
        let t = self.top.load(SeqCst);
        let mut a = self.array.load(SeqCst);
        let size = b - t;
        if size >= (*a).size() - 1 {
            // You won't find this code in the chase-lev deque paper. This is
            // alluded to in a small footnote, however. We always free a buffer
            // when growing in order to prevent leaks.
            a = self.swap_buffer(b, a, (*a).resize(b, t, 1));
            b = self.bottom.load(SeqCst);
        }
        (*a).put(b, data);
        self.bottom.store(b + 1, SeqCst);
    }

    unsafe fn pop(&self) -> Option<T> {
        let b = self.bottom.load(SeqCst);
        let a = self.array.load(SeqCst);
        let b = b - 1;
        self.bottom.store(b, SeqCst);
        let t = self.top.load(SeqCst);
        let size = b - t;
        if size < 0 {
            self.bottom.store(t, SeqCst);
            return None;
        }
        let data = (*a).get(b);
        if size > 0 {
            self.maybe_shrink(b, t);
            return Some(data);
        }
        if self.top.compare_and_swap(t, t + 1, SeqCst) == t {
            self.bottom.store(t + 1, SeqCst);
            return Some(data);
        } else {
            self.bottom.store(t + 1, SeqCst);
            forget(data); // someone else stole this value
            return None;
        }
    }

    unsafe fn steal(&self) -> Stolen<T> {
        let t = self.top.load(SeqCst);
        let old = self.array.load(SeqCst);
        let b = self.bottom.load(SeqCst);
        let a = self.array.load(SeqCst);
        let size = b - t;
        if size <= 0 { return Empty }
        if size % (*a).size() == 0 {
            if a == old && t == self.top.load(SeqCst) {
                return Empty
            }
            return Abort
        }
        let data = (*a).get(t);
        if self.top.compare_and_swap(t, t + 1, SeqCst) == t {
            Data(data)
        } else {
            forget(data); // someone else stole this value
            Abort
        }
    }

    unsafe fn maybe_shrink(&self, b: isize, t: isize) {
        let a = self.array.load(SeqCst);
        if b - t < (*a).size() / K && b - t > (1 << MIN_BITS) {
            self.swap_buffer(b, a, (*a).resize(b, t, -1));
        }
    }

    // Helper routine not mentioned in the paper which is used in growing and
    // shrinking buffers to swap in a new buffer into place. As a bit of a
    // recap, the whole point that we need a buffer pool rather than just
    // calling malloc/free directly is that stealers can continue using buffers
    // after this method has called 'free' on it. The continued usage is simply
    // a read followed by a forget, but we must make sure that the memory can
    // continue to be read after we flag this buffer for reclamation.
    unsafe fn swap_buffer(&self, b: isize, old: *mut Buffer<T>,
                          buf: Buffer<T>) -> *mut Buffer<T> {
        let newbuf: *mut Buffer<T> = transmute(Box::new(buf));
        self.array.store(newbuf, SeqCst);
        let ss = (*newbuf).size();
        self.bottom.store(b + ss, SeqCst);
        let t = self.top.load(SeqCst);
        if self.top.compare_and_swap(t, t + ss, SeqCst) != t {
            self.bottom.store(b, SeqCst);
        }
        self.pool.free(transmute(old));
        return newbuf;
    }
}

#[unsafe_destructor]
impl<T: Send> Drop for Deque<T> {
    fn drop(&mut self) {
        let t = self.top.load(SeqCst);
        let b = self.bottom.load(SeqCst);
        let a = self.array.load(SeqCst);
        // Free whatever is leftover in the dequeue, and then move the buffer
        // back into the pool.
        for i in range(t, b) {
            let _: T = unsafe { (*a).get(i) };
        }
        self.pool.free(unsafe { transmute(a) });
    }
}

#[inline]
fn buffer_alloc_size<T>(log_size: usize) -> usize {
    (1 << log_size) * size_of::<T>()
}

impl<T: Send> Buffer<T> {
    unsafe fn new(log_size: usize) -> Buffer<T> {
        let size = buffer_alloc_size::<T>(log_size);
        let buffer = allocate(size, min_align_of::<T>());
        if buffer.is_null() { ::alloc::oom() }
        Buffer {
            storage: buffer as *const T,
            log_size: log_size,
        }
    }

    fn size(&self) -> isize { 1 << self.log_size }

    // Apparently LLVM cannot optimize (foo % (1 << bar)) into this implicitly
    fn mask(&self) -> isize { (1 << self.log_size) - 1 }

    unsafe fn elem(&self, i: isize) -> *const T {
        self.storage.offset(i & self.mask())
    }

    // This does not protect against loading duplicate values of the same cell,
    // nor does this clear out the contents contained within. Hence, this is a
    // very unsafe method which the caller needs to treat specially in case a
    // race is lost.
    unsafe fn get(&self, i: isize) -> T {
        ptr::read(self.elem(i))
    }

    // Unsafe because this unsafely overwrites possibly uninitialized or
    // initialized data.
    unsafe fn put(&self, i: isize, t: T) {
        ptr::write(self.elem(i) as *mut T, t);
    }

    // Again, unsafe because this has incredibly dubious ownership violations.
    // It is assumed that this buffer is immediately dropped.
    unsafe fn resize(&self, b: isize, t: isize, delta: isize) -> Buffer<T> {
        // NB: not entirely obvious, but thanks to 2's complement,
        // casting delta to usize and then adding gives the desired
        // effect.
        let buf = Buffer::new(self.log_size + delta as usize);
        for i in range(t, b) {
            buf.put(i, self.get(i));
        }
        return buf;
    }
}

#[unsafe_destructor]
impl<T: Send> Drop for Buffer<T> {
    fn drop(&mut self) {
        // It is assumed that all buffers are empty on drop.
        let size = buffer_alloc_size::<T>(self.log_size);
        unsafe { deallocate(self.storage as *mut u8, size, min_align_of::<T>()) }
    }
}
<|endoftext|>


<commit_before>//! The `ipnetwork` crate provides a set of APIs to work with IP CIDRs in
//! Rust. Implementation for IPv4 is more or less stable, IPv6 implementation
//! is still WIP.
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]
#![crate_type = "lib"]

use std::fmt;
use std::net::IpAddr;

mod ipv4;
mod ipv6;
mod common;

use std::str::FromStr;

pub use ipv4::{Ipv4Network, ipv4_mask_to_prefix};
pub use ipv6::{Ipv6Network, ipv6_mask_to_prefix};
pub use common::IpNetworkError;

/// Represents a generic network range. This type can have two variants:
/// the v4 and the v6 case.
#[derive(Debug,Clone,Copy,Hash,PartialEq,Eq)]
pub enum IpNetwork {
    V4(Ipv4Network),
    V6(Ipv6Network),
}

impl IpNetwork {
    /// Constructs a new `IpNetwork` from a given `IpAddr` and a prefix denoting the
    /// network size. If the prefix is larger than 32 (for IPv4) or 128 (for IPv6), this
    /// will raise an `IpNetworkError::InvalidPrefix` error. Support for IPv6 is not
    /// complete yet.
    pub fn new(ip: IpAddr, prefix: u8) -> Result<IpNetwork, IpNetworkError> {
        match ip {
            IpAddr::V4(a) => Ok(IpNetwork::V4(Ipv4Network::new(a, prefix)?)),
            IpAddr::V6(a) => Ok(IpNetwork::V6(Ipv6Network::new(a, prefix)?)),
        }
    }

    /// Returns the IP part of a given `IpNetwork`
    pub fn ip(&self) -> IpAddr {
        match *self {
            IpNetwork::V4(ref a) => IpAddr::V4(a.ip()),
            IpNetwork::V6(ref a) => IpAddr::V6(a.ip()),
        }
    }

    /// Returns the prefix of the given `IpNetwork`
    ///
    /// # Example
    /// ```
    /// use ipnetwork::IpNetwork;
    ///
    /// assert_eq!(IpNetwork::V4("10.9.0.32/16".parse().unwrap()).prefix(), 16u8);
    /// assert_eq!(IpNetwork::V6("ff01::0/32".parse().unwrap()).prefix(), 32u8);
    /// ```
    pub fn prefix(&self) -> u8 {
        match *self {
            IpNetwork::V4(ref a) => a.prefix(),
            IpNetwork::V6(ref a) => a.prefix(),
        }
    }

    /// Returns the mask of the given `IpNetwork`
    ///
    /// # Example
    /// ```
    /// use ipnetwork::IpNetwork;
    ///
    /// assert_eq!(IpNetwork::V4("10.9.0.32/16".parse().unwrap()).mask(), 16u8);
    /// assert_eq!(IpNetwork::V6("ff01::0/32".parse().unwrap()).mask(), 32u8);
    ///```
    pub fn mask(&self) -> IpAddr {
        match *self {
            IpNetwork::V4(ref a) => IpAddr::V4(a.mask()),
            IpNetwork::V6(ref a) => IpAddr::V6(a.mask()),
        }
    }

    /// Returns true if the IP in this `IpNetwork` is a valid IPv4 address,
    /// false if it's a valid IPv6 address.
    ///
    /// # Example
    ///
    ///```
    /// use ipnetwork::IpNetwork;
    ///
    /// let v4: IpNetwork = IpNetwork::V4("10.9.0.32/16".parse().unwrap());
    /// assert_eq!(v4.is_ipv4(), true);
    /// assert_eq!(v4.is_ipv6(), false);
    ///```
    pub fn is_ipv4(&self) -> bool {
        match *self {
            IpNetwork::V4(_) => true,
            IpNetwork::V6(_) => false,
        }
    }

    /// Returns true if the IP in this `IpNetwork` is a valid IPv6 address,
    /// false if it's a valid IPv4 address.
    ///
    /// # Example
    ///
    ///```
    /// use ipnetwork::IpNetwork;
    ///
    /// let v6: IpNetwork = IpNetwork::V6("ff01::0/32".parse().unwrap());
    /// assert_eq!(v6.is_ipv6(), true);
    /// assert_eq!(v6.is_ipv4(), false);
    ///```
    pub fn is_ipv6(&self) -> bool {
        match *self {
            IpNetwork::V4(_) => false,
            IpNetwork::V6(_) => true,
        }
    }
}

/// Constructs a new `IpNetwork` from a given &str with a prefix denoting the
/// network size.  If the prefix is larger than 32 (for IPv4) or 128 (for IPv6), this
/// will raise an `IpNetworkError::InvalidPrefix` error.
/// # Examples
///
/// ```
/// use std::net::Ipv4Addr;
/// use ipnetwork::Ipv4Network;
/// use ipnetwork::IpNetwork;
///
/// let expected = IpNetwork::V4(Ipv4Network::new(Ipv4Addr::new(10, 1, 9, 32), 16).unwrap());
/// let from_cidr: IpNetwork = "10.1.9.32/16".parse().unwrap();
/// assert_eq!(expected.ip(), from_cidr.ip());
/// assert_eq!(expected.prefix(), from_cidr.prefix());
impl FromStr for IpNetwork {
    type Err = IpNetworkError;
    fn from_str(s: &str) -> Result<IpNetwork, IpNetworkError> {
        let v4addr: Result<Ipv4Network, IpNetworkError> = s.parse();
        let v6addr: Result<Ipv6Network, IpNetworkError> = s.parse();

        if v4addr.is_ok() {
            Ok(IpNetwork::V4(v4addr.unwrap()))
        } else if v6addr.is_ok() {
            Ok(IpNetwork::V6(v6addr.unwrap()))
        } else {
            Err(IpNetworkError::InvalidAddr(s.to_string()))
        }
    }
}

impl From<Ipv4Network> for IpNetwork {
    fn from(v4: Ipv4Network) -> IpNetwork {
        IpNetwork::V4(v4)
    }
}

impl From<Ipv6Network> for IpNetwork {
    fn from(v6: Ipv6Network) -> IpNetwork {
        IpNetwork::V6(v6)
    }
}

impl fmt::Display for IpNetwork {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            IpNetwork::V4(net) => net.fmt(f),
            IpNetwork::V6(net) => net.fmt(f),
        }
    }
}

/// Converts a `IpAddr` network mask into a prefix.
/// If the mask is invalid this will return an `IpNetworkError::InvalidPrefix`.
pub fn ip_mask_to_prefix(mask: IpAddr) -> Result<u8, IpNetworkError> {
    match mask {
        IpAddr::V4(mask) => ipv4_mask_to_prefix(mask),
        IpAddr::V6(mask) => ipv6_mask_to_prefix(mask),
    }
}
<commit_msg>Fix failing doc test<commit_after>//! The `ipnetwork` crate provides a set of APIs to work with IP CIDRs in
//! Rust. Implementation for IPv4 is more or less stable, IPv6 implementation
//! is still WIP.
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]
#![crate_type = "lib"]

use std::fmt;
use std::net::IpAddr;

mod ipv4;
mod ipv6;
mod common;

use std::str::FromStr;

pub use ipv4::{Ipv4Network, ipv4_mask_to_prefix};
pub use ipv6::{Ipv6Network, ipv6_mask_to_prefix};
pub use common::IpNetworkError;

/// Represents a generic network range. This type can have two variants:
/// the v4 and the v6 case.
#[derive(Debug,Clone,Copy,Hash,PartialEq,Eq)]
pub enum IpNetwork {
    V4(Ipv4Network),
    V6(Ipv6Network),
}

impl IpNetwork {
    /// Constructs a new `IpNetwork` from a given `IpAddr` and a prefix denoting the
    /// network size. If the prefix is larger than 32 (for IPv4) or 128 (for IPv6), this
    /// will raise an `IpNetworkError::InvalidPrefix` error. Support for IPv6 is not
    /// complete yet.
    pub fn new(ip: IpAddr, prefix: u8) -> Result<IpNetwork, IpNetworkError> {
        match ip {
            IpAddr::V4(a) => Ok(IpNetwork::V4(Ipv4Network::new(a, prefix)?)),
            IpAddr::V6(a) => Ok(IpNetwork::V6(Ipv6Network::new(a, prefix)?)),
        }
    }

    /// Returns the IP part of a given `IpNetwork`
    pub fn ip(&self) -> IpAddr {
        match *self {
            IpNetwork::V4(ref a) => IpAddr::V4(a.ip()),
            IpNetwork::V6(ref a) => IpAddr::V6(a.ip()),
        }
    }

    /// Returns the prefix of the given `IpNetwork`
    ///
    /// # Example
    /// ```
    /// use ipnetwork::IpNetwork;
    ///
    /// assert_eq!(IpNetwork::V4("10.9.0.32/16".parse().unwrap()).prefix(), 16u8);
    /// assert_eq!(IpNetwork::V6("ff01::0/32".parse().unwrap()).prefix(), 32u8);
    /// ```
    pub fn prefix(&self) -> u8 {
        match *self {
            IpNetwork::V4(ref a) => a.prefix(),
            IpNetwork::V6(ref a) => a.prefix(),
        }
    }

    /// Returns the mask for this `IpNetwork`
    /// That means the `prefix` most significant bits will be 1 and the rest 0
    ///
    /// # Example
    /// ```
    /// use ipnetwork::IpNetwork;
    /// use std::net::{Ipv4Addr, Ipv6Addr};
    ///
    /// let v4_net: IpNetwork = "10.9.0.32/16".parse().unwrap();
    /// assert_eq!(v4_net.mask(), Ipv4Addr::new(255, 255, 0, 0));
    /// let v6_net: IpNetwork = "ff01::0/32".parse().unwrap();
    /// assert_eq!(v6_net.mask(), Ipv6Addr::new(0xffff, 0xffff, 0, 0, 0, 0, 0, 0));
    ///```
    pub fn mask(&self) -> IpAddr {
        match *self {
            IpNetwork::V4(ref a) => IpAddr::V4(a.mask()),
            IpNetwork::V6(ref a) => IpAddr::V6(a.mask()),
        }
    }

    /// Returns true if the IP in this `IpNetwork` is a valid IPv4 address,
    /// false if it's a valid IPv6 address.
    ///
    /// # Example
    ///
    ///```
    /// use ipnetwork::IpNetwork;
    ///
    /// let v4: IpNetwork = IpNetwork::V4("10.9.0.32/16".parse().unwrap());
    /// assert_eq!(v4.is_ipv4(), true);
    /// assert_eq!(v4.is_ipv6(), false);
    ///```
    pub fn is_ipv4(&self) -> bool {
        match *self {
            IpNetwork::V4(_) => true,
            IpNetwork::V6(_) => false,
        }
    }

    /// Returns true if the IP in this `IpNetwork` is a valid IPv6 address,
    /// false if it's a valid IPv4 address.
    ///
    /// # Example
    ///
    ///```
    /// use ipnetwork::IpNetwork;
    ///
    /// let v6: IpNetwork = IpNetwork::V6("ff01::0/32".parse().unwrap());
    /// assert_eq!(v6.is_ipv6(), true);
    /// assert_eq!(v6.is_ipv4(), false);
    ///```
    pub fn is_ipv6(&self) -> bool {
        match *self {
            IpNetwork::V4(_) => false,
            IpNetwork::V6(_) => true,
        }
    }
}

/// Constructs a new `IpNetwork` from a given &str with a prefix denoting the
/// network size.  If the prefix is larger than 32 (for IPv4) or 128 (for IPv6), this
/// will raise an `IpNetworkError::InvalidPrefix` error.
/// # Examples
///
/// ```
/// use std::net::Ipv4Addr;
/// use ipnetwork::Ipv4Network;
/// use ipnetwork::IpNetwork;
///
/// let expected = IpNetwork::V4(Ipv4Network::new(Ipv4Addr::new(10, 1, 9, 32), 16).unwrap());
/// let from_cidr: IpNetwork = "10.1.9.32/16".parse().unwrap();
/// assert_eq!(expected.ip(), from_cidr.ip());
/// assert_eq!(expected.prefix(), from_cidr.prefix());
impl FromStr for IpNetwork {
    type Err = IpNetworkError;
    fn from_str(s: &str) -> Result<IpNetwork, IpNetworkError> {
        let v4addr: Result<Ipv4Network, IpNetworkError> = s.parse();
        let v6addr: Result<Ipv6Network, IpNetworkError> = s.parse();

        if v4addr.is_ok() {
            Ok(IpNetwork::V4(v4addr.unwrap()))
        } else if v6addr.is_ok() {
            Ok(IpNetwork::V6(v6addr.unwrap()))
        } else {
            Err(IpNetworkError::InvalidAddr(s.to_string()))
        }
    }
}

impl From<Ipv4Network> for IpNetwork {
    fn from(v4: Ipv4Network) -> IpNetwork {
        IpNetwork::V4(v4)
    }
}

impl From<Ipv6Network> for IpNetwork {
    fn from(v6: Ipv6Network) -> IpNetwork {
        IpNetwork::V6(v6)
    }
}

impl fmt::Display for IpNetwork {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            IpNetwork::V4(net) => net.fmt(f),
            IpNetwork::V6(net) => net.fmt(f),
        }
    }
}

/// Converts a `IpAddr` network mask into a prefix.
/// If the mask is invalid this will return an `IpNetworkError::InvalidPrefix`.
pub fn ip_mask_to_prefix(mask: IpAddr) -> Result<u8, IpNetworkError> {
    match mask {
        IpAddr::V4(mask) => ipv4_mask_to_prefix(mask),
        IpAddr::V6(mask) => ipv6_mask_to_prefix(mask),
    }
}
<|endoftext|>