<commit_before>use std::thread;
use std::sync::mpsc;
use websocket;
use websocket::{Message, Sender, Receiver};
use websocket::server::sender;
use websocket::stream::WebSocketStream;
use websocket::message::CloseData;
use std::io::prelude::*;
use std::fs::{OpenOptions};
use std::net::Shutdown;
use rustc_serialize::json::{Json, ToJson};
use cbor;
use hyper::header::Cookie;

use value::Value;
use relation::Change;
use flow::{Changes, Flow};

// The server manages a single Eve program and handles communication with the editor and clients
// TODO needs review / refactoring, especially session handling

pub struct Server {
    pub flow: Flow,
    pub senders: Vec<sender::Sender<WebSocketStream>>,
}

#[derive(Debug, Clone)]
pub struct Event {
    pub changes: Changes,
    pub session: String,
    // commands that affect the whole program state have to go through this side-channel rather than being added to a view
    // supported commands: ["load", filename], ["save", filename]
    pub commands: Vec<Vec<String>>,
}

pub enum ServerEvent {
    Change(Vec<u8>),
    Sync((sender::Sender<WebSocketStream>, Option<String>)),
    Terminate(Option<CloseData>),
}

// --- json encodings ---

pub trait FromJson {
    fn from_json(json: &Json) -> Self;
}

impl ToJson for Value {
    fn to_json(&self) -> Json {
        match *self {
            Value::Null => panic!("Cannot allow the client to see nulls"),
            Value::Bool(bool) => Json::Boolean(bool),
            Value::String(ref string) => Json::String(string.clone()),
            Value::Float(float) => Json::F64(float),
            Value::Column(ref column) => Json::Array(column.iter().map(|v| v.to_json()).collect()),
        }
    }
}

impl FromJson for Value {
    fn from_json(json: &Json) -> Self {
        match *json {
            Json::Boolean(bool) => Value::Bool(bool),
            Json::String(ref string) => Value::String(string.clone()),
            Json::F64(float) => Value::Float(float),
            Json::I64(int) => Value::Float(int as f64),
            Json::U64(uint) => Value::Float(uint as f64),
            Json::Array(ref array) => Value::Column(array.iter().map(FromJson::from_json).collect()),
            _ => panic!("Cannot decode {:?} as Value", json),
        }
    }
}

impl FromJson for String {
    fn from_json(json: &Json) -> Self {
        json.as_string().unwrap().to_owned()
    }
}

impl<T: FromJson> FromJson for Vec<T> {
    fn from_json(json: &Json) -> Self {
        json.as_array().unwrap().iter().map(|t| FromJson::from_json(t)).collect()
    }
}

impl ToJson for Event {
    fn to_json(&self) -> Json {
        Json::Object(vec![
            ("changes".to_string(), Json::Array(
                self.changes.iter().map(|&(ref view_id, ref view_changes)| {
                    Json::Array(vec![
                        view_id.to_json(),
                        view_changes.fields.to_json(),
                        view_changes.insert.to_json(),
                        view_changes.remove.to_json(),
                        ])
                }).collect()
                )
            ),
            ("session".to_string(), self.session.to_json()),
            ("commands".to_string(), self.commands.to_json()),
        ].into_iter().collect())
    }
}

impl FromJson for Event {
    fn from_json(json: &Json) -> Self {
        Event{
            changes: json.as_object().unwrap()["changes"]
            .as_array().unwrap().iter().map(|change| {
                let change = change.as_array().unwrap();
                assert_eq!(change.len(), 4);
                let view_id = FromJson::from_json(&change[0]);
                let fields = FromJson::from_json(&change[1]);
                let insert = FromJson::from_json(&change[2]);
                let remove = FromJson::from_json(&change[3]);
                (view_id, Change{fields:fields, insert: insert, remove: remove})
            }).collect(),
            session: "".to_string(),
            commands: FromJson::from_json(json.as_object().unwrap().get("commands").unwrap_or(&Json::Array(vec![]))),
        }
    }
}

// --- persistence ---

pub fn load(flow: &mut Flow, filename: &str) {
    let mut events = OpenOptions::new().create(true).open(filename).unwrap();
    let mut old_events = String::new();
    events.read_to_string(&mut old_events).unwrap();
    for line in old_events.lines() {
        let json = Json::from_str(&line).unwrap();
        let event: Event = FromJson::from_json(&json);
        flow.quiesce(event.changes);
    }
}

// TODO should probably just save changes, not the whole event
pub fn save(flow: &Flow, filename: &str) {
    let changes = flow.as_changes();
    let text = format!("{}", Event{changes: changes, session: "".to_owned(), commands: vec![]}.to_json());
    let mut events = OpenOptions::new().create(true).truncate(true).write(true).open(filename).unwrap();
    events.write_all(text.as_bytes()).unwrap();
}

// --- server ---

pub fn get_user_id(cookies: Option<&Cookie>) -> Option<String> {
    match cookies {
        Some(cookies) => {
            match cookies.iter().find(|cookie| cookie.name == "userid") {
                Some(user_id) => Some(user_id.value.clone()),
                None => None,
            }
        },
        None => None,
    }
}

// rust-websocket is blocking, so we have to spawn a thread per connection
// each thread sends events back to a central channel
pub fn server_events() -> mpsc::Receiver<ServerEvent> {
    let (event_sender, event_receiver) = mpsc::channel();
    thread::spawn(move || {
        let server = websocket::Server::bind("0.0.0.0:2794").unwrap();
        for connection in server {
            let event_sender = event_sender.clone();
            thread::spawn(move || {
                // accept request
                let request = connection.unwrap().read_request().unwrap();
                request.validate().unwrap();

                // get the User ID from a cookie in the headers
                let user_id = get_user_id(request.headers.get::<Cookie>());

                let response = request.accept();
                let (mut sender, mut receiver) = response.send().unwrap().split();

                let ip = sender.get_mut().peer_addr().unwrap();
                println!("Connection from {}", ip);
                ::std::io::stdout().flush().unwrap(); // TODO is this actually necessary?

                // hand over the sender
                event_sender.send(ServerEvent::Sync((sender,user_id))).unwrap();

                // handle messages
                for message in receiver.incoming_messages() {
                    let message = match message {
                        Ok(m) => m,
                        Err(_) => return,
                    };
                    match message {
                        Message::Binary(bytes) => {
                            event_sender.send(ServerEvent::Change(bytes)).unwrap();
                        }
                        Message::Close(_) => {
                            let ip_addr = format!("{}", ip);
                            println!("Received close message from {}.",ip_addr);
                            let close_message = CloseData{status_code: 0, reason: ip_addr};
                            event_sender.send(ServerEvent::Terminate(Some(close_message))).unwrap();
                        }
                        _ => println!("Unknown message: {:?}", message)
                    }
                }
            });
        }
    });
    event_receiver
}

pub fn handle_event(server: &mut Server, event: Event, event_json: Json) {
    // save the event
    let mut autosave = OpenOptions::new().write(true).append(true).open("./autosave").unwrap();
    autosave.write_all(format!("{}", event_json).as_bytes()).unwrap();
    autosave.write_all("\n".as_bytes()).unwrap();
    autosave.flush().unwrap();

    // copy the old flow so we can compare to the new flow for changes
    let old_flow = server.flow.clone();

    // run the flow until it reaches fixpoint
    server.flow.quiesce(event.changes);

    // handle commands
    for command in event.commands.iter() {
        let borrowed_words = command.iter().map(|word| &word[..]).collect::<Vec<_>>();
        match &borrowed_words[..] {
            ["load", filename] => {
                server.flow = Flow::new();
                load(&mut server.flow, "./bootstrap");
                load(&mut server.flow, filename);
                save(&server.flow, "./autosave");
            }
            ["save", filename] => {
                save(&server.flow, filename);
            }
            other => panic!("Unknown command: {:?}", other),
        }
    }

    let changes = server.flow.changes_from(old_flow);
    for sender in server.senders.iter_mut() {
        let session_id = format!("{}", sender.get_mut().peer_addr().unwrap());
        let event = Event{changes: changes.clone(), session: session_id, commands: event.commands.clone()};
        let text = format!("{}", event.to_json());
        match sender.send_message(Message::Text(text)) {
            Ok(_) => (),
            Err(error) => println!("Send error: {}", error),
        };
    }
}

pub fn run() {
    let mut flow = Flow::new();
    time!("reading saved state", {
        load(&mut flow, "./bootstrap");
        load(&mut flow, "./autosave");
    });

    let senders: Vec<sender::Sender<WebSocketStream>> = Vec::new();

    let mut server = Server{flow: flow, senders: senders};

    for server_event in server_events() {
        match server_event {

            // a new client has connected and needs to sync its state
            ServerEvent::Sync((mut sender, user_id)) => {
                let mut changes = vec![];

                // add a session to the session table
                let session_id = format!("{}", sender.get_mut().peer_addr().unwrap());
                changes.push(("sessions".to_owned(),
                    Change{
                        fields: vec!["sessions: id".to_owned(), "sessions: status".to_owned()],
                        insert: vec![vec![Value::String(session_id.clone()), Value::Float(1f64)]],
                        remove: vec![],
                    }));

                // if we have a user ID, add a mapping from the session ID to the user ID
                if let Some(user_id) = user_id {
                    changes.push(("session id to user id".to_owned(),
                        Change{
                            fields: vec!["session id to user id: session id".to_owned(), "session id to user id: user id".to_owned()],
                            insert: vec![vec![Value::String(session_id.clone()), Value::String(user_id)]],
                            remove: vec![]
                        }));
                }

                // handle the session change
                let event = Event{changes: changes, session: session_id.clone(), commands: vec![]};
                let json = event.to_json();
                handle_event(&mut server, event, json);

                // sync the new client
                let changes = server.flow.as_changes();
                let event = Event{changes: changes, session: session_id, commands: vec![]};
                let text = format!("{}", event.to_json());
                match sender.send_message(Message::Text(text)) {
                    Ok(_) => (),
                    Err(error) => println!("Send error: {}", error),
                };
                server.senders.push(sender)
            }

            // an existing client has sent a new message
            ServerEvent::Change(input_bytes) => {
                // TODO we throw cbor in here to avoid https://github.com/rust-lang/rustc-serialize/issues/113
                let mut decoder = cbor::Decoder::from_bytes(&input_bytes[..]);
                let cbor = decoder.items().next().unwrap().unwrap();
                let json = cbor.to_json();
                let event = FromJson::from_json(&json);
                handle_event(&mut server, event, json);
            }

            ServerEvent::Terminate(m) => {
                let terminate_ip = m.unwrap().reason;
                println!("Closing connection from {}...",terminate_ip);

                // find the index of the connection's sender
                let ip_ix = server.senders.iter_mut().position(|mut sender| {
                    let ip = format!("{}",sender.get_mut().peer_addr().unwrap());
                    ip == terminate_ip
                });

                match ip_ix {
                    Some(ix) => {
                        // close the connection
                        let _ = server.senders[ix].send_message(Message::Close(None));
                        match server.senders[ix].get_mut().shutdown(Shutdown::Both) {
                            Ok(_) => println!("Connection from {} has closed successfully.",terminate_ip),
                            Err(e) => println!("Connection from {} failed to shut down properly: {}",terminate_ip,e),
                        }
                        server.senders.remove(ix);

                        // update the session table
                        let sessions = server.flow.get_output("sessions").clone();
                        let ip_string = Value::String(terminate_ip.clone());

                        // change the session status to 0
                        for row in sessions.find(vec![&ip_string, &Value::Null]) {
                            match row {
                                [_, ref status] => {
                                    let change = Change {
                                        fields: sessions.fields.clone(),
                                        insert: vec![vec![ip_string.clone(), Value::Float(0f64)]],
                                        remove: vec![vec![ip_string.clone(), status.clone()]],
                                    };
                                    let event = Event{changes: vec![("sessions".to_string(),change)], session: "".to_string(), commands: vec![]};
                                    let json = event.to_json();
                                    handle_event(&mut server, event, json);
                                }
                                _ => unreachable!(),
                            }
                        }

                    },
                    None => panic!("IP address {} is not connected",terminate_ip),
                }
            }
        }
    }
}<commit_msg>Add new commands to help the browser manage loading/saving<commit_after>use std::thread;
use std::sync::mpsc;
use websocket;
use websocket::{Message, Sender, Receiver};
use websocket::server::sender;
use websocket::stream::WebSocketStream;
use websocket::message::CloseData;
use std::io::prelude::*;
use std::fs::{OpenOptions};
use std::net::Shutdown;
use rustc_serialize::json::{Json, ToJson};
use cbor;
use hyper::header::Cookie;

use value::Value;
use relation::Change;
use flow::{Changes, Flow};

// The server manages a single Eve program and handles communication with the editor and clients
// TODO needs review / refactoring, especially session handling

pub struct Server {
    pub flow: Flow,
    pub senders: Vec<sender::Sender<WebSocketStream>>,
}

#[derive(Debug, Clone)]
pub struct Event {
    pub changes: Changes,
    pub session: String,
    // commands that affect the whole program state have to go through this side-channel rather than being added to a view
    // supported commands: ["load", filename], ["save", filename]
    pub commands: Vec<Vec<String>>,
}

pub enum ServerEvent {
    Change(Vec<u8>),
    Sync((sender::Sender<WebSocketStream>, Option<String>)),
    Terminate(Option<CloseData>),
}

// --- json encodings ---

pub trait FromJson {
    fn from_json(json: &Json) -> Self;
}

impl ToJson for Value {
    fn to_json(&self) -> Json {
        match *self {
            Value::Null => panic!("Cannot allow the client to see nulls"),
            Value::Bool(bool) => Json::Boolean(bool),
            Value::String(ref string) => Json::String(string.clone()),
            Value::Float(float) => Json::F64(float),
            Value::Column(ref column) => Json::Array(column.iter().map(|v| v.to_json()).collect()),
        }
    }
}

impl FromJson for Value {
    fn from_json(json: &Json) -> Self {
        match *json {
            Json::Boolean(bool) => Value::Bool(bool),
            Json::String(ref string) => Value::String(string.clone()),
            Json::F64(float) => Value::Float(float),
            Json::I64(int) => Value::Float(int as f64),
            Json::U64(uint) => Value::Float(uint as f64),
            Json::Array(ref array) => Value::Column(array.iter().map(FromJson::from_json).collect()),
            _ => panic!("Cannot decode {:?} as Value", json),
        }
    }
}

impl FromJson for String {
    fn from_json(json: &Json) -> Self {
        json.as_string().unwrap().to_owned()
    }
}

impl<T: FromJson> FromJson for Vec<T> {
    fn from_json(json: &Json) -> Self {
        json.as_array().unwrap().iter().map(|t| FromJson::from_json(t)).collect()
    }
}

impl ToJson for Event {
    fn to_json(&self) -> Json {
        Json::Object(vec![
            ("changes".to_string(), Json::Array(
                self.changes.iter().map(|&(ref view_id, ref view_changes)| {
                    Json::Array(vec![
                        view_id.to_json(),
                        view_changes.fields.to_json(),
                        view_changes.insert.to_json(),
                        view_changes.remove.to_json(),
                        ])
                }).collect()
                )
            ),
            ("session".to_string(), self.session.to_json()),
            ("commands".to_string(), self.commands.to_json()),
        ].into_iter().collect())
    }
}

impl FromJson for Event {
    fn from_json(json: &Json) -> Self {
        Event{
            changes: json.as_object().unwrap()["changes"]
            .as_array().unwrap().iter().map(|change| {
                let change = change.as_array().unwrap();
                assert_eq!(change.len(), 4);
                let view_id = FromJson::from_json(&change[0]);
                let fields = FromJson::from_json(&change[1]);
                let insert = FromJson::from_json(&change[2]);
                let remove = FromJson::from_json(&change[3]);
                (view_id, Change{fields:fields, insert: insert, remove: remove})
            }).collect(),
            session: "".to_string(),
            commands: FromJson::from_json(json.as_object().unwrap().get("commands").unwrap_or(&Json::Array(vec![]))),
        }
    }
}

// --- persistence ---

pub fn read_file(filename: &str) -> String {
    let mut file = OpenOptions::new().create(true).open(filename).unwrap();
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    contents
}

pub fn write_file(filename: &str, contents: &str) {
    let mut file = OpenOptions::new().create(true).truncate(true).write(true).open(filename).unwrap();
    file.write_all(contents.as_bytes()).unwrap();
}

pub fn load(flow: &mut Flow, filename: &str) {
    for line in read_file(filename).lines() {
        let json = Json::from_str(&line).unwrap();
        let event: Event = FromJson::from_json(&json);
        flow.quiesce(event.changes);
    }
}

// TODO should probably just save changes, not the whole event
pub fn save(flow: &Flow, filename: &str) {
    let changes = flow.as_changes();
    let text = format!("{}", Event{changes: changes, session: "".to_owned(), commands: vec![]}.to_json());
    write_file(filename, &text[..]);
}

// --- server ---

pub fn send_event(server: &mut Server, changes: &Changes, commands: &Vec<Vec<String>>) {
    for sender in server.senders.iter_mut() {
        let session_id = format!("{}", sender.get_mut().peer_addr().unwrap());
        let event = Event{changes: changes.clone(), session: session_id, commands: commands.clone()};
        let text = format!("{}", event.to_json());
        match sender.send_message(Message::Text(text)) {
            Ok(_) => (),
            Err(error) => println!("Send error: {}", error),
        };
    }
}

pub fn get_user_id(cookies: Option<&Cookie>) -> Option<String> {
    match cookies {
        Some(cookies) => {
            match cookies.iter().find(|cookie| cookie.name == "userid") {
                Some(user_id) => Some(user_id.value.clone()),
                None => None,
            }
        },
        None => None,
    }
}

// rust-websocket is blocking, so we have to spawn a thread per connection
// each thread sends events back to a central channel
pub fn server_events() -> mpsc::Receiver<ServerEvent> {
    let (event_sender, event_receiver) = mpsc::channel();
    thread::spawn(move || {
        let server = websocket::Server::bind("0.0.0.0:2794").unwrap();
        for connection in server {
            let event_sender = event_sender.clone();
            thread::spawn(move || {
                // accept request
                let request = connection.unwrap().read_request().unwrap();
                request.validate().unwrap();

                // get the User ID from a cookie in the headers
                let user_id = get_user_id(request.headers.get::<Cookie>());

                let response = request.accept();
                let (mut sender, mut receiver) = response.send().unwrap().split();

                let ip = sender.get_mut().peer_addr().unwrap();
                println!("Connection from {}", ip);
                ::std::io::stdout().flush().unwrap(); // TODO is this actually necessary?

                // hand over the sender
                event_sender.send(ServerEvent::Sync((sender,user_id))).unwrap();

                // handle messages
                for message in receiver.incoming_messages() {
                    let message = match message {
                        Ok(m) => m,
                        Err(_) => return,
                    };
                    match message {
                        Message::Binary(bytes) => {
                            event_sender.send(ServerEvent::Change(bytes)).unwrap();
                        }
                        Message::Close(_) => {
                            let ip_addr = format!("{}", ip);
                            println!("Received close message from {}.",ip_addr);
                            let close_message = CloseData{status_code: 0, reason: ip_addr};
                            event_sender.send(ServerEvent::Terminate(Some(close_message))).unwrap();
                        }
                        _ => println!("Unknown message: {:?}", message)
                    }
                }
            });
        }
    });
    event_receiver
}

pub fn handle_event(server: &mut Server, event: Event, event_json: Json) {
    // save the event
    {
        let mut autosave = OpenOptions::new().write(true).append(true).open("./autosave").unwrap();
        autosave.write_all(format!("{}", event_json).as_bytes()).unwrap();
        autosave.write_all("\n".as_bytes()).unwrap();
        autosave.flush().unwrap();
    }

    // copy the old flow so we can compare to the new flow for changes
    let old_flow = server.flow.clone();

    // run the flow until it reaches fixpoint
    server.flow.quiesce(event.changes);

    // handle commands
    for command in event.commands.iter() {
        let borrowed_words = command.iter().map(|word| &word[..]).collect::<Vec<_>>();
        match &borrowed_words[..] {
            ["load", filename] => {
                server.flow = Flow::new();
                load(&mut server.flow, "./bootstrap");
                load(&mut server.flow, filename);
                save(&server.flow, "./autosave");
            }
            ["save", filename] => {
                save(&server.flow, filename);
            }
            ["get events", id] => {
                let events_string = read_file("./autosave");
                send_event(server, &vec![], &vec![
                    vec!["got events".to_owned(), id.to_owned(), events_string]
                    ]);
            }
            ["set events", events_string] => {
                write_file("./autosave", events_string);
                server.flow = Flow::new();
                load(&mut server.flow, "./bootstrap");
                load(&mut server.flow, "./autosave");
            }
            other => panic!("Unknown command: {:?}", other),
        }
    }

    let changes = &server.flow.changes_from(old_flow);
    send_event(server, changes, &event.commands.clone())
}

pub fn run() {
    let mut flow = Flow::new();
    time!("reading saved state", {
        load(&mut flow, "./bootstrap");
        load(&mut flow, "./autosave");
    });

    let senders: Vec<sender::Sender<WebSocketStream>> = Vec::new();

    let mut server = Server{flow: flow, senders: senders};

    for server_event in server_events() {
        match server_event {

            // a new client has connected and needs to sync its state
            ServerEvent::Sync((mut sender, user_id)) => {
                let mut changes = vec![];

                // add a session to the session table
                let session_id = format!("{}", sender.get_mut().peer_addr().unwrap());
                changes.push(("sessions".to_owned(),
                    Change{
                        fields: vec!["sessions: id".to_owned(), "sessions: status".to_owned()],
                        insert: vec![vec![Value::String(session_id.clone()), Value::Float(1f64)]],
                        remove: vec![],
                    }));

                // if we have a user ID, add a mapping from the session ID to the user ID
                if let Some(user_id) = user_id {
                    changes.push(("session id to user id".to_owned(),
                        Change{
                            fields: vec!["session id to user id: session id".to_owned(), "session id to user id: user id".to_owned()],
                            insert: vec![vec![Value::String(session_id.clone()), Value::String(user_id)]],
                            remove: vec![]
                        }));
                }

                // handle the session change
                let event = Event{changes: changes, session: session_id.clone(), commands: vec![]};
                let json = event.to_json();
                handle_event(&mut server, event, json);

                // sync the new client
                let changes = server.flow.as_changes();
                let event = Event{changes: changes, session: session_id, commands: vec![]};
                let text = format!("{}", event.to_json());
                match sender.send_message(Message::Text(text)) {
                    Ok(_) => (),
                    Err(error) => println!("Send error: {}", error),
                };
                server.senders.push(sender)
            }

            // an existing client has sent a new message
            ServerEvent::Change(input_bytes) => {
                // TODO we throw cbor in here to avoid https://github.com/rust-lang/rustc-serialize/issues/113
                let mut decoder = cbor::Decoder::from_bytes(&input_bytes[..]);
                let cbor = decoder.items().next().unwrap().unwrap();
                let json = cbor.to_json();
                let event = FromJson::from_json(&json);
                handle_event(&mut server, event, json);
            }

            ServerEvent::Terminate(m) => {
                let terminate_ip = m.unwrap().reason;
                println!("Closing connection from {}...",terminate_ip);

                // find the index of the connection's sender
                let ip_ix = server.senders.iter_mut().position(|mut sender| {
                    let ip = format!("{}",sender.get_mut().peer_addr().unwrap());
                    ip == terminate_ip
                });

                match ip_ix {
                    Some(ix) => {
                        // close the connection
                        let _ = server.senders[ix].send_message(Message::Close(None));
                        match server.senders[ix].get_mut().shutdown(Shutdown::Both) {
                            Ok(_) => println!("Connection from {} has closed successfully.",terminate_ip),
                            Err(e) => println!("Connection from {} failed to shut down properly: {}",terminate_ip,e),
                        }
                        server.senders.remove(ix);

                        // update the session table
                        let sessions = server.flow.get_output("sessions").clone();
                        let ip_string = Value::String(terminate_ip.clone());

                        // change the session status to 0
                        for row in sessions.find(vec![&ip_string, &Value::Null]) {
                            match row {
                                [_, ref status] => {
                                    let change = Change {
                                        fields: sessions.fields.clone(),
                                        insert: vec![vec![ip_string.clone(), Value::Float(0f64)]],
                                        remove: vec![vec![ip_string.clone(), status.clone()]],
                                    };
                                    let event = Event{changes: vec![("sessions".to_string(),change)], session: "".to_string(), commands: vec![]};
                                    let json = event.to_json();
                                    handle_event(&mut server, event, json);
                                }
                                _ => unreachable!(),
                            }
                        }

                    },
                    None => panic!("IP address {} is not connected",terminate_ip),
                }
            }
        }
    }
}<|endoftext|>


<commit_before>extern crate sfml;

use sfml::system::Vector2f;
use sfml::window::{ContextSettings, VideoMode, event, Close};
use sfml::graphics::{RenderWindow, RenderTarget, CircleShape, Color};

fn main() {
    let mut window = RenderWindow::new(VideoMode::new_init(800, 600, 32),
                                        "SFML Example",
                                        Close,
                                        &ContextSettings::default())
        .expect("Cannot create a new Render Window.");

    let mut circle = CircleShape::new().expect("Error cannot create ball.");
    circle.set_radius(30.);
    circle.set_fill_color(&Color::red());
    circle.set_position(&Vector2f::new(100., 100.));

    while window.is_open() {
        for event in window.events() {
            match event {
                event::Closed => window.close(),
                _ => { }
            }
        }

        window.clear(&Color::new_rgb(0, 200, 200));
        window.draw(&circle);
        window.display();
    }
}
<commit_msg>make struct with window<commit_after>extern crate sfml;

use sfml::system::Vector2f;
use sfml::window::{ContextSettings, VideoMode, event, Close};
use sfml::graphics::{RenderWindow, RenderTarget, CircleShape, Color};

fn main() {
    let mut env = SFMLEnv::new(800, 600);

    let mut circle = CircleShape::new().expect("Error cannot create ball.");
    circle.set_radius(30.);
    circle.set_fill_color(&Color::red());
    circle.set_position(&Vector2f::new(100., 100.));

    while env.win.is_open() {
        for event in env.win.events() {
            match event {
                event::Closed => env.win.close(),
                _ => { }
            }
        }

        env.win.clear(&Color::new_rgb(0, 200, 200));
        env.win.draw(&circle);
        env.win.display();
    }
}

struct SFMLEnv {
    win: RenderWindow,
    width: u32,
    height: u32
}

impl SFMLEnv {
    fn new(width: u32, height: u32) -> SFMLEnv {
        let mut window = RenderWindow::new(VideoMode::new_init(width, height, 32),
                                           "SFML Example",
                                           Close,
                                           &ContextSettings::default())
            .expect("Cannot create a new Render Window.");
        window.set_vertical_sync_enabled(true);
        SFMLEnv {
            win: window,
            width: width,
            height: height
        }
    }
}
<|endoftext|>


<commit_before>use geo::Point;
use std::cmp;

use codearea::CodeArea;

use consts::{
    CODE_ALPHABET, ENCODING_BASE, GRID_CODE_LENGTH, GRID_COLUMNS, GRID_ROWS, LATITUDE_MAX,
    LAT_INTEGER_MULTIPLIER, LNG_INTEGER_MULTIPLIER, LONGITUDE_MAX, MAX_CODE_LENGTH,
    MIN_TRIMMABLE_CODE_LEN, PADDING_CHAR, PADDING_CHAR_STR, PAIR_CODE_LENGTH, PAIR_RESOLUTIONS,
    SEPARATOR, SEPARATOR_POSITION,
};

use private::{
    clip_latitude, code_value, compute_latitude_precision, normalize_longitude, prefix_by_reference,
};

/// Determines if a code is a valid Open Location Code.
pub fn is_valid(code: &str) -> bool {
    let mut code: String = code.to_string();
    if code.len() < 3 {
        // A code must have at-least a separator character + 1 lat/lng pair
        return false;
    }

    // Validate separator character
    if code.find(SEPARATOR).is_none() {
        // The code MUST contain a separator character
        return false;
    }
    if code.find(SEPARATOR) != code.rfind(SEPARATOR) {
        // .. And only one separator character
        return false;
    }
    let spos = code.find(SEPARATOR).unwrap();
    if spos % 2 == 1 || spos > SEPARATOR_POSITION {
        // The separator must be in a valid location
        return false;
    }
    if code.len() - spos - 1 == 1 {
        // There must be > 1 character after the separator
        return false;
    }

    // Validate padding
    let padstart = code.find(PADDING_CHAR);
    if padstart.is_some() {
        if spos < SEPARATOR_POSITION {
            // Short codes cannot have padding
            return false;
        }
        let ppos = padstart.unwrap();
        if ppos == 0 || ppos % 2 == 1 {
            // Padding must be "within" the string, starting at an even position
            return false;
        }
        if code.len() > spos + 1 {
            // If there is padding, the code must end with the separator char
            return false;
        }
        let eppos = code.rfind(PADDING_CHAR).unwrap();
        if eppos - ppos % 2 == 1 {
            // Must have even number of padding chars
            return false;
        }
        // Extract the padding from the code (mutates code)
        let padding: String = code.drain(ppos..eppos + 1).collect();
        if padding.chars().any(|c| c != PADDING_CHAR) {
            // Padding must be one, contiguous block of padding chars
            return false;
        }
    }

    // Validate all characters are permissible
    code.chars()
        .map(|c| c.to_ascii_uppercase())
        .all(|c| c == SEPARATOR || CODE_ALPHABET.contains(&c))
}

/// Determines if a code is a valid short code.
///
/// A short Open Location Code is a sequence created by removing four or more
/// digits from an Open Location Code. It must include a separator character.
pub fn is_short(code: &str) -> bool {
    is_valid(code) && code.find(SEPARATOR).unwrap() < SEPARATOR_POSITION
}

/// Determines if a code is a valid full Open Location Code.
///
/// Not all possible combinations of Open Location Code characters decode to
/// valid latitude and longitude values. This checks that a code is valid
/// and also that the latitude and longitude values are legal. If the prefix
/// character is present, it must be the first character. If the separator
/// character is present, it must be after four characters.
pub fn is_full(code: &str) -> bool {
    is_valid(code) && !is_short(code)
}

/// Encode a location into an Open Location Code.
///
/// Produces a code of the specified length, or the default length if no
/// length is provided.
/// The length determines the accuracy of the code. The default length is
/// 10 characters, returning a code of approximately 13.5x13.5 meters. Longer
/// codes represent smaller areas, but lengths > 14 are sub-centimetre and so
/// 11 or 12 are probably the limit of useful codes.
pub fn encode(pt: Point<f64>, code_length: usize) -> String {
    let mut lat = clip_latitude(pt.lat());
    let lng = normalize_longitude(pt.lng());

    let trimmed_code_length = cmp::min(code_length, MAX_CODE_LENGTH);

    // Latitude 90 needs to be adjusted to be just less, so the returned code
    // can also be decoded.
    if lat > LATITUDE_MAX || (LATITUDE_MAX - lat) < 1e-10f64 {
        lat -= compute_latitude_precision(trimmed_code_length);
    }

    // Convert to integers.
    let mut lat_val =
        (((lat + LATITUDE_MAX) * LAT_INTEGER_MULTIPLIER as f64 * 1e6).round() / 1e6f64) as i64;
    let mut lng_val =
        (((lng + LONGITUDE_MAX) * LNG_INTEGER_MULTIPLIER as f64 * 1e6).round() / 1e6f64) as i64;

    // Compute the code digits. This largely ignores the requested length - it
    // generates either a 10 digit code, or a 15 digit code, and then truncates
    // it to the requested length.

    // Build up the code digits in reverse order.
    let mut rev_code = String::with_capacity(trimmed_code_length + 1);

    // First do the grid digits.
    if code_length > PAIR_CODE_LENGTH {
        for _i in 0..GRID_CODE_LENGTH {
            let lat_digit = lat_val % GRID_ROWS as i64;
            let lng_digit = lng_val % GRID_COLUMNS as i64;
            let ndx = (lat_digit * GRID_COLUMNS as i64 + lng_digit) as usize;
            rev_code.push(CODE_ALPHABET[ndx]);
            lat_val /= GRID_ROWS as i64;
            lng_val /= GRID_COLUMNS as i64;
        }
    } else {
        // Adjust latitude and longitude values to skip the grid digits.
        lat_val /= GRID_ROWS.pow(GRID_CODE_LENGTH as u32) as i64;
        lng_val /= GRID_COLUMNS.pow(GRID_CODE_LENGTH as u32) as i64;
    }
    // Compute the pair section of the code.
    for i in 0..PAIR_CODE_LENGTH / 2 {
        rev_code.push(CODE_ALPHABET[(lng_val % ENCODING_BASE as i64) as usize]);
        lng_val /= ENCODING_BASE as i64;
        rev_code.push(CODE_ALPHABET[(lat_val % ENCODING_BASE as i64) as usize]);
        lat_val /= ENCODING_BASE as i64;
        // If we are at the separator position, add the separator.
        if i == 0 {
            rev_code.push(SEPARATOR);
        }
    }
    let mut code: String;
    // If we need to pad the code, replace some of the digits.
    if code_length < SEPARATOR_POSITION {
        code = rev_code.chars().rev().take(code_length).collect();
        code.push_str(
            PADDING_CHAR_STR
                .repeat(SEPARATOR_POSITION - code_length)
                .as_str(),
        );
        code.push(SEPARATOR);
    } else {
        code = rev_code.chars().rev().take(code_length + 1).collect();
    }

    code
}

/// Decodes an Open Location Code into the location coordinates.
///
/// Returns a CodeArea object that includes the coordinates of the bounding
/// box - the lower left, center and upper right.
pub fn decode(code: &str) -> Result<CodeArea, String> {
    if !is_full(code) {
        return Err(format!("Code must be a valid full code: {}", code));
    }
    let mut code = code
        .to_string()
        .replace(SEPARATOR, "")
        .replace(PADDING_CHAR_STR, "")
        .to_uppercase();
    if code.len() > MAX_CODE_LENGTH {
        code = code.chars().take(MAX_CODE_LENGTH).collect();
    }

    // Work out the values as integers and convert to floating point at the end.
    let mut lat: i64 = -90 * LAT_INTEGER_MULTIPLIER;
    let mut lng: i64 = -180 * LNG_INTEGER_MULTIPLIER;
    let mut lat_place_val: i64 = LAT_INTEGER_MULTIPLIER * ENCODING_BASE.pow(2) as i64;
    let mut lng_place_val: i64 = LNG_INTEGER_MULTIPLIER * ENCODING_BASE.pow(2) as i64;

    for (idx, chr) in code.chars().enumerate() {
        if idx < PAIR_CODE_LENGTH {
            if idx % 2 == 0 {
                lat_place_val /= ENCODING_BASE as i64;
                lat += lat_place_val * code_value(chr) as i64;
            } else {
                lng_place_val /= ENCODING_BASE as i64;
                lng += lng_place_val * code_value(chr) as i64;
            }
        } else {
            lat_place_val /= GRID_ROWS as i64;
            lng_place_val /= GRID_COLUMNS as i64;
            lat += lat_place_val * (code_value(chr) / GRID_COLUMNS) as i64;
            lng += lng_place_val * (code_value(chr) % GRID_COLUMNS) as i64;
        }
    }
    // Convert to floating point values.
    let lat_lo: f64 = lat as f64 / LAT_INTEGER_MULTIPLIER as f64;
    let lng_lo: f64 = lng as f64 / LNG_INTEGER_MULTIPLIER as f64;
    let lat_hi: f64 =
        (lat + lat_place_val) as f64 / (ENCODING_BASE.pow(3) * GRID_ROWS.pow(5)) as f64;
    let lng_hi: f64 =
        (lng + lng_place_val) as f64 / (ENCODING_BASE.pow(3) * GRID_COLUMNS.pow(5)) as f64;
    Ok(CodeArea::new(lat_lo, lng_lo, lat_hi, lng_hi, code.len()))
}

/// Remove characters from the start of an OLC code.
///
/// This uses a reference location to determine how many initial characters
/// can be removed from the OLC code. The number of characters that can be
/// removed depends on the distance between the code center and the reference
/// location.
/// The minimum number of characters that will be removed is four. If more
/// than four characters can be removed, the additional characters will be
/// replaced with the padding character. At most eight characters will be
/// removed.
/// The reference location must be within 50% of the maximum range. This
/// ensures that the shortened code will be able to be recovered using
/// slightly different locations.
///
/// It returns either the original code, if the reference location was not
/// close enough, or the .
pub fn shorten(code: &str, ref_pt: Point<f64>) -> Result<String, String> {
    if !is_full(code) {
        return Ok(code.to_string());
    }
    if code.find(PADDING_CHAR).is_some() {
        return Err("Cannot shorten padded codes".to_owned());
    }

    let codearea: CodeArea = decode(code).unwrap();
    if codearea.code_length < MIN_TRIMMABLE_CODE_LEN {
        return Err(format!(
            "Code length must be at least {}",
            MIN_TRIMMABLE_CODE_LEN
        ));
    }

    // How close are the latitude and longitude to the code center.
    let range = (codearea.center.lat() - clip_latitude(ref_pt.lat()))
        .abs()
        .max((codearea.center.lng() - normalize_longitude(ref_pt.lng())).abs());

    for i in 0..PAIR_RESOLUTIONS.len() - 2 {
        // Check if we're close enough to shorten. The range must be less than 1/2
        // the resolution to shorten at all, and we want to allow some safety, so
        // use 0.3 instead of 0.5 as a multiplier.
        let idx = PAIR_RESOLUTIONS.len() - 2 - i;
        if range < (PAIR_RESOLUTIONS[idx] * 0.3f64) {
            let mut code = code.to_string();
            code.drain(..((idx + 1) * 2));
            return Ok(code);
        }
    }
    Ok(code.to_string())
}

/// Recover the nearest matching code to a specified location.
///
/// Given a short Open Location Code of between four and seven characters,
/// this recovers the nearest matching full code to the specified location.
/// The number of characters that will be prepended to the short code, depends
/// on the length of the short code and whether it starts with the separator.
/// If it starts with the separator, four characters will be prepended. If it
/// does not, the characters that will be prepended to the short code, where S
/// is the supplied short code and R are the computed characters, are as
/// follows:
///
/// * SSSS    -> RRRR.RRSSSS
/// * SSSSS   -> RRRR.RRSSSSS
/// * SSSSSS  -> RRRR.SSSSSS
/// * SSSSSSS -> RRRR.SSSSSSS
///
/// Note that short codes with an odd number of characters will have their
/// last character decoded using the grid refinement algorithm.
///
/// It returns the nearest full Open Location Code to the reference location
/// that matches the [shortCode]. Note that the returned code may not have the
/// same computed characters as the reference location (provided by
/// [referenceLatitude] and [referenceLongitude]). This is because it returns
/// the nearest match, not necessarily the match within the same cell. If the
/// passed code was not a valid short code, but was a valid full code, it is
/// returned unchanged.
pub fn recover_nearest(code: &str, ref_pt: Point<f64>) -> Result<String, String> {
    if !is_short(code) {
        if is_full(code) {
            return Ok(code.to_string().to_uppercase());
        } else {
            return Err(format!("Passed short code is not valid: {}", code));
        }
    }

    let prefix_len = SEPARATOR_POSITION - code.find(SEPARATOR).unwrap();
    let mut code = prefix_by_reference(ref_pt, prefix_len) + code;

    let code_area = decode(code.as_str()).unwrap();

    let resolution = compute_latitude_precision(prefix_len);
    let half_res = resolution / 2f64;

    let mut latitude = code_area.center.lat();
    let mut longitude = code_area.center.lng();

    let ref_lat = clip_latitude(ref_pt.lat());
    let ref_lng = normalize_longitude(ref_pt.lng());
    if ref_lat + half_res < latitude && latitude - resolution >= -LATITUDE_MAX {
        latitude -= resolution;
    } else if ref_lat - half_res > latitude && latitude + resolution <= LATITUDE_MAX {
        latitude += resolution;
    }
    if ref_lng + half_res < longitude {
        longitude -= resolution;
    } else if ref_lng - half_res > longitude {
        longitude += resolution;
    }
    Ok(encode(
        Point::new(longitude, latitude),
        code_area.code_length,
    ))
}
<commit_msg>Fix unused mut warning<commit_after>use geo::Point;
use std::cmp;

use codearea::CodeArea;

use consts::{
    CODE_ALPHABET, ENCODING_BASE, GRID_CODE_LENGTH, GRID_COLUMNS, GRID_ROWS, LATITUDE_MAX,
    LAT_INTEGER_MULTIPLIER, LNG_INTEGER_MULTIPLIER, LONGITUDE_MAX, MAX_CODE_LENGTH,
    MIN_TRIMMABLE_CODE_LEN, PADDING_CHAR, PADDING_CHAR_STR, PAIR_CODE_LENGTH, PAIR_RESOLUTIONS,
    SEPARATOR, SEPARATOR_POSITION,
};

use private::{
    clip_latitude, code_value, compute_latitude_precision, normalize_longitude, prefix_by_reference,
};

/// Determines if a code is a valid Open Location Code.
pub fn is_valid(code: &str) -> bool {
    let mut code: String = code.to_string();
    if code.len() < 3 {
        // A code must have at-least a separator character + 1 lat/lng pair
        return false;
    }

    // Validate separator character
    if code.find(SEPARATOR).is_none() {
        // The code MUST contain a separator character
        return false;
    }
    if code.find(SEPARATOR) != code.rfind(SEPARATOR) {
        // .. And only one separator character
        return false;
    }
    let spos = code.find(SEPARATOR).unwrap();
    if spos % 2 == 1 || spos > SEPARATOR_POSITION {
        // The separator must be in a valid location
        return false;
    }
    if code.len() - spos - 1 == 1 {
        // There must be > 1 character after the separator
        return false;
    }

    // Validate padding
    let padstart = code.find(PADDING_CHAR);
    if padstart.is_some() {
        if spos < SEPARATOR_POSITION {
            // Short codes cannot have padding
            return false;
        }
        let ppos = padstart.unwrap();
        if ppos == 0 || ppos % 2 == 1 {
            // Padding must be "within" the string, starting at an even position
            return false;
        }
        if code.len() > spos + 1 {
            // If there is padding, the code must end with the separator char
            return false;
        }
        let eppos = code.rfind(PADDING_CHAR).unwrap();
        if eppos - ppos % 2 == 1 {
            // Must have even number of padding chars
            return false;
        }
        // Extract the padding from the code (mutates code)
        let padding: String = code.drain(ppos..eppos + 1).collect();
        if padding.chars().any(|c| c != PADDING_CHAR) {
            // Padding must be one, contiguous block of padding chars
            return false;
        }
    }

    // Validate all characters are permissible
    code.chars()
        .map(|c| c.to_ascii_uppercase())
        .all(|c| c == SEPARATOR || CODE_ALPHABET.contains(&c))
}

/// Determines if a code is a valid short code.
///
/// A short Open Location Code is a sequence created by removing four or more
/// digits from an Open Location Code. It must include a separator character.
pub fn is_short(code: &str) -> bool {
    is_valid(code) && code.find(SEPARATOR).unwrap() < SEPARATOR_POSITION
}

/// Determines if a code is a valid full Open Location Code.
///
/// Not all possible combinations of Open Location Code characters decode to
/// valid latitude and longitude values. This checks that a code is valid
/// and also that the latitude and longitude values are legal. If the prefix
/// character is present, it must be the first character. If the separator
/// character is present, it must be after four characters.
pub fn is_full(code: &str) -> bool {
    is_valid(code) && !is_short(code)
}

/// Encode a location into an Open Location Code.
///
/// Produces a code of the specified length, or the default length if no
/// length is provided.
/// The length determines the accuracy of the code. The default length is
/// 10 characters, returning a code of approximately 13.5x13.5 meters. Longer
/// codes represent smaller areas, but lengths > 14 are sub-centimetre and so
/// 11 or 12 are probably the limit of useful codes.
pub fn encode(pt: Point<f64>, code_length: usize) -> String {
    let mut lat = clip_latitude(pt.lat());
    let lng = normalize_longitude(pt.lng());

    let trimmed_code_length = cmp::min(code_length, MAX_CODE_LENGTH);

    // Latitude 90 needs to be adjusted to be just less, so the returned code
    // can also be decoded.
    if lat > LATITUDE_MAX || (LATITUDE_MAX - lat) < 1e-10f64 {
        lat -= compute_latitude_precision(trimmed_code_length);
    }

    // Convert to integers.
    let mut lat_val =
        (((lat + LATITUDE_MAX) * LAT_INTEGER_MULTIPLIER as f64 * 1e6).round() / 1e6f64) as i64;
    let mut lng_val =
        (((lng + LONGITUDE_MAX) * LNG_INTEGER_MULTIPLIER as f64 * 1e6).round() / 1e6f64) as i64;

    // Compute the code digits. This largely ignores the requested length - it
    // generates either a 10 digit code, or a 15 digit code, and then truncates
    // it to the requested length.

    // Build up the code digits in reverse order.
    let mut rev_code = String::with_capacity(trimmed_code_length + 1);

    // First do the grid digits.
    if code_length > PAIR_CODE_LENGTH {
        for _i in 0..GRID_CODE_LENGTH {
            let lat_digit = lat_val % GRID_ROWS as i64;
            let lng_digit = lng_val % GRID_COLUMNS as i64;
            let ndx = (lat_digit * GRID_COLUMNS as i64 + lng_digit) as usize;
            rev_code.push(CODE_ALPHABET[ndx]);
            lat_val /= GRID_ROWS as i64;
            lng_val /= GRID_COLUMNS as i64;
        }
    } else {
        // Adjust latitude and longitude values to skip the grid digits.
        lat_val /= GRID_ROWS.pow(GRID_CODE_LENGTH as u32) as i64;
        lng_val /= GRID_COLUMNS.pow(GRID_CODE_LENGTH as u32) as i64;
    }
    // Compute the pair section of the code.
    for i in 0..PAIR_CODE_LENGTH / 2 {
        rev_code.push(CODE_ALPHABET[(lng_val % ENCODING_BASE as i64) as usize]);
        lng_val /= ENCODING_BASE as i64;
        rev_code.push(CODE_ALPHABET[(lat_val % ENCODING_BASE as i64) as usize]);
        lat_val /= ENCODING_BASE as i64;
        // If we are at the separator position, add the separator.
        if i == 0 {
            rev_code.push(SEPARATOR);
        }
    }
    let mut code: String;
    // If we need to pad the code, replace some of the digits.
    if code_length < SEPARATOR_POSITION {
        code = rev_code.chars().rev().take(code_length).collect();
        code.push_str(
            PADDING_CHAR_STR
                .repeat(SEPARATOR_POSITION - code_length)
                .as_str(),
        );
        code.push(SEPARATOR);
    } else {
        code = rev_code.chars().rev().take(code_length + 1).collect();
    }

    code
}

/// Decodes an Open Location Code into the location coordinates.
///
/// Returns a CodeArea object that includes the coordinates of the bounding
/// box - the lower left, center and upper right.
pub fn decode(code: &str) -> Result<CodeArea, String> {
    if !is_full(code) {
        return Err(format!("Code must be a valid full code: {}", code));
    }
    let mut code = code
        .to_string()
        .replace(SEPARATOR, "")
        .replace(PADDING_CHAR_STR, "")
        .to_uppercase();
    if code.len() > MAX_CODE_LENGTH {
        code = code.chars().take(MAX_CODE_LENGTH).collect();
    }

    // Work out the values as integers and convert to floating point at the end.
    let mut lat: i64 = -90 * LAT_INTEGER_MULTIPLIER;
    let mut lng: i64 = -180 * LNG_INTEGER_MULTIPLIER;
    let mut lat_place_val: i64 = LAT_INTEGER_MULTIPLIER * ENCODING_BASE.pow(2) as i64;
    let mut lng_place_val: i64 = LNG_INTEGER_MULTIPLIER * ENCODING_BASE.pow(2) as i64;

    for (idx, chr) in code.chars().enumerate() {
        if idx < PAIR_CODE_LENGTH {
            if idx % 2 == 0 {
                lat_place_val /= ENCODING_BASE as i64;
                lat += lat_place_val * code_value(chr) as i64;
            } else {
                lng_place_val /= ENCODING_BASE as i64;
                lng += lng_place_val * code_value(chr) as i64;
            }
        } else {
            lat_place_val /= GRID_ROWS as i64;
            lng_place_val /= GRID_COLUMNS as i64;
            lat += lat_place_val * (code_value(chr) / GRID_COLUMNS) as i64;
            lng += lng_place_val * (code_value(chr) % GRID_COLUMNS) as i64;
        }
    }
    // Convert to floating point values.
    let lat_lo: f64 = lat as f64 / LAT_INTEGER_MULTIPLIER as f64;
    let lng_lo: f64 = lng as f64 / LNG_INTEGER_MULTIPLIER as f64;
    let lat_hi: f64 =
        (lat + lat_place_val) as f64 / (ENCODING_BASE.pow(3) * GRID_ROWS.pow(5)) as f64;
    let lng_hi: f64 =
        (lng + lng_place_val) as f64 / (ENCODING_BASE.pow(3) * GRID_COLUMNS.pow(5)) as f64;
    Ok(CodeArea::new(lat_lo, lng_lo, lat_hi, lng_hi, code.len()))
}

/// Remove characters from the start of an OLC code.
///
/// This uses a reference location to determine how many initial characters
/// can be removed from the OLC code. The number of characters that can be
/// removed depends on the distance between the code center and the reference
/// location.
/// The minimum number of characters that will be removed is four. If more
/// than four characters can be removed, the additional characters will be
/// replaced with the padding character. At most eight characters will be
/// removed.
/// The reference location must be within 50% of the maximum range. This
/// ensures that the shortened code will be able to be recovered using
/// slightly different locations.
///
/// It returns either the original code, if the reference location was not
/// close enough, or the .
pub fn shorten(code: &str, ref_pt: Point<f64>) -> Result<String, String> {
    if !is_full(code) {
        return Ok(code.to_string());
    }
    if code.find(PADDING_CHAR).is_some() {
        return Err("Cannot shorten padded codes".to_owned());
    }

    let codearea: CodeArea = decode(code).unwrap();
    if codearea.code_length < MIN_TRIMMABLE_CODE_LEN {
        return Err(format!(
            "Code length must be at least {}",
            MIN_TRIMMABLE_CODE_LEN
        ));
    }

    // How close are the latitude and longitude to the code center.
    let range = (codearea.center.lat() - clip_latitude(ref_pt.lat()))
        .abs()
        .max((codearea.center.lng() - normalize_longitude(ref_pt.lng())).abs());

    for i in 0..PAIR_RESOLUTIONS.len() - 2 {
        // Check if we're close enough to shorten. The range must be less than 1/2
        // the resolution to shorten at all, and we want to allow some safety, so
        // use 0.3 instead of 0.5 as a multiplier.
        let idx = PAIR_RESOLUTIONS.len() - 2 - i;
        if range < (PAIR_RESOLUTIONS[idx] * 0.3f64) {
            let mut code = code.to_string();
            code.drain(..((idx + 1) * 2));
            return Ok(code);
        }
    }
    Ok(code.to_string())
}

/// Recover the nearest matching code to a specified location.
///
/// Given a short Open Location Code of between four and seven characters,
/// this recovers the nearest matching full code to the specified location.
/// The number of characters that will be prepended to the short code, depends
/// on the length of the short code and whether it starts with the separator.
/// If it starts with the separator, four characters will be prepended. If it
/// does not, the characters that will be prepended to the short code, where S
/// is the supplied short code and R are the computed characters, are as
/// follows:
///
/// * SSSS    -> RRRR.RRSSSS
/// * SSSSS   -> RRRR.RRSSSSS
/// * SSSSSS  -> RRRR.SSSSSS
/// * SSSSSSS -> RRRR.SSSSSSS
///
/// Note that short codes with an odd number of characters will have their
/// last character decoded using the grid refinement algorithm.
///
/// It returns the nearest full Open Location Code to the reference location
/// that matches the [shortCode]. Note that the returned code may not have the
/// same computed characters as the reference location (provided by
/// [referenceLatitude] and [referenceLongitude]). This is because it returns
/// the nearest match, not necessarily the match within the same cell. If the
/// passed code was not a valid short code, but was a valid full code, it is
/// returned unchanged.
pub fn recover_nearest(code: &str, ref_pt: Point<f64>) -> Result<String, String> {
    if !is_short(code) {
        if is_full(code) {
            return Ok(code.to_string().to_uppercase());
        } else {
            return Err(format!("Passed short code is not valid: {}", code));
        }
    }

    let prefix_len = SEPARATOR_POSITION - code.find(SEPARATOR).unwrap();
    let code = prefix_by_reference(ref_pt, prefix_len) + code;

    let code_area = decode(code.as_str()).unwrap();

    let resolution = compute_latitude_precision(prefix_len);
    let half_res = resolution / 2f64;

    let mut latitude = code_area.center.lat();
    let mut longitude = code_area.center.lng();

    let ref_lat = clip_latitude(ref_pt.lat());
    let ref_lng = normalize_longitude(ref_pt.lng());
    if ref_lat + half_res < latitude && latitude - resolution >= -LATITUDE_MAX {
        latitude -= resolution;
    } else if ref_lat - half_res > latitude && latitude + resolution <= LATITUDE_MAX {
        latitude += resolution;
    }
    if ref_lng + half_res < longitude {
        longitude -= resolution;
    } else if ref_lng - half_res > longitude {
        longitude += resolution;
    }
    Ok(encode(
        Point::new(longitude, latitude),
        code_area.code_length,
    ))
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate arg_parser;
extern crate extra;
extern crate walkdir;

use std::env;
use std::fs;
use std::io::{stderr, stdout, Write};
use std::path;
use std::process::exit;
use arg_parser::ArgParser;
use extra::io::fail;
use extra::option::OptionalExt;

use walkdir::WalkDir;

const MAN_PAGE: &'static str = /* @MANSTART{cp} */ r#"
NAME
    cp - copy files

SYNOPSIS
    cp SOURCE_FILE, ... DESTINATION

DESCRIPTION
    The cp utility copies the contents of the SOURCE_FILE to the DESTINATION. If multiple
    source files are specified, then they are copied to DESTINATION.

OPTIONS
    -h
    --help
        print this message
    -n
    --no-action
        usefull only in combination with '--verbose'
    -v
    --verbose
        print what is being copied
    -r
    --recusive
        if any of the SOURCE_FILEs is a directory recurse into it and copy any content.
        NOTE: it is illegal for any SOURCE_FILE to be a directory if this flag isn't given
"#; /* @MANEND */

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag(&["r", "recursive"])
        .add_flag(&["n", "no-action"])
        .add_flag(&["v", "verbose"])
        .add_flag(&["h", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    let recurse = parser.found("recursive");
    let verbose = parser.found("verbose");
    let execute = ! parser.found("no-action");

    if parser.args.is_empty() {
        fail("No source argument. Use --help to see the usage.", &mut stderr);
    }
    else if parser.args.len() == 1 {
        fail("No destination argument. Use --help to see the usage.", &mut stderr);
    }
    else if parser.args.len() == 2 && ! recurse {
        let src = path::Path::new(&parser.args[0]);
        let mut dst = path::PathBuf::from(&parser.args[1]);
        if dst.is_dir() {
            dst.push(src.file_name().try(&mut stderr))
        }
        if execute {
            fs::copy(src, dst).try(&mut stderr);
        }
        if verbose {
            println!("{}", src.display());
        }
    }
    else {
        // This unwrap won't panic since it's been verified not to be empty
        let dst = parser.args.pop().unwrap();
        let dst = path::PathBuf::from(dst);
        if dst.is_dir() {
            for ref arg in parser.args {
                let src = path::Path::new(arg);
                if src.is_dir() && ! recurse {
                    fail("Can not copy directories non-recursive", &mut stderr);
                }
                if recurse {
                    for entry in WalkDir::new(arg) {
                        let entry = entry.unwrap();
                        let src = path::Path::new(entry.path());
                        if execute {
                            if src.is_dir() {
                                fs::create_dir(dst.join(src)).try(&mut stderr);
                            } else if src.is_file() {
                                fs::copy(src, dst.join(src)).try(&mut stderr);
                            } // here we might also want to check for symlink, hardlink, socket, block, char, ...?
                        }
                        if verbose {
                            println!("{}", src.display());
                        }
                    }
                } else {
                    if execute {
                        fs::copy(src, dst.join(src.file_name().try(&mut stderr))).try(&mut stderr);
                    }
                    if verbose {
                        println!("{}", src.display());
                    }
                }
            }
        }
        else if dst.is_file() {
            fail("Destination should be a path, not a file. Use --help to see the usage.", &mut stderr);
        }
        else {
            fail("No destination found. Use --help to see the usage.", &mut stderr);
        }
    }
}
<commit_msg>Ported changes from mv.rs to cp.rs<commit_after>#![deny(warnings)]

extern crate arg_parser;
extern crate extra;
extern crate walkdir;

use std::env;
use std::fs;
use std::io::{stderr, stdout, Write};
use std::path;
use std::process::exit;
use arg_parser::ArgParser;
use extra::io::fail;
use extra::option::OptionalExt;

use walkdir::WalkDir;

const MAN_PAGE: &'static str = /* @MANSTART{cp} */ r#"
NAME
    cp - copy files

SYNOPSIS
    cp SOURCE_FILE, ... DESTINATION

DESCRIPTION
    The cp utility copies the contents of the SOURCE_FILE to the DESTINATION. If multiple
    source files are specified, then they are copied to DESTINATION.

OPTIONS
    -h
    --help
        print this message
    -n
    --no-action
        usefull only in combination with '--verbose'
    -v
    --verbose
        print what is being copied
    -r
    --recusive
        if any of the SOURCE_FILEs is a directory recurse into it and copy any content.
        NOTE: it is illegal for any SOURCE_FILE to be a directory if this flag isn't given
"#; /* @MANEND */

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag(&["r", "recursive"])
        .add_flag(&["n", "no-action"])
        .add_flag(&["v", "verbose"])
        .add_flag(&["h", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    let recurse = parser.found("recursive");
    let verbose = parser.found("verbose");
    let execute = !parser.found("no-action");

    if parser.args.is_empty() {
        fail("No source argument. Use --help to see the usage.", &mut stderr);
    } else if parser.args.len() == 1 {
        fail("No destination argument. Use --help to see the usage.", &mut stderr);
    } else {
        // This unwrap won't panic since it's been verified not to be empty
        let dst = parser.args.pop().unwrap();
        let dst = path::PathBuf::from(dst);
        if dst.is_file() {
            if parser.args.len() == 2 {
                let src = path::Path::new(parser.args[0]);
                if src.is_file() {
                    if execute {
                        fs::copy(src, dst).try(&mut stderr);
                    }
                    if verbose {
                        println!("{}", src.display());
                    }
                } else {
                    fail("Attempted to copy a non-file onto a file. Use --help to see the usage.", &mut stderr);
                }
            } else {
                fail("Cannot copy multiple objects onto one location. Use --help to see the usage.", &mut stderr);
            }
        } else if dst.is_dir() {
            for ref arg in parser.args {
                let src = path::Path::new(arg);
                if src.is_dir() {
                    if recurse {
                        for entry in WalkDir::new(arg) {
                            let entry = entry.unwrap();
                            let src = path::Path::new(entry.path());
                            if execute {
                                fs::create_dir(dst.join(src)).try(&mut stderr);
                            }
                            if verbose {
                                println!("{}", src.display());
                            }
                        }
                    } else {
                        fail("Can not move directories without the -r recursive tag. Use --help to see the usage.", &mut stderr);
                    }
                } else if src.is_file() {
                    if execute {
                        fs::copy(src, dst.join(src.file_name().try(&mut stderr))).try(&mut stderr);
                    }
                    if verbose {
                        println!("{}", src.display());
                    }
                } // here we might also want to check for symlink, hardlink, socket, block, char, ...?
            }
        } else {
            fail("No destination found. Use --help to see the usage.", &mut stderr);
        }
    }
}
<|endoftext|>


<commit_before>use std::rc::{Rc};
use std::cell::{RefCell};
use std::collections::HashMap;

//is same identity
fn is_same<T>(lhs: &T, rhs: &T) -> bool {
    lhs as *const T as i64 == rhs as *const T as i64
}

//the code below is horrible
//borrow doesn't return T, it returns Ref<T>
//we need to dereference it to get to the T inside
//is_same takes borrow so reapply the ampersand
fn is_same_subscriber<T: Subscriber>(lhs: Rc<RefCell<T>>, rhs: Rc<RefCell<T>>) -> bool {
    let lhs = lhs.clone();
    let rhs = rhs.clone();
    let res = is_same(&*lhs.borrow(), &*rhs.borrow()); //needed to live long enough
    res
}

pub trait Subscriber {
    fn new_message(&mut self, bytes: &[u8]);
}

pub struct Broker<T: Subscriber> {
    tree: Node<T>,
}

struct Node<T: Subscriber> {
    children: HashMap<String, Node<T>>,
    leaves: Vec<Subscription<T>>,
}

struct Subscription<T: Subscriber> {
    subscriber: Rc<RefCell<T>>,
}

impl<T: Subscriber> Subscription<T> {
    fn new(subscriber: Rc<RefCell<T>>) -> Self {
        Subscription { subscriber: subscriber.clone()}
    }
}

impl<T: Subscriber> Node<T> {
    fn new() -> Self {
        Node { children: HashMap::new(), leaves: vec![] }
    }

    fn add_subscription(&mut self, subscription: Subscription<T>) {
        self.leaves.push(subscription);
    }
}

impl<T: Subscriber> Broker<T> {
    pub fn new() -> Self {
        Broker { tree: Node::new() }
    }

    pub fn subscribe(&mut self, subscriber: Rc<RefCell<T>>, topics: &[&str]) {
        for topic in topics {
            let sub_parts : Vec<&str> = topic.split("/").collect();
            Self::ensure_node_exists(&sub_parts, &mut self.tree);
            Self::add_subscription_to_node(&mut self.tree, subscriber.clone(), &sub_parts);
        }
    }

    pub fn unsubscribe_all(&mut self, subscriber: Rc<RefCell<T>>) {
        Self::unsubscribe_all_impl(&mut self.tree, subscriber.clone());
    }

    pub fn publish(&self, topic: &str, payload: &[u8]) {
        let pub_parts : Vec<&str> = topic.split("/").collect();
        Self::publish_impl(&self.tree, &pub_parts, &payload);
    }

    fn ensure_node_exists(sub_parts: &[&str], node: &mut Node<T>) {
        if sub_parts.len() == 0 {
            return;
        }

        let part = &sub_parts[0][..];
        if !node.children.contains_key(part) {
            node.children.insert(sub_parts[0].to_string(), Node::new());
        }

        Self::ensure_node_exists(&sub_parts[1..], node.children.get_mut(part).unwrap());
    }

    fn add_subscription_to_node(tree: &mut Node<T>, subscriber: Rc<RefCell<T>>, sub_parts: &[&str]) {
        if sub_parts.len() < 1 {
            panic!("oops");
        }

        let part = &sub_parts[0][..];
        let node = tree.children.get_mut(part).unwrap();
        let sub_parts = &sub_parts[1..];

        if sub_parts.len() == 0 {
            node.add_subscription(Subscription::new(subscriber.clone()));
        } else {
            Self::add_subscription_to_node(node, subscriber, sub_parts);
        }
    }

    fn publish_impl(tree: &Node<T>, pub_parts: &[&str], payload: &[u8]) {
        if pub_parts.len() < 1 {
            panic!("oops");
        }

        let part = &pub_parts[0][..];
        let node = tree.children.get(part);
        let pub_parts = &pub_parts[1..];

        match node {
            None => {
                return; //didn't find a subscriber
            },
            Some(node) => {
                if pub_parts.len() == 0 {
                    for subscription in &node.leaves {
                        let subscriber = subscription.subscriber.clone();
                        subscriber.borrow_mut().new_message(payload);
                    }
                } else {
                    Self::publish_impl(node, pub_parts, payload);
                }
            }
        }
    }

    fn unsubscribe_all_impl(tree: &mut Node<T>, subscriber: Rc<RefCell<T>>) {
        tree.leaves.retain(|s| !is_same_subscriber(s.subscriber.clone(), subscriber.clone()));

        if tree.children.len() == 0 {
            return;
        }

        for (_, node) in tree.children.iter_mut() {
            Self::unsubscribe_all_impl(node, subscriber.clone());
        }
    }
}

#[cfg(test)]
struct TestSubscriber {
    msgs: Vec<Vec<u8>>,
}

#[cfg(test)]
impl TestSubscriber {
    fn new() -> Self {
        TestSubscriber{msgs: vec![]}
    }
}

#[cfg(test)]
impl Subscriber for TestSubscriber {
    fn new_message(&mut self, bytes: &[u8]) {
        self.msgs.push(bytes.to_vec());
    }
}

#[test]
fn test_subscribe() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();
    broker.publish("topics/foo", &[0, 1, 2]);
    assert_eq!(subscriber.borrow().msgs.len(), 0);

    broker.subscribe(subscriber.clone(), &["topics/foo"]);
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4, 6]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);

    broker.subscribe(subscriber.clone(), &["topics/bar"]);
    broker.publish("topics/foo", &[1, 3, 5, 7]);
    broker.publish("topics/bar", &[2, 4]);
    assert_eq!(subscriber.borrow().msgs.len(), 3);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[1, 3, 5, 7]);
    assert_eq!(subscriber.borrow().msgs[2], &[2, 4]);
}

#[test]
fn test_unsubscribe_all() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();
    {
        let foo = subscriber.borrow();
        println!("in block, subscriber is {}", &*foo as *const TestSubscriber as i64);
    }

    broker.subscribe(subscriber.clone(), &["topics/foo"]);
    assert_eq!(is_same_subscriber(subscriber.clone(), subscriber.clone()), true);
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4, 6]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);

    broker.unsubscribe_all(subscriber.clone());
    broker.publish("topics/foo", &[0, 1, 9]);
    broker.publish("topics/bar", &[2, 4]);
    broker.publish("topics/baz", &[2, 4, 7, 11]);

    //shouldn't have changed
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
}
<commit_msg>Unsubscribe one<commit_after>use std::rc::{Rc};
use std::cell::{RefCell};
use std::collections::HashMap;

//is same identity
fn is_same<T>(lhs: &T, rhs: &T) -> bool {
    lhs as *const T as i64 == rhs as *const T as i64
}

//the code below is horrible
//borrow doesn't return T, it returns Ref<T>
//we need to dereference it to get to the T inside
//is_same takes borrow so reapply the ampersand
fn is_same_subscriber<T: Subscriber>(lhs: Rc<RefCell<T>>, rhs: Rc<RefCell<T>>) -> bool {
    let lhs = lhs.clone();
    let rhs = rhs.clone();
    let res = is_same(&*lhs.borrow(), &*rhs.borrow()); //needed to live long enough
    res
}

pub trait Subscriber {
    fn new_message(&mut self, bytes: &[u8]);
}

pub struct Broker<T: Subscriber> {
    tree: Node<T>,
}

struct Node<T: Subscriber> {
    children: HashMap<String, Node<T>>,
    leaves: Vec<Subscription<T>>,
}

struct Subscription<T: Subscriber> {
    subscriber: Rc<RefCell<T>>,
    topic: String,
}

impl<T: Subscriber> Subscription<T> {
    fn new(subscriber: Rc<RefCell<T>>, topic: &str) -> Self {
        Subscription { subscriber: subscriber.clone(), topic: topic.to_string() }
    }
}

impl<T: Subscriber> Node<T> {
    fn new() -> Self {
        Node { children: HashMap::new(), leaves: vec![] }
    }

    fn add_subscription(&mut self, subscription: Subscription<T>) {
        self.leaves.push(subscription);
    }
}

impl<T: Subscriber> Broker<T> {
    pub fn new() -> Self {
        Broker { tree: Node::new() }
    }

    pub fn subscribe(&mut self, subscriber: Rc<RefCell<T>>, topics: &[&str]) {
        for topic in topics {
            let sub_parts : Vec<&str> = topic.split("/").collect();
            Self::ensure_node_exists(&sub_parts, &mut self.tree);
            Self::add_subscription_to_node(&mut self.tree, subscriber.clone(), &sub_parts, topic);
        }
    }

    pub fn unsubscribe_all(&mut self, subscriber: Rc<RefCell<T>>) {
        Self::unsubscribe_all_impl(&mut self.tree, subscriber.clone());
    }

    pub fn unsubscribe(&mut self, subscriber: Rc<RefCell<T>>, topics: &[&str]) {
        Self::unsubscribe_impl(&mut self.tree, subscriber.clone(), topics);
    }

    pub fn publish(&self, topic: &str, payload: &[u8]) {
        let pub_parts : Vec<&str> = topic.split("/").collect();
        Self::publish_impl(&self.tree, &pub_parts, &payload);
    }

    fn ensure_node_exists(sub_parts: &[&str], node: &mut Node<T>) {
        if sub_parts.len() == 0 {
            return;
        }

        let part = &sub_parts[0][..];
        if !node.children.contains_key(part) {
            node.children.insert(sub_parts[0].to_string(), Node::new());
        }

        Self::ensure_node_exists(&sub_parts[1..], node.children.get_mut(part).unwrap());
    }

    fn add_subscription_to_node(tree: &mut Node<T>, subscriber: Rc<RefCell<T>>, sub_parts: &[&str], topic: &str) {
        if sub_parts.len() < 1 {
            panic!("oops");
        }

        let part = &sub_parts[0][..];
        let node = tree.children.get_mut(part).unwrap();
        let sub_parts = &sub_parts[1..];

        if sub_parts.len() == 0 {
            node.add_subscription(Subscription::new(subscriber.clone(), topic));
        } else {
            Self::add_subscription_to_node(node, subscriber, sub_parts, topic);
        }
    }

    fn publish_impl(tree: &Node<T>, pub_parts: &[&str], payload: &[u8]) {
        if pub_parts.len() < 1 {
            panic!("oops");
        }

        let part = &pub_parts[0][..];
        let node = tree.children.get(part);
        let pub_parts = &pub_parts[1..];

        match node {
            None => {
                return; //didn't find a subscriber
            },
            Some(node) => {
                if pub_parts.len() == 0 {
                    for subscription in &node.leaves {
                        let subscriber = subscription.subscriber.clone();
                        subscriber.borrow_mut().new_message(payload);
                    }
                } else {
                    Self::publish_impl(node, pub_parts, payload);
                }
            }
        }
    }

    fn unsubscribe_all_impl(tree: &mut Node<T>, subscriber: Rc<RefCell<T>>) {
        tree.leaves.retain(|s| !is_same_subscriber(s.subscriber.clone(), subscriber.clone()));

        if tree.children.len() == 0 {
            return;
        }

        for (_, node) in tree.children.iter_mut() {
            Self::unsubscribe_all_impl(node, subscriber.clone());
        }
    }

    fn unsubscribe_impl(tree: &mut Node<T>, subscriber: Rc<RefCell<T>>, topics: &[&str]) {
        tree.leaves.retain(|s| {
            let is_same_subscriber = is_same_subscriber(s.subscriber.clone(), subscriber.clone());
            //I have no idea why t below is &&&str, I added a tripe deref cos the compiler told me to
            let is_same_topic = topics.into_iter().find(|t| ***t == s.topic).is_some();
            !is_same_subscriber || !is_same_topic
        });

        if tree.children.len() == 0 {
            return;
        }

        for (_, node) in tree.children.iter_mut() {
            Self::unsubscribe_impl(node, subscriber.clone(), topics);
        }
    }
}

#[cfg(test)]
struct TestSubscriber {
    msgs: Vec<Vec<u8>>,
}

#[cfg(test)]
impl TestSubscriber {
    fn new() -> Self {
        TestSubscriber{msgs: vec![]}
    }
}

#[cfg(test)]
impl Subscriber for TestSubscriber {
    fn new_message(&mut self, bytes: &[u8]) {
        self.msgs.push(bytes.to_vec());
    }
}

#[test]
fn test_subscribe() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();
    broker.publish("topics/foo", &[0, 1, 2]);
    assert_eq!(subscriber.borrow().msgs.len(), 0);

    broker.subscribe(subscriber.clone(), &["topics/foo"]);
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4, 6]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);

    broker.subscribe(subscriber.clone(), &["topics/bar"]);
    broker.publish("topics/foo", &[1, 3, 5, 7]);
    broker.publish("topics/bar", &[2, 4]);
    assert_eq!(subscriber.borrow().msgs.len(), 3);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[1, 3, 5, 7]);
    assert_eq!(subscriber.borrow().msgs[2], &[2, 4]);
}

#[test]
fn test_unsubscribe_all() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();

    broker.subscribe(subscriber.clone(), &["topics/foo"]);
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4, 6]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);

    broker.unsubscribe_all(subscriber.clone());
    broker.publish("topics/foo", &[0, 1, 9]);
    broker.publish("topics/bar", &[2, 4]);
    broker.publish("topics/baz", &[2, 4, 7, 11]);

    //shouldn't have changed
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
}

#[test]
fn test_unsubscribe_one() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();

    broker.subscribe(subscriber.clone(), &["topics/foo", "topics/bar"]);
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4]); //should get this
    broker.publish("topics/baz", &[2, 4, 7, 11]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 2);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[2, 4]);

    broker.unsubscribe(subscriber.clone(), &["topics/foo"]);
    broker.publish("topics/foo", &[0, 1, 9]); //shouldn't get this
    broker.publish("topics/bar", &[2, 4]); //should get this
    broker.publish("topics/baz", &[2, 4, 7, 11]); //shouldn't get this

    assert_eq!(subscriber.borrow().msgs.len(), 3);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[2, 4]);
    assert_eq!(subscriber.borrow().msgs[2], &[2, 4]);
}
<|endoftext|>


<commit_before>use std::mem;
use std::ptr;
use std::io::{File, BufferedReader};

use utils;
use cursor::Cursor;

pub struct Buffer {
    length: uint,
    pub first_line: Link,
    pub last_line: Rawlink,

    pub cursor: Cursor,
}

impl Buffer {
    /// Create a new buffer instance
    pub fn new() -> Buffer {
        Buffer {
            length: 0,
            first_line: None,
            last_line: Rawlink::none(),
            cursor: Cursor::new(),
        }
    }

    /// Create a new buffer instance and load the given file
    pub fn new_from_file(path: &Path) -> Buffer {
        let mut file = BufferedReader::new(File::open(path));
        let lines: Vec<String> = file.lines().map(|x| x.unwrap()).collect();
        let mut buffer = Buffer::new();

        // for every line in the file we add a corresponding line to the buffer
        for line in lines.iter() {
            buffer.add_line(line.clone());
        }

        // FIXME: This doesn't seem like a good idea..
        // Update the `cursor.line` to point to the `buffer.first_line`
        let b = buffer.first_line.clone();
        let cursor = Cursor{x:0, y:0, line: b};
        mem::replace(&mut buffer.cursor, cursor);

        buffer
    }

    /// Draw the contents of the buffer
    ///
    /// Loops over each line in the buffer and draws it to the screen
    pub fn draw_contents(&self) {
        for (index, line) in self.iter_lines().enumerate() {
            utils::draw(index, line.value.clone());
        }
    }

    /// Add a line to the front/top of the buffer
    pub fn push_front_line(&mut self, mut new_head: Box<Line>) {
        match self.first_line {
            None => {
                self.last_line = Rawlink::some(&mut *new_head);
                self.first_line = link_with_prev(new_head, Rawlink::none());
            }
            Some(ref mut head) => {
                new_head.prev = Rawlink::none();
                head.prev = Rawlink::some(&mut *new_head);
                mem::swap(head, &mut new_head);
                head.next = Some(new_head);
            }
        }
        self.length += 1;
    }

    /// Add a line to the back/end of the buffer
    ///
    /// If there is no last_line, ie the buffer is empty, then it will
    /// defer to `push_front_line`.
    pub fn push_back_line(&mut self, mut new_tail: Box<Line>) {
        match self.last_line.resolve() {
            None => return self.push_front_line(new_tail),
            Some(tail) => {
                self.last_line = Rawlink::some(&mut *new_tail);
                tail.next = link_with_prev(new_tail, Rawlink::some(tail));
            }
        }
        self.length += 1
    }

    /// Add a line to the buffer
    pub fn add_line(&mut self, elt: String) {
        self.push_back_line(box Line::new(elt));
    }

    /// Get the length of the buffer - number of lines
    pub fn len(&self) -> uint {
        self.length
    }

    /// Iterate over each line in the buffer
    pub fn iter_lines<'a>(&'a self) -> Items<'a> {
        Items { nelem: self.len(), head: &self.first_line, tail: self.last_line }
    }
}

fn link_with_prev(mut next: Box<Line>, prev: Rawlink) -> Link {
    next.prev = prev;
    Some(next)
}

struct Items<'a> {
    head: &'a Link,
    tail: Rawlink,
    nelem: uint,
}

impl<'a> Iterator<&'a Line> for Items<'a> {
    #[inline]
    fn next(&mut self) -> Option<&'a Line> {
        if self.nelem == 0 {
            return None;
        }
        self.head.as_ref().map(|head| {
            self.nelem -= 1;
            self.head = &head.next;
            &**head
        })
    }
}

#[deriving(Clone)]
pub struct Line {
    pub next: Link,
    pub prev: Rawlink,
    value: String,
}

impl Line {
    /// Create a new line instance
    pub fn new(v: String) -> Line {
        Line{value: v, next: None, prev: Rawlink::none()}
    }

    /// Get the length of the current line
    pub fn len(&self) -> uint {
        self.value.len()
    }
}

pub type Link = Option<Box<Line>>;

#[deriving(Clone)]
struct Rawlink {
    p: *mut Line,
}

impl Rawlink {
    fn none() -> Rawlink {
        Rawlink{p: ptr::null_mut()}
    }

    fn some(n: &mut Line) -> Rawlink {
        Rawlink{p: n}
    }

    pub fn resolve<'a>(&mut self) -> Option<&'a mut Line> {
        if self.p.is_null() {
            None
        } else {
            Some(unsafe { mem::transmute(self.p) })
        }
    }
}
<commit_msg>Sort public and private methods<commit_after>use std::mem;
use std::ptr;
use std::io::{File, BufferedReader};

use utils;
use cursor::Cursor;

pub struct Buffer {
    length: uint,
    pub first_line: Link,
    pub last_line: Rawlink,

    pub cursor: Cursor,
}

impl Buffer {
    /// Create a new buffer instance
    pub fn new() -> Buffer {
        Buffer {
            length: 0,
            first_line: None,
            last_line: Rawlink::none(),
            cursor: Cursor::new(),
        }
    }

    /// Create a new buffer instance and load the given file
    pub fn new_from_file(path: &Path) -> Buffer {
        let mut file = BufferedReader::new(File::open(path));
        let lines: Vec<String> = file.lines().map(|x| x.unwrap()).collect();
        let mut buffer = Buffer::new();

        // for every line in the file we add a corresponding line to the buffer
        for line in lines.iter() {
            buffer.add_line(line.clone());
        }

        // FIXME: This doesn't seem like a good idea..
        // Update the `cursor.line` to point to the `buffer.first_line`
        let b = buffer.first_line.clone();
        let cursor = Cursor{x:0, y:0, line: b};
        mem::replace(&mut buffer.cursor, cursor);

        buffer
    }

    /// Draw the contents of the buffer
    ///
    /// Loops over each line in the buffer and draws it to the screen
    pub fn draw_contents(&self) {
        for (index, line) in self.iter_lines().enumerate() {
            utils::draw(index, line.value.clone());
        }
    }

    /// Add a line to the buffer
    pub fn add_line(&mut self, elt: String) {
        self.push_back_line(box Line::new(elt));
    }

    /// Get the length of the buffer - number of lines
    pub fn len(&self) -> uint {
        self.length
    }

    /// Iterate over each line in the buffer
    pub fn iter_lines<'a>(&'a self) -> Items<'a> {
        Items { nelem: self.len(), head: &self.first_line, tail: self.last_line }
    }

    /// Add a line to the front/top of the buffer
    fn push_front_line(&mut self, mut new_head: Box<Line>) {
        match self.first_line {
            None => {
                self.last_line = Rawlink::some(&mut *new_head);
                self.first_line = link_with_prev(new_head, Rawlink::none());
            }
            Some(ref mut head) => {
                new_head.prev = Rawlink::none();
                head.prev = Rawlink::some(&mut *new_head);
                mem::swap(head, &mut new_head);
                head.next = Some(new_head);
            }
        }
        self.length += 1;
    }

    /// Add a line to the back/end of the buffer
    ///
    /// If there is no last_line, ie the buffer is empty, then it will
    /// defer to `push_front_line`.
    fn push_back_line(&mut self, mut new_tail: Box<Line>) {
        match self.last_line.resolve() {
            None => return self.push_front_line(new_tail),
            Some(tail) => {
                self.last_line = Rawlink::some(&mut *new_tail);
                tail.next = link_with_prev(new_tail, Rawlink::some(tail));
            }
        }
        self.length += 1
    }

}

fn link_with_prev(mut next: Box<Line>, prev: Rawlink) -> Link {
    next.prev = prev;
    Some(next)
}

struct Items<'a> {
    head: &'a Link,
    tail: Rawlink,
    nelem: uint,
}

impl<'a> Iterator<&'a Line> for Items<'a> {
    #[inline]
    fn next(&mut self) -> Option<&'a Line> {
        if self.nelem == 0 {
            return None;
        }
        self.head.as_ref().map(|head| {
            self.nelem -= 1;
            self.head = &head.next;
            &**head
        })
    }
}

#[deriving(Clone)]
pub struct Line {
    pub next: Link,
    pub prev: Rawlink,
    value: String,
}

impl Line {
    /// Create a new line instance
    pub fn new(v: String) -> Line {
        Line{value: v, next: None, prev: Rawlink::none()}
    }

    /// Get the length of the current line
    pub fn len(&self) -> uint {
        self.value.len()
    }
}

pub type Link = Option<Box<Line>>;

#[deriving(Clone)]
struct Rawlink {
    p: *mut Line,
}

impl Rawlink {
    fn none() -> Rawlink {
        Rawlink{p: ptr::null_mut()}
    }

    fn some(n: &mut Line) -> Rawlink {
        Rawlink{p: n}
    }

    pub fn resolve<'a>(&mut self) -> Option<&'a mut Line> {
        if self.p.is_null() {
            None
        } else {
            Some(unsafe { mem::transmute(self.p) })
        }
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2014 Kashyap
//
// 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.

pub fn outb (port: u16, value: u8) {
	unsafe {
	asm!("out %al, %dx"::"{al}"(value), "{dx}"(port));
	}
}

pub fn inb(port: u16) -> u8 {
        let ret : u8;
	unsafe {
        asm!("inb %dx, %al" : "={ax}"(ret) : "{dx}"(port));
	}
        return ret;
}

<commit_msg>read_eflags added<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2014 Kashyap
//
// 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.

pub fn outb (port: u16, value: u8) {
	unsafe {
	asm!("out %al, %dx"::"{al}"(value), "{dx}"(port));
	}
}

pub fn inb(port: u16) -> u8 {
        let ret : u8;
	unsafe {
        asm!("inb %dx, %al" : "={ax}"(ret) : "{dx}"(port));
	}
        return ret;
}

pub fn read_eflags() -> u64 { //TODO 64 bit hard coded
	let ret : u64;
	unsafe {
		asm!("pushf; pop $0" : "=r"(ret) : );
	}
	return ret;
}
<|endoftext|>