<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, File};
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};
use client;

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),
            _ => 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()
    }
}

#[derive(Debug, Clone)]
pub struct Event {
    pub changes: Changes,
    pub session: String,
}

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()),
        ].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(),
        }
    }
}

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

// TODO holy crap why is everything blocking? this is a mess
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 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 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);
    }
}

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

pub fn handle_event(server: &mut Server, event: Event, event_json: Json) {
    server.events.write_all(format!("{}", event_json).as_bytes()).unwrap();
    server.events.write_all("\n".as_bytes()).unwrap();
    server.events.flush().unwrap();
    let old_flow = time!("cloning", {
        server.flow.clone()
    });
    server.flow.quiesce(event.changes);
    let changes = time!("diffing", {
        server.flow.changes_from(old_flow)
    });
    for sender in server.senders.iter_mut() {
        let session_id = format!("{}", sender.get_mut().peer_addr().unwrap());
        let text = format!("{}", Event{changes: changes.clone(), session: session_id}.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, "./events");
    });

    let events = OpenOptions::new().write(true).append(true).open("./events").unwrap();
    let senders: Vec<sender::Sender<WebSocketStream>> = Vec::new();

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

    for server_event in server_events() {
        match server_event {

            ServerEvent::Sync((mut sender,user_id)) => {

                // Add a session to the session table
                let session_id = format!("{}", sender.get_mut().peer_addr().unwrap());
				let mut add_session = client::insert_fact(&"sessions",&vec!["id","status"],&vec![Value::String(session_id.clone()),
				                                                                       		   Value::Float(1f64)
				                                                                      	     ],None);

				// If we have a user ID, add a mapping from the session ID to the user ID
                add_session = match user_id {
                    Some(user_id) => {

                        client::insert_fact(&"session id to user id",&vec!["session id","user id"],&vec![Value::String(session_id.clone()),
                                                                                Value::String(user_id),
                                                                                ],Some(add_session))
                    },
                    None => add_session,
                };
                let json = add_session.to_json();
                handle_event(&mut server, add_session, json);

                let changes = server.flow.as_changes();
                let text = format!("{}", Event{changes: changes, session: session_id}.to_json());
                match sender.send_message(Message::Text(text)) {
                    Ok(_) => (),
                    Err(error) => println!("Send error: {}", error),
                };
                server.senders.push(sender)
            }

            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
                                                        });

                // Properly clean up connections and the session table
                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());

                        match sessions.find_maybe("id",&ip_string) {
                            Some(session) => {
                            	let closed_session = session.clone();
                                let mut close_session_values = &mut closed_session.values.to_vec();
                                let status_ix = match closed_session.names.iter().position(|name| name == "status") {
                                	Some(ix) => ix,
                                	None => panic!("No field named \"status\""),
                                };
                                close_session_values[status_ix] = Value::Float(0f64);

                                let change = Change {
                                                        fields: sessions.fields.clone(),
                                                        insert: vec![close_session_values.clone()],
                                                        remove: vec![session.values.to_vec().clone()],
                                                    };
                                let event = Event{changes: vec![("sessions".to_string(),change)], session: "".to_string()};
                                let json = event.to_json();
                                handle_event(&mut server, event, json);

                            },
                            None => println!("No session found"),
                        }

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

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,
    }
}<commit_msg>Decode columns too<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, File};
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};
use client;

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()
    }
}

#[derive(Debug, Clone)]
pub struct Event {
    pub changes: Changes,
    pub session: String,
}

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()),
        ].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(),
        }
    }
}

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

// TODO holy crap why is everything blocking? this is a mess
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 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 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);
    }
}

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

pub fn handle_event(server: &mut Server, event: Event, event_json: Json) {
    server.events.write_all(format!("{}", event_json).as_bytes()).unwrap();
    server.events.write_all("\n".as_bytes()).unwrap();
    server.events.flush().unwrap();
    let old_flow = time!("cloning", {
        server.flow.clone()
    });
    server.flow.quiesce(event.changes);
    let changes = time!("diffing", {
        server.flow.changes_from(old_flow)
    });
    for sender in server.senders.iter_mut() {
        let session_id = format!("{}", sender.get_mut().peer_addr().unwrap());
        let text = format!("{}", Event{changes: changes.clone(), session: session_id}.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, "./events");
    });

    let events = OpenOptions::new().write(true).append(true).open("./events").unwrap();
    let senders: Vec<sender::Sender<WebSocketStream>> = Vec::new();

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

    for server_event in server_events() {
        match server_event {

            ServerEvent::Sync((mut sender,user_id)) => {

                // Add a session to the session table
                let session_id = format!("{}", sender.get_mut().peer_addr().unwrap());
				let mut add_session = client::insert_fact(&"sessions",&vec!["id","status"],&vec![Value::String(session_id.clone()),
				                                                                       		   Value::Float(1f64)
				                                                                      	     ],None);

				// If we have a user ID, add a mapping from the session ID to the user ID
                add_session = match user_id {
                    Some(user_id) => {

                        client::insert_fact(&"session id to user id",&vec!["session id","user id"],&vec![Value::String(session_id.clone()),
                                                                                Value::String(user_id),
                                                                                ],Some(add_session))
                    },
                    None => add_session,
                };
                let json = add_session.to_json();
                handle_event(&mut server, add_session, json);

                let changes = server.flow.as_changes();
                let text = format!("{}", Event{changes: changes, session: session_id}.to_json());
                match sender.send_message(Message::Text(text)) {
                    Ok(_) => (),
                    Err(error) => println!("Send error: {}", error),
                };
                server.senders.push(sender)
            }

            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
                                                        });

                // Properly clean up connections and the session table
                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());

                        match sessions.find_maybe("id",&ip_string) {
                            Some(session) => {
                            	let closed_session = session.clone();
                                let mut close_session_values = &mut closed_session.values.to_vec();
                                let status_ix = match closed_session.names.iter().position(|name| name == "status") {
                                	Some(ix) => ix,
                                	None => panic!("No field named \"status\""),
                                };
                                close_session_values[status_ix] = Value::Float(0f64);

                                let change = Change {
                                                        fields: sessions.fields.clone(),
                                                        insert: vec![close_session_values.clone()],
                                                        remove: vec![session.values.to_vec().clone()],
                                                    };
                                let event = Event{changes: vec![("sessions".to_string(),change)], session: "".to_string()};
                                let json = event.to_json();
                                handle_event(&mut server, event, json);

                            },
                            None => println!("No session found"),
                        }

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

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,
    }
}<|endoftext|>


<commit_before>extern crate websocket;
extern crate rustc_serialize;

mod emulator;

use std::thread;

use websocket::{Server, Message, Sender, Receiver};
use websocket::header::WebSocketProtocol;

fn main() {
	let server = Server::bind("127.0.0.1:2794").unwrap();

	for connection in server {
		// Spawn a new thread for each connection.
		thread::spawn(move || {
			let request = connection.unwrap().read_request().unwrap(); // Get the request
			let headers = request.headers.clone(); // Keep the headers so we can check them

			request.validate().unwrap(); // Validate the request

			let mut response = request.accept(); // Form a response

			if let Some(&WebSocketProtocol(ref protocols)) = headers.get() {
				if protocols.contains(&("rust-websocket".to_string())) {
					// We have a protocol we want to use
					response.headers.set(WebSocketProtocol(vec!["rust-websocket".to_string()]));
				}
			}

			let mut client = response.send().unwrap(); // Send the response

			let ip = client.get_mut_sender()
				.get_mut()
				.peer_addr()
				.unwrap();

			println!("Connection from {}", ip);

			let message = Message::Text("Hello".to_string());
			client.send_message(message).unwrap();

			let (mut sender, mut receiver) = client.split();

			for message in receiver.incoming_messages() {
				let message = message.unwrap();

				match message {
					Message::Close(_) => {
						let message = Message::Close(None);
						sender.send_message(message).unwrap();
						println!("Client {} disconnected", ip);
						return;
					}
					Message::Ping(data) => {
						let message = Message::Pong(data);
						sender.send_message(message).unwrap();
					}
					_ => {
            // this is where we are echoing back the message sent to us
            let encoded = Message::Text(emulator::serialize());
            sender.send_message(encoded).unwrap();
          }
				}
			}
		});
	}
}
<commit_msg>clean up whitespace<commit_after>extern crate websocket;
extern crate rustc_serialize;

mod emulator;

use std::thread;

use websocket::{Server, Message, Sender, Receiver};
use websocket::header::WebSocketProtocol;

fn main() {
    let server = Server::bind("127.0.0.1:2794").unwrap();

    for connection in server {
        // Spawn a new thread for each connection.
        thread::spawn(move || {
            let request = connection.unwrap().read_request().unwrap(); // Get the request
            let headers = request.headers.clone(); // Keep the headers so we can check them

            request.validate().unwrap(); // Validate the request

            let mut response = request.accept(); // Form a response

            if let Some(&WebSocketProtocol(ref protocols)) = headers.get() {
                if protocols.contains(&("rust-websocket".to_string())) {
                    // We have a protocol we want to use
                    response.headers.set(WebSocketProtocol(vec!["rust-websocket".to_string()]));
                }
            }

            let mut client = response.send().unwrap(); // Send the response

            let ip = client.get_mut_sender()
            .get_mut()
            .peer_addr()
            .unwrap();

            println!("Connection from {}", ip);

            let message = Message::Text("Hello".to_string());
            client.send_message(message).unwrap();

            let (mut sender, mut receiver) = client.split();

            for message in receiver.incoming_messages() {
                let message = message.unwrap();

                match message {
                    Message::Close(_) => {
                        let message = Message::Close(None);
                        sender.send_message(message).unwrap();
                        println!("Client {} disconnected", ip);
                        return;
                    }
                    Message::Ping(data) => {
                        let message = Message::Pong(data);
                        sender.send_message(message).unwrap();
                    }
                    _ => {
                        // this is where we are echoing back the message sent to us
                        let encoded = Message::Text(emulator::serialize());
                        sender.send_message(encoded).unwrap();
                    }
                }
            }
        });
    }
}
<|endoftext|>


<commit_before>// pub fn decode_at_index(s: String, k: i32) -> String {
//     use std::iter::FromIterator;
//     let mut length = 0_usize;
//     let mut cache = Vec::new();
//     let mut result = String::new();
//     let mut cache_clean = false;
//     for c in s.chars() {
//         if let Some(times) = c.to_digit(10) {
//             length *= times as usize;
//             //result += &String::from_iter(cache);
//             //result = result.repeat(times as usize);
//             cache_clean = true;
//         } else {
//             if cache_clean {
//                 cache = vec![];
//                 cache_clean = false;
//             }
//             length += 1;
//             cache.push(c);
//         }

//         //println!("{}", result);
//         if length == k as usize {
//             return cache.pop().unwrap().to_string();
//         }

//         if length > k as usize {
//             println!("{}", length);
//             return result.get(k as usize - 1..k as usize).unwrap().into();
//         }
//     }

//     result
// }

pub fn decode_at_index(s: String, k: i32) -> String {
    inner_helper(&s, k, 0, vec![])
}

fn inner_helper(s: &str, k: i32, last_sum_k: i32, last_cache: Vec<char>) -> String {
    println!("s: {}, k: {}, last_cache: {:?}", s, k, last_cache);
    let mut cache = last_cache;
    let mut cache_new = false;
    let mut mut_k = k;
    for (ind, c) in s.chars().enumerate() {
        println!("cache is: {:?}", cache);
        if let Some(times) = c.to_digit(10) {
            dbg!(times as i32 * cache.len() as i32);
            if (times as i32 * cache.len() as i32) >= k {
                if k > cache.len() as i32 {
                    return cache[((k + 1) % cache.len() as i32) as usize].to_string();
                } else {
                    return cache[k as usize - 1].to_string();
                }
            } else {
                return inner_helper(
                    &s[ind + 1..s.len()],
                    k - times as i32 * (cache.len() as i32 + last_sum_k),
                    times as i32 * (cache.len() as i32 + last_sum_k),
                    cache,
                );
            }
        } else {
            mut_k -= 1;
            if mut_k == 0 {
                return c.to_string();
            }

            if !cache_new {
                cache = vec![];
                cache_new = true;
            }
            cache.push(c);
        }
    }

    if k > cache.len() as i32 {
        return cache[((k + 1) % cache.len() as i32) as usize].to_string();
    } else {
        return cache[k as usize - 1].to_string();
    }
}

fn main() {
    // assert_eq!(
    //     decode_at_index("leet2code3".to_string(), 10),
    //     "o".to_string()
    // );
    // assert_eq!(decode_at_index("ha22".to_string(), 5), "h".to_string());
    // assert_eq!(
    //     decode_at_index("a2345678999999999999999".to_string(), 1),
    //     "a".to_string()
    // );
    // assert_eq!(decode_at_index("a23".to_string(), 6), "a".to_string());

    assert_eq!(
        decode_at_index("a2b3c4d5e6f7g8h9".to_string(), 9),
        "c".to_string()
    );
}
<commit_msg>finish<commit_after>// pub fn decode_at_index(s: String, k: i32) -> String {
//     use std::iter::FromIterator;
//     let mut length = 0_usize;
//     let mut cache = Vec::new();
//     let mut result = String::new();
//     let mut cache_clean = false;
//     for c in s.chars() {
//         if let Some(times) = c.to_digit(10) {
//             length *= times as usize;
//             //result += &String::from_iter(cache);
//             //result = result.repeat(times as usize);
//             cache_clean = true;
//         } else {
//             if cache_clean {
//                 cache = vec![];
//                 cache_clean = false;
//             }
//             length += 1;
//             cache.push(c);
//         }

//         //println!("{}", result);
//         if length == k as usize {
//             return cache.pop().unwrap().to_string();
//         }

//         if length > k as usize {
//             println!("{}", length);
//             return result.get(k as usize - 1..k as usize).unwrap().into();
//         }
//     }

//     result
// }

pub fn decode_at_index(s: String, k: i32) -> String {
    //inner_helper(&s, k, 0, vec![])
    inner_helper(&s, k as i64)
}

// fn inner_helper(s: &str, k: i32, last_sum_k: i32, last_cache: Vec<char>) -> String {
//     println!("s: {}, k: {}, last_cache: {:?}", s, k, last_cache);
//     let mut cache = last_cache;
//     let mut cache_new = false;
//     let mut mut_k = k;
//     for (ind, c) in s.chars().enumerate() {
//         println!("cache is: {:?}", cache);
//         if let Some(times) = c.to_digit(10) {
//             dbg!(times as i32 * cache.len() as i32);
//             if (times as i32 * cache.len() as i32) >= k {
//                 if k > cache.len() as i32 {
//                     return cache[((k + 1) % cache.len() as i32) as usize].to_string();
//                 } else {
//                     return cache[k as usize - 1].to_string();
//                 }
//             } else {
//                 return inner_helper(
//                     &s[ind + 1..s.len()],
//                     k - times as i32 * (cache.len() as i32 + last_sum_k),
//                     times as i32 * (cache.len() as i32 + last_sum_k),
//                     cache,
//                 );
//             }
//         } else {
//             mut_k -= 1;
//             if mut_k == 0 {
//                 return c.to_string();
//             }

//             if !cache_new {
//                 cache = vec![];
//                 cache_new = true;
//             }
//             cache.push(c);
//         }
//     }

//     if k > cache.len() as i32 {
//         return cache[((k + 1) % cache.len() as i32) as usize].to_string();
//     } else {
//         return cache[k as usize - 1].to_string();
//     }
// }

fn _inner_helper_v0(s: &str, mut k: i32) -> String {
    let mut groups = vec![];
    let (mut last_group, mut this_group) = (0, 0);
    let mut this_group_cache: Vec<char> = vec![];
    let mut group_cache = vec![];

    for (ind, c) in s.chars().enumerate() {
        if let Some(times) = c.to_digit(10) {
            group_cache.push(this_group_cache.clone());
            this_group_cache.clear();

            last_group += this_group;
            last_group *= times;
            groups.push(last_group);
            this_group = 0;
            if last_group as i32 > k {
                break;
            }
        } else {
            this_group_cache.push(c);
            this_group += 1;
        }
    }

    dbg!(&groups);
    dbg!(&group_cache);

    for x in (0..groups.len()).rev() {
        if (groups[x] as i32) < k {
            k %= groups[x] as i32;
            dbg!(x);
            break;
        }
    }
    dbg!(k);

    String::new()
}

fn inner_helper_v1(s: &str, k: i32) {
    let mut each_section: Vec<Vec<char>> = vec![];
    let mut section_cache: Vec<char> = vec![];

    let mut length_before_multi: Vec<i32> = vec![];

    let mut lenght_after_multi: Vec<i32> = vec![];

    let mut last_length_after_multi = 0;
    let mut last = true;
    for c in s.chars() {
        if let Some(times) = c.to_digit(10) {
            length_before_multi.push(last_length_after_multi + section_cache.len() as i32);
            lenght_after_multi
                .push((last_length_after_multi + section_cache.len() as i32) * times as i32);

            last_length_after_multi =
                (last_length_after_multi + section_cache.len() as i32) * times as i32;

            each_section.push(section_cache.clone());
            section_cache.clear();
        } else {
            section_cache.push(c);
        }

        if last_length_after_multi > k {
            last = false;
            break;
        }
    }

    // last
    if last {
        length_before_multi.push(last_length_after_multi + section_cache.len() as i32);
        each_section.push(section_cache.clone());
    }

    dbg!(each_section);
    dbg!(lenght_after_multi);
    dbg!(length_before_multi);
}

fn inner_helper(s: &str, k: i64) -> String {
    let mut l = 0;
    for c in s.chars() {
        if let Some(times) = c.to_digit(10) {
            if k <= l * (times as i64) {
                if k % l == 0 {
                    return inner_helper(s, l);
                }
                return inner_helper(s, k % l);
            }
            l *= times as i64;
        } else {
            l += 1;
            if l == k {
                return c.to_string();
            }
        }
    }
    "".to_string()
}

fn main() {
    assert_eq!(
        decode_at_index("leet2code3".to_string(), 10),
        "o".to_string()
    );

    assert_eq!(decode_at_index("ha22".to_string(), 5), "h".to_string());

    assert_eq!(
        decode_at_index("a2345678999999999999999".to_string(), 1),
        "a".to_string()
    );

    assert_eq!(decode_at_index("a23".to_string(), 6), "a".to_string());

    assert_eq!(
        decode_at_index("a2b3c4d5e6f7g8h9".to_string(), 9),
        "b".to_string()
    );

    assert_eq!(
        decode_at_index("ajx37nyx97niysdrzice4petvcvmcgqn282zicpbx6okybw93vhk782unctdbgmcjmbqn25rorktmu5ig2qn2y4xagtru2nehmsp".to_string(), 976159153),
        "a".to_string()
    );

    //dbg!(inner_helper("leet2code3", 10));
    //dbg!(inner_helper("a2b3c4d5e6f7g8h9", 9));
    //dbg!(inner_helper("ha22", 3));
    //dbg!(inner_helper("a23", 6));
}
<|endoftext|>


<commit_before>use bencode::{BDict, BString, BInt};
use std::{error, fmt};
use convert::TryFrom;

#[derive(Default, Clone)]
pub struct MetaInfo {
    pub announce: String,
    pub announce_list: Vec<Vec<String>>,
    pub comment: Option<String>,
    pub created_by: Option<String>,
    pub creation_date: Option<u32>,
    pub info: FileInfo,
}

#[derive(Debug)]
pub struct MetaInfoError {
    kind: MetaInfoErrorKind,
}

impl fmt::Display for MetaInfoError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Error while parsing metainfo: {}", self._description())
    }
}
impl MetaInfoError {
    pub fn missing_field(field: &str) -> MetaInfoError {
        MetaInfoError { kind: MetaInfoErrorKind::MissingField(field.to_string()) }
    }

    pub fn field_type(field: &str) -> MetaInfoError {
        MetaInfoError { kind: MetaInfoErrorKind::FieldIsWrongType(field.to_string()) }
    }

    pub fn invalid_data(field: &str) -> MetaInfoError {
        MetaInfoError { kind: MetaInfoErrorKind::InvalidDataFieldValue(field.to_string()) }
    }

    fn _description(&self) -> &str {
        match self.kind {
            MetaInfoErrorKind::MissingField(_) => "required field on file is missing",
            MetaInfoErrorKind::FieldIsWrongType(_) => "required field has wrong bencoding type",
            MetaInfoErrorKind::InvalidDataFieldValue(_) => {
                "required field has correct type but invalid data"
            }
        }
    }
}

impl error::Error for MetaInfoError {
    fn description(&self) -> &str {
        self._description()
    }
}

#[derive(Debug, Clone)]
pub enum MetaInfoErrorKind {
    MissingField(String),
    FieldIsWrongType(String),
    InvalidDataFieldValue(String),
}

impl TryFrom<BDict> for MetaInfo {
    type Err = MetaInfoError;

    fn try_from(bdict: BDict) -> Result<MetaInfo, MetaInfoError> {
        let dict = &bdict;
        let mut info: MetaInfo = Default::default();

        let announce: Option<String> = dict.get_copy("announce");
        let announce_list: Option<Vec<Vec<String>>> = dict.get_copy("announce_list");
        let comment: Option<String> = dict.get_copy("comment");
        let created_by: Option<String> = dict.get_copy("created_by");
        let creation_date: Option<BInt> = dict.get_copy("creation date");

        info.announce = try!(announce.ok_or(MetaInfoError::missing_field("annouce")));
        info.announce_list = announce_list.unwrap_or(Vec::new());
        info.comment = comment; //try!(comment.ok_or(MetaInfoError::missing_field("comment")));
        info.created_by = created_by;
        info.creation_date = creation_date.map(|bdict| bdict.to_i64() as u32);
        info.info = try!(MetaInfo::get_info(dict));
        Ok(info)
    }
}

impl MetaInfo {
    fn get_info(dict: &BDict) -> Result<FileInfo, MetaInfoError> {
        let mut info: FileInfo = Default::default();
        let bdict: BDict = try!(dict.get_copy("info").ok_or(MetaInfoError::missing_field("info")));
        info.piece_length = try!(bdict.get_copy("piece length")
            .map(|pl: BInt| pl.to_i64() as u64)
            .ok_or(MetaInfoError::missing_field("piece length")));
        info.private = bdict.get_copy("private").map(|p: BInt| p.to_i64() as u32);
        let pieces_bstr: BString = try!(bdict.get_copy("pieces")
            .ok_or(MetaInfoError::missing_field("pieces")));
        let pieces = pieces_bstr.to_bytes();
        let pieces_vec = (0..pieces.len() / 20)
            .map(|p| (&pieces[p..(p + 20)]).iter().map(|&b| b).collect())
            .collect::<Vec<SHA1Hash20b>>();

        info.pieces = pieces_vec;
        info.name = bdict.get_copy("name");

        let single_file_fields: (Option<BString>, Option<BInt>) = (bdict.get_copy("md5sum"),
                                                                   bdict.get_copy("length"));
        if let (md5sum, Some(length)) = single_file_fields {
            info.mode_info = ModeInfo::Single(SingleFileInfo {
                md5_sum: md5sum.map(|m| m.to_bytes()),
                length: length.to_i64() as u64,
            });
            return Ok(info);
        }

        let bdict_files = bdict.get_copy("files");
        let bdict_list: Vec<BDict> = try!(bdict_files.ok_or(MetaInfoError::missing_field("files")));
        let mut files = Vec::new();
        for fdict in bdict_list.into_iter() {
            let length: BInt = try!(fdict.get_copy("length")
                .ok_or(MetaInfoError::missing_field("length")));
            let md5_sum = fdict.get_copy("md5sum").map(|m: BString| m.to_bytes());
            let path: Vec<String> = try!(fdict.get_copy("path")
                .ok_or(MetaInfoError::missing_field("path")));
            files.push((length.to_i64() as u64, md5_sum, path));
        }

        info.mode_info = ModeInfo::Multi(MultiFileInfo { files: files });
        Ok(info)
    }
}

#[derive(Default, Clone)]
pub struct FileInfo {
    pub piece_length: u64,
    pub pieces: Vec<SHA1Hash20b>,
    pub private: Option<u32>,
    pub name: Option<String>,
    pub mode_info: ModeInfo,
}

#[derive(Clone)]
pub enum ModeInfo {
    Single(SingleFileInfo),
    Multi(MultiFileInfo),
}

impl Default for ModeInfo {
    fn default() -> ModeInfo {
        ModeInfo::Single(Default::default())
    }
}

#[derive(Debug, Default, Clone)]
pub struct SingleFileInfo {
    pub length: u64,
    pub md5_sum: Option<MD5Sum>,
}

#[derive(Debug, Default, Clone)]
pub struct MultiFileInfo {
    pub files: Vec<(u64, Option<MD5Sum>, FPath)>,
}

pub type MD5Sum = Vec<u8>;
pub type SHA1Hash20b = Vec<u8>;
pub type FPath = Vec<String>;
<commit_msg>Add skeleton Into for MetaInfo<commit_after>use bencode::{BDict, BString, BInt};
use std::{error, fmt};
use convert::TryFrom;

#[derive(Default, Clone)]
pub struct MetaInfo {
    pub announce: String,
    pub announce_list: Vec<Vec<String>>,
    pub comment: Option<String>,
    pub created_by: Option<String>,
    pub creation_date: Option<u32>,
    pub info: FileInfo,
}

#[derive(Debug)]
pub struct MetaInfoError {
    kind: MetaInfoErrorKind,
}

impl fmt::Display for MetaInfoError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Error while parsing metainfo: {}", self._description())
    }
}
impl MetaInfoError {
    pub fn missing_field(field: &str) -> MetaInfoError {
        MetaInfoError { kind: MetaInfoErrorKind::MissingField(field.to_string()) }
    }

    pub fn field_type(field: &str) -> MetaInfoError {
        MetaInfoError { kind: MetaInfoErrorKind::FieldIsWrongType(field.to_string()) }
    }

    pub fn invalid_data(field: &str) -> MetaInfoError {
        MetaInfoError { kind: MetaInfoErrorKind::InvalidDataFieldValue(field.to_string()) }
    }

    fn _description(&self) -> &str {
        match self.kind {
            MetaInfoErrorKind::MissingField(_) => "required field on file is missing",
            MetaInfoErrorKind::FieldIsWrongType(_) => "required field has wrong bencoding type",
            MetaInfoErrorKind::InvalidDataFieldValue(_) => {
                "required field has correct type but invalid data"
            }
        }
    }
}

impl error::Error for MetaInfoError {
    fn description(&self) -> &str {
        self._description()
    }
}

#[derive(Debug, Clone)]
pub enum MetaInfoErrorKind {
    MissingField(String),
    FieldIsWrongType(String),
    InvalidDataFieldValue(String),
}

impl TryFrom<BDict> for MetaInfo {
    type Err = MetaInfoError;

    fn try_from(bdict: BDict) -> Result<MetaInfo, MetaInfoError> {
        let dict = &bdict;
        let mut info: MetaInfo = Default::default();

        let announce: Option<String> = dict.get_copy("announce");
        let announce_list: Option<Vec<Vec<String>>> = dict.get_copy("announce_list");
        let comment: Option<String> = dict.get_copy("comment");
        let created_by: Option<String> = dict.get_copy("created_by");
        let creation_date: Option<BInt> = dict.get_copy("creation date");

        info.announce = try!(announce.ok_or(MetaInfoError::missing_field("annouce")));
        info.announce_list = announce_list.unwrap_or(Vec::new());
        info.comment = comment; //try!(comment.ok_or(MetaInfoError::missing_field("comment")));
        info.created_by = created_by;
        info.creation_date = creation_date.map(|bdict| bdict.to_i64() as u32);
        info.info = try!(MetaInfo::get_info(dict));
        Ok(info)
    }
}

impl Into<BDict> for MetaInfo {
    fn into(self) -> BDict {
        unimplemented!();
    }
}

impl MetaInfo {
    fn get_info(dict: &BDict) -> Result<FileInfo, MetaInfoError> {
        let mut info: FileInfo = Default::default();
        let bdict: BDict = try!(dict.get_copy("info").ok_or(MetaInfoError::missing_field("info")));
        info.piece_length = try!(bdict.get_copy("piece length")
            .map(|pl: BInt| pl.to_i64() as u64)
            .ok_or(MetaInfoError::missing_field("piece length")));
        info.private = bdict.get_copy("private").map(|p: BInt| p.to_i64() as u32);
        let pieces_bstr: BString = try!(bdict.get_copy("pieces")
            .ok_or(MetaInfoError::missing_field("pieces")));
        let pieces = pieces_bstr.to_bytes();
        let pieces_vec = (0..pieces.len() / 20)
            .map(|p| (&pieces[p..(p + 20)]).iter().map(|&b| b).collect())
            .collect::<Vec<SHA1Hash20b>>();

        info.pieces = pieces_vec;
        info.name = bdict.get_copy("name");

        let single_file_fields: (Option<BString>, Option<BInt>) = (bdict.get_copy("md5sum"),
                                                                   bdict.get_copy("length"));
        if let (md5sum, Some(length)) = single_file_fields {
            info.mode_info = ModeInfo::Single(SingleFileInfo {
                md5_sum: md5sum.map(|m| m.to_bytes()),
                length: length.to_i64() as u64,
            });
            return Ok(info);
        }

        let bdict_files = bdict.get_copy("files");
        let bdict_list: Vec<BDict> = try!(bdict_files.ok_or(MetaInfoError::missing_field("files")));
        let mut files = Vec::new();
        for fdict in bdict_list.into_iter() {
            let length: BInt = try!(fdict.get_copy("length")
                .ok_or(MetaInfoError::missing_field("length")));
            let md5_sum = fdict.get_copy("md5sum").map(|m: BString| m.to_bytes());
            let path: Vec<String> = try!(fdict.get_copy("path")
                .ok_or(MetaInfoError::missing_field("path")));
            files.push((length.to_i64() as u64, md5_sum, path));
        }

        info.mode_info = ModeInfo::Multi(MultiFileInfo { files: files });
        Ok(info)
    }
}

#[derive(Default, Clone)]
pub struct FileInfo {
    pub piece_length: u64,
    pub pieces: Vec<SHA1Hash20b>,
    pub private: Option<u32>,
    pub name: Option<String>,
    pub mode_info: ModeInfo,
}

#[derive(Clone)]
pub enum ModeInfo {
    Single(SingleFileInfo),
    Multi(MultiFileInfo),
}

impl Default for ModeInfo {
    fn default() -> ModeInfo {
        ModeInfo::Single(Default::default())
    }
}

#[derive(Debug, Default, Clone)]
pub struct SingleFileInfo {
    pub length: u64,
    pub md5_sum: Option<MD5Sum>,
}

#[derive(Debug, Default, Clone)]
pub struct MultiFileInfo {
    pub files: Vec<(u64, Option<MD5Sum>, FPath)>,
}

pub type MD5Sum = Vec<u8>;
pub type SHA1Hash20b = Vec<u8>;
pub type FPath = Vec<String>;
<|endoftext|>


<commit_before>use common::*;
use main;
use glw::gl_buffer::{GLSliceBuffer, Triangles, Lines};
use glw::gl_context::GLContext;
use glw::shader::Shader;
use glw::vertex;
use nalgebra::na::{Vec2, Vec3};
use ncollide3df32::bounding_volume::LooseBoundingVolume;
use ncollide3df32::bounding_volume::aabb::AABB;
use std::collections::HashMap;
use std::rc::Rc;

static MAX_WORLD_SIZE: uint = 40000;

#[deriving(Copy, Clone, PartialEq, Eq, Hash)]
pub enum BlockType {
  Grass,
  Dirt,
  Stone,
}

#[deriving(Clone)]
/// A voxel-ish block in the game world.
pub struct Block {
  pub block_type: BlockType,
  pub id: main::Id,
}

impl Block {
  // Construct outlines for this Block, to sharpen the edges.
  pub fn to_outlines(bounds: &AABB) -> [vertex::ColoredVertex, ..LINE_VERTICES_PER_BOX] {
    to_outlines(&bounds.loosened(0.002))
  }

  pub fn to_texture_triangles(bounds: &AABB) -> [vertex::WorldTextureVertex, ..TRIANGLE_VERTICES_PER_BOX] {
    let (x1, y1, z1) = (bounds.mins().x, bounds.mins().y, bounds.mins().z);
    let (x2, y2, z2) = (bounds.maxs().x, bounds.maxs().y, bounds.maxs().z);

    let vtx = |x, y, z, nx, ny, nz, tx, ty| {
      vertex::WorldTextureVertex {
        world_position: Vec3::new(x, y, z),
        texture_position: Vec2::new(tx, ty),
        normal: Vec3::new(nx, ny, nz),
      }
    };

    // hacky little solution so that we don't index right onto the edge of a
    // texture; if we do, we get edges showing up in rendering.
    let d = 0.001;

    // Remember: x increases to the right, y increases up, and z becomes more
    // negative as depth from the viewer increases.
    [
      // front
      vtx(x1, y1, z2,  0.0,  0.0,  1.0, 0.00 + d, 0.50 - d),
      vtx(x2, y2, z2,  0.0,  0.0,  1.0, 0.25 - d, 0.25 + d),
      vtx(x1, y2, z2,  0.0,  0.0,  1.0, 0.25 - d, 0.50 - d),
      vtx(x1, y1, z2,  0.0,  0.0,  1.0, 0.00 + d, 0.50 - d),
      vtx(x2, y1, z2,  0.0,  0.0,  1.0, 0.00 + d, 0.25 + d),
      vtx(x2, y2, z2,  0.0,  0.0,  1.0, 0.25 - d, 0.25 + d),
      // left
      vtx(x1, y1, z1, -1.0,  0.0,  0.0, 0.75 - d, 0.00 + d),
      vtx(x1, y2, z2, -1.0,  0.0,  0.0, 0.50 + d, 0.25 - d),
      vtx(x1, y2, z1, -1.0,  0.0,  0.0, 0.50 + d, 0.00 + d),
      vtx(x1, y1, z1, -1.0,  0.0,  0.0, 0.75 - d, 0.00 + d),
      vtx(x1, y1, z2, -1.0,  0.0,  0.0, 0.75 - d, 0.25 - d),
      vtx(x1, y2, z2, -1.0,  0.0,  0.0, 0.50 + d, 0.25 - d),
      // top
      vtx(x1, y2, z1,  0.0,  1.0,  0.0, 0.25 + d, 0.25 + d),
      vtx(x2, y2, z2,  0.0,  1.0,  0.0, 0.50 - d, 0.50 - d),
      vtx(x2, y2, z1,  0.0,  1.0,  0.0, 0.25 + d, 0.50 - d),
      vtx(x1, y2, z1,  0.0,  1.0,  0.0, 0.25 + d, 0.25 + d),
      vtx(x1, y2, z2,  0.0,  1.0,  0.0, 0.50 - d, 0.25 + d),
      vtx(x2, y2, z2,  0.0,  1.0,  0.0, 0.50 - d, 0.50 - d),
      // back
      vtx(x1, y1, z1,  0.0,  0.0, -1.0, 0.75 - d, 0.50 - d),
      vtx(x2, y2, z1,  0.0,  0.0, -1.0, 0.50 + d, 0.25 + d),
      vtx(x2, y1, z1,  0.0,  0.0, -1.0, 0.75 - d, 0.25 + d),
      vtx(x1, y1, z1,  0.0,  0.0, -1.0, 0.75 - d, 0.50 - d),
      vtx(x1, y2, z1,  0.0,  0.0, -1.0, 0.50 + d, 0.50 - d),
      vtx(x2, y2, z1,  0.0,  0.0, -1.0, 0.50 + d, 0.25 + d),
      // right
      vtx(x2, y1, z1,  1.0,  0.0,  0.0, 0.75 - d, 0.75 - d),
      vtx(x2, y2, z2,  1.0,  0.0,  0.0, 0.50 + d, 0.50 + d),
      vtx(x2, y1, z2,  1.0,  0.0,  0.0, 0.75 - d, 0.50 + d),
      vtx(x2, y1, z1,  1.0,  0.0,  0.0, 0.75 - d, 0.75 - d),
      vtx(x2, y2, z1,  1.0,  0.0,  0.0, 0.50 + d, 0.75 - d),
      vtx(x2, y2, z2,  1.0,  0.0,  0.0, 0.50 + d, 0.50 + d),
      // bottom
      vtx(x1, y1, z1,  0.0, -1.0,  0.0, 0.75 + d, 0.50 - d),
      vtx(x2, y1, z2,  0.0, -1.0,  0.0, 1.00 - d, 0.25 + d),
      vtx(x1, y1, z2,  0.0, -1.0,  0.0, 1.00 - d, 0.50 - d),
      vtx(x1, y1, z1,  0.0, -1.0,  0.0, 0.75 + d, 0.50 - d),
      vtx(x2, y1, z1,  0.0, -1.0,  0.0, 0.75 + d, 0.25 + d),
      vtx(x2, y1, z2,  0.0, -1.0,  0.0, 1.00 - d, 0.25 + d),
    ]
  }
}

pub struct BlockBuffers {
  id_to_index: HashMap<main::Id, uint>,
  index_to_id: Vec<main::Id>,

  triangles: GLSliceBuffer<vertex::WorldTextureVertex>,
  outlines: GLSliceBuffer<vertex::ColoredVertex>,
}

impl BlockBuffers {
  pub unsafe fn new(gl: &GLContext, color_shader: &Rc<Shader>, texture_shader: &Rc<Shader>) -> BlockBuffers {
    BlockBuffers {
      id_to_index: HashMap::new(),
      index_to_id: Vec::new(),
      triangles: GLSliceBuffer::new(
        gl,
        texture_shader.clone(),
        [ vertex::AttribData { name: "position", size: 3 },
          vertex::AttribData { name: "texture_position", size: 2 },
          vertex::AttribData { name: "vertex_normal", size: 3 },
        ],
        TRIANGLE_VERTICES_PER_BOX,
        MAX_WORLD_SIZE,
        Triangles
      ),
      outlines: GLSliceBuffer::new(
        gl,
        color_shader.clone(),
        [ vertex::AttribData { name: "position", size: 3 },
          vertex::AttribData { name: "in_color", size: 4 },
        ],
        LINE_VERTICES_PER_BOX,
        MAX_WORLD_SIZE,
        Lines
      ),
    }
  }

  pub fn push(
    &mut self,
    gl: &GLContext,
    id: main::Id,
    triangles: &[vertex::WorldTextureVertex],
    outlines: &[vertex::ColoredVertex]
  ) {
    self.id_to_index.insert(id, self.index_to_id.len());
    self.index_to_id.push(id);
    self.triangles.push(gl, triangles);
    self.outlines.push(gl, outlines);
  }

  pub fn swap_remove(&mut self, gl: &GLContext, id: main::Id) {
    let idx = *unwrap!(self.id_to_index.find(&id));
    let swapped_id = self.index_to_id[self.index_to_id.len() - 1];
    unwrap!(self.index_to_id.swap_remove(idx));
    self.id_to_index.remove(&id);
    self.triangles.swap_remove(gl, idx);
    self.outlines.swap_remove(gl, idx);
    if id != swapped_id {
      self.id_to_index.insert(swapped_id, idx);
    }
  }

  pub fn draw(&self, gl: &GLContext) {
    self.triangles.draw(gl);
    self.outlines.draw(gl);
  }
}

<commit_msg>increased hacky texture indexing delta<commit_after>use common::*;
use main;
use glw::gl_buffer::{GLSliceBuffer, Triangles, Lines};
use glw::gl_context::GLContext;
use glw::shader::Shader;
use glw::vertex;
use nalgebra::na::{Vec2, Vec3};
use ncollide3df32::bounding_volume::LooseBoundingVolume;
use ncollide3df32::bounding_volume::aabb::AABB;
use std::collections::HashMap;
use std::rc::Rc;

static MAX_WORLD_SIZE: uint = 40000;

#[deriving(Copy, Clone, PartialEq, Eq, Hash)]
pub enum BlockType {
  Grass,
  Dirt,
  Stone,
}

#[deriving(Clone)]
/// A voxel-ish block in the game world.
pub struct Block {
  pub block_type: BlockType,
  pub id: main::Id,
}

impl Block {
  // Construct outlines for this Block, to sharpen the edges.
  pub fn to_outlines(bounds: &AABB) -> [vertex::ColoredVertex, ..LINE_VERTICES_PER_BOX] {
    to_outlines(&bounds.loosened(0.002))
  }

  pub fn to_texture_triangles(bounds: &AABB) -> [vertex::WorldTextureVertex, ..TRIANGLE_VERTICES_PER_BOX] {
    let (x1, y1, z1) = (bounds.mins().x, bounds.mins().y, bounds.mins().z);
    let (x2, y2, z2) = (bounds.maxs().x, bounds.maxs().y, bounds.maxs().z);

    let vtx = |x, y, z, nx, ny, nz, tx, ty| {
      vertex::WorldTextureVertex {
        world_position: Vec3::new(x, y, z),
        texture_position: Vec2::new(tx, ty),
        normal: Vec3::new(nx, ny, nz),
      }
    };

    // hacky little solution so that we don't index right onto the edge of a
    // texture; if we do, we get edges showing up in rendering.
    let d = 0.01;

    // Remember: x increases to the right, y increases up, and z becomes more
    // negative as depth from the viewer increases.
    [
      // front
      vtx(x1, y1, z2,  0.0,  0.0,  1.0, 0.00 + d, 0.50 - d),
      vtx(x2, y2, z2,  0.0,  0.0,  1.0, 0.25 - d, 0.25 + d),
      vtx(x1, y2, z2,  0.0,  0.0,  1.0, 0.25 - d, 0.50 - d),
      vtx(x1, y1, z2,  0.0,  0.0,  1.0, 0.00 + d, 0.50 - d),
      vtx(x2, y1, z2,  0.0,  0.0,  1.0, 0.00 + d, 0.25 + d),
      vtx(x2, y2, z2,  0.0,  0.0,  1.0, 0.25 - d, 0.25 + d),
      // left
      vtx(x1, y1, z1, -1.0,  0.0,  0.0, 0.75 - d, 0.00 + d),
      vtx(x1, y2, z2, -1.0,  0.0,  0.0, 0.50 + d, 0.25 - d),
      vtx(x1, y2, z1, -1.0,  0.0,  0.0, 0.50 + d, 0.00 + d),
      vtx(x1, y1, z1, -1.0,  0.0,  0.0, 0.75 - d, 0.00 + d),
      vtx(x1, y1, z2, -1.0,  0.0,  0.0, 0.75 - d, 0.25 - d),
      vtx(x1, y2, z2, -1.0,  0.0,  0.0, 0.50 + d, 0.25 - d),
      // top
      vtx(x1, y2, z1,  0.0,  1.0,  0.0, 0.25 + d, 0.25 + d),
      vtx(x2, y2, z2,  0.0,  1.0,  0.0, 0.50 - d, 0.50 - d),
      vtx(x2, y2, z1,  0.0,  1.0,  0.0, 0.25 + d, 0.50 - d),
      vtx(x1, y2, z1,  0.0,  1.0,  0.0, 0.25 + d, 0.25 + d),
      vtx(x1, y2, z2,  0.0,  1.0,  0.0, 0.50 - d, 0.25 + d),
      vtx(x2, y2, z2,  0.0,  1.0,  0.0, 0.50 - d, 0.50 - d),
      // back
      vtx(x1, y1, z1,  0.0,  0.0, -1.0, 0.75 - d, 0.50 - d),
      vtx(x2, y2, z1,  0.0,  0.0, -1.0, 0.50 + d, 0.25 + d),
      vtx(x2, y1, z1,  0.0,  0.0, -1.0, 0.75 - d, 0.25 + d),
      vtx(x1, y1, z1,  0.0,  0.0, -1.0, 0.75 - d, 0.50 - d),
      vtx(x1, y2, z1,  0.0,  0.0, -1.0, 0.50 + d, 0.50 - d),
      vtx(x2, y2, z1,  0.0,  0.0, -1.0, 0.50 + d, 0.25 + d),
      // right
      vtx(x2, y1, z1,  1.0,  0.0,  0.0, 0.75 - d, 0.75 - d),
      vtx(x2, y2, z2,  1.0,  0.0,  0.0, 0.50 + d, 0.50 + d),
      vtx(x2, y1, z2,  1.0,  0.0,  0.0, 0.75 - d, 0.50 + d),
      vtx(x2, y1, z1,  1.0,  0.0,  0.0, 0.75 - d, 0.75 - d),
      vtx(x2, y2, z1,  1.0,  0.0,  0.0, 0.50 + d, 0.75 - d),
      vtx(x2, y2, z2,  1.0,  0.0,  0.0, 0.50 + d, 0.50 + d),
      // bottom
      vtx(x1, y1, z1,  0.0, -1.0,  0.0, 0.75 + d, 0.50 - d),
      vtx(x2, y1, z2,  0.0, -1.0,  0.0, 1.00 - d, 0.25 + d),
      vtx(x1, y1, z2,  0.0, -1.0,  0.0, 1.00 - d, 0.50 - d),
      vtx(x1, y1, z1,  0.0, -1.0,  0.0, 0.75 + d, 0.50 - d),
      vtx(x2, y1, z1,  0.0, -1.0,  0.0, 0.75 + d, 0.25 + d),
      vtx(x2, y1, z2,  0.0, -1.0,  0.0, 1.00 - d, 0.25 + d),
    ]
  }
}

pub struct BlockBuffers {
  id_to_index: HashMap<main::Id, uint>,
  index_to_id: Vec<main::Id>,

  triangles: GLSliceBuffer<vertex::WorldTextureVertex>,
  outlines: GLSliceBuffer<vertex::ColoredVertex>,
}

impl BlockBuffers {
  pub unsafe fn new(gl: &GLContext, color_shader: &Rc<Shader>, texture_shader: &Rc<Shader>) -> BlockBuffers {
    BlockBuffers {
      id_to_index: HashMap::new(),
      index_to_id: Vec::new(),
      triangles: GLSliceBuffer::new(
        gl,
        texture_shader.clone(),
        [ vertex::AttribData { name: "position", size: 3 },
          vertex::AttribData { name: "texture_position", size: 2 },
          vertex::AttribData { name: "vertex_normal", size: 3 },
        ],
        TRIANGLE_VERTICES_PER_BOX,
        MAX_WORLD_SIZE,
        Triangles
      ),
      outlines: GLSliceBuffer::new(
        gl,
        color_shader.clone(),
        [ vertex::AttribData { name: "position", size: 3 },
          vertex::AttribData { name: "in_color", size: 4 },
        ],
        LINE_VERTICES_PER_BOX,
        MAX_WORLD_SIZE,
        Lines
      ),
    }
  }

  pub fn push(
    &mut self,
    gl: &GLContext,
    id: main::Id,
    triangles: &[vertex::WorldTextureVertex],
    outlines: &[vertex::ColoredVertex]
  ) {
    self.id_to_index.insert(id, self.index_to_id.len());
    self.index_to_id.push(id);
    self.triangles.push(gl, triangles);
    self.outlines.push(gl, outlines);
  }

  pub fn swap_remove(&mut self, gl: &GLContext, id: main::Id) {
    let idx = *unwrap!(self.id_to_index.find(&id));
    let swapped_id = self.index_to_id[self.index_to_id.len() - 1];
    unwrap!(self.index_to_id.swap_remove(idx));
    self.id_to_index.remove(&id);
    self.triangles.swap_remove(gl, idx);
    self.outlines.swap_remove(gl, idx);
    if id != swapped_id {
      self.id_to_index.insert(swapped_id, idx);
    }
  }

  pub fn draw(&self, gl: &GLContext) {
    self.triangles.draw(gl);
    self.outlines.draw(gl);
  }
}

<|endoftext|>


<commit_before>use super::*;
use ::client::rest;
use ::internal::prelude::*;
use ::utils::builder::CreateInvite;
use ::utils;

#[cfg(feature="cache")]
use super::permissions;
#[cfg(feature="cache")]
use super::utils as model_utils;

/// Information about an invite code.
///
/// Information can not be accessed for guilds the current user is banned from.
#[derive(Clone, Debug, Deserialize)]
pub struct Invite {
    /// The approximate number of [`Member`]s in the related [`Guild`].
    ///
    /// [`Guild`]: struct.Guild.html
    /// [`Member`]: struct.Member.html
    pub approximate_member_count: Option<u64>,
    /// The approximate number of [`Member`]s with an active session in the
    /// related [`Guild`].
    ///
    /// An active session is defined as an open, heartbeating WebSocket connection.
    /// These include [invisible][`OnlineStatus::Invisible`] members.
    ///
    /// [`OnlineStatus::Invisible`]: enum.OnlineStatus.html#variant.Invisible
    pub approximate_presence_count: Option<u64>,
    /// The unique code for the invite.
    pub code: String,
    /// A representation of the minimal amount of information needed about the
    /// [`GuildChannel`] being invited to.
    ///
    /// [`GuildChannel`]: struct.GuildChannel.html
    pub channel: InviteChannel,
    /// a representation of the minimal amount of information needed about the
    /// [`Guild`] being invited to.
    pub guild: InviteGuild,
}

impl Invite {
    /// Creates an invite for a [`GuildChannel`], providing a builder so that
    /// fields may optionally be set.
    ///
    /// See the documentation for the [`CreateInvite`] builder for information
    /// on how to use this and the default values that it provides.
    ///
    /// Requires the [Create Invite] permission.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, returns a [`ClientError::InvalidPermissions`]
    /// if the current user does not have the required [permission].
    ///
    /// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
    /// [`CreateInvite`]: ../utils/builder/struct.CreateInvite.html
    /// [`GuildChannel`]: struct.GuildChannel.html
    /// [Create Invite]: permissions/constant.CREATE_INVITE.html
    /// [permission]: permissions/index.html
    pub fn create<C, F>(channel_id: C, f: F) -> Result<RichInvite>
        where C: Into<ChannelId>, F: FnOnce(CreateInvite) -> CreateInvite {
        let channel_id = channel_id.into();

        #[cfg(feature="cache")]
        {
            let req = permissions::CREATE_INVITE;

            if !model_utils::user_has_perms(channel_id, req)? {
                return Err(Error::Client(ClientError::InvalidPermissions(req)));
            }
        }

        rest::create_invite(channel_id.0, &f(CreateInvite::default()).0)
    }

    /// Deletes the invite.
    ///
    /// **Note**: Requires the [Manage Guild] permission.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, returns a [`ClientError::InvalidPermissions`]
    /// if the current user does not have the required [permission].
    ///
    /// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
    /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
    /// [permission]: permissions/index.html
    pub fn delete(&self) -> Result<Invite> {
        #[cfg(feature="cache")]
        {
            let req = permissions::MANAGE_GUILD;

            if !model_utils::user_has_perms(self.channel.id, req)? {
                return Err(Error::Client(ClientError::InvalidPermissions(req)));
            }
        }

        rest::delete_invite(&self.code)
    }

    /// Gets the information about an invite.
    pub fn get(code: &str, stats: bool) -> Result<Invite> {
        rest::get_invite(utils::parse_invite(code), stats)
    }
}

/// A inimal information about the channel an invite points to.
#[derive(Clone, Debug, Deserialize)]
pub struct InviteChannel {
    pub id: ChannelId,
    pub name: String,
    #[serde(rename="type")]
    pub kind: ChannelType,
}

/// A minimal amount of information about the guild an invite points to.
#[derive(Clone, Debug, Deserialize)]
pub struct InviteGuild {
    pub id: GuildId,
    pub icon: Option<String>,
    pub name: String,
    pub splash_hash: Option<String>,
    pub text_channel_count: Option<u64>,
    pub voice_channel_count: Option<u64>,
}

impl InviteGuild {
    /// Returns the Id of the shard associated with the guild.
    ///
    /// When the cache is enabled this will automatically retrieve the total
    /// number of shards.
    ///
    /// **Note**: When the cache is enabled, this function unlocks the cache to
    /// retrieve the total number of shards in use. If you already have the
    /// total, consider using [`utils::shard_id`].
    ///
    /// [`utils::shard_id`]: ../utils/fn.shard_id.html
    #[cfg(feature="cache")]
    #[inline]
    pub fn shard_id(&self) -> u64 {
        self.id.shard_id()
    }

    /// Returns the Id of the shard associated with the guild.
    ///
    /// When the cache is enabled this will automatically retrieve the total
    /// number of shards.
    ///
    /// When the cache is not enabled, the total number of shards being used
    /// will need to be passed.
    ///
    /// # Examples
    ///
    /// Retrieve the Id of the shard for a guild with Id `81384788765712384`,
    /// using 17 shards:
    ///
    /// ```rust,ignore
    /// use serenity::utils;
    ///
    /// // assumes a `guild` has already been bound
    ///
    /// assert_eq!(guild.shard_id(17), 7);
    /// ```
    #[cfg(not(feature="cache"))]
    #[inline]
    pub fn shard_id(&self, shard_count: u64) -> u64 {
        self.id.shard_id(shard_count)
    }
}

/// Detailed information about an invite.
/// This information can only be retrieved by anyone with the [Manage Guild]
/// permission. Otherwise, a minimal amount of information can be retrieved via
/// the [`Invite`] struct.
///
/// [`Invite`]: struct.Invite.html
/// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
#[derive(Clone, Debug, Deserialize)]
pub struct RichInvite {
    /// A representation of the minimal amount of information needed about the
    /// channel being invited to.
    pub channel: InviteChannel,
    /// The unique code for the invite.
    pub code: String,
    /// When the invite was created.
    pub created_at: String,
    /// A representation of the minimal amount of information needed about the
    /// guild being invited to.
    pub guild: InviteGuild,
    /// The user that created the invite.
    pub inviter: User,
    /// The maximum age of the invite in seconds, from when it was created.
    pub max_age: u64,
    /// The maximum number of times that an invite may be used before it expires.

    /// Note that this does not supercede the [`max_age`] value, if the value of
    /// [`temporary`] is `true`. If the value of `temporary` is `false`, then the
    /// invite _will_ self-expire after the given number of max uses.

    /// If the value is `0`, then the invite is permanent.
    ///
    /// [`max_age`]: #structfield.max_age
    /// [`temporary`]: #structfield.temporary
    pub max_uses: u64,
    /// Indicator of whether the invite self-expires after a certain amount of
    /// time or uses.
    pub temporary: bool,
    /// The amount of times that an invite has been used.
    pub uses: u64,
}

impl RichInvite {
    /// Deletes the invite.
    ///
    /// Refer to [`rest::delete_invite`] for more information.
    ///
    /// **Note**: Requires the [Manage Guild] permission.
    ///
    /// # Errors
    ///
    /// If the `cache` feature is enabled, then this returns a
    /// [`ClientError::InvalidPermissions`] if the current user does not have
    /// the required [permission].
    ///
    /// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
    /// [`Invite::delete`]: struct.Invite.html#method.delete
    /// [`rest::delete_invite`]: ../client/rest/fn.delete_invite.html
    /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
    /// [permission]: permissions/index.html
    pub fn delete(&self) -> Result<Invite> {
        #[cfg(feature="cache")]
        {
            let req = permissions::MANAGE_GUILD;

            if !model_utils::user_has_perms(self.channel.id, req)? {
                return Err(Error::Client(ClientError::InvalidPermissions(req)));
            }
        }

        rest::delete_invite(&self.code)
    }
}
<commit_msg>Add `Invite::url()`, `RichInvite::url()`<commit_after>use super::*;
use ::client::rest;
use ::internal::prelude::*;
use ::utils::builder::CreateInvite;
use ::utils;

#[cfg(feature="cache")]
use super::permissions;
#[cfg(feature="cache")]
use super::utils as model_utils;

/// Information about an invite code.
///
/// Information can not be accessed for guilds the current user is banned from.
#[derive(Clone, Debug, Deserialize)]
pub struct Invite {
    /// The approximate number of [`Member`]s in the related [`Guild`].
    ///
    /// [`Guild`]: struct.Guild.html
    /// [`Member`]: struct.Member.html
    pub approximate_member_count: Option<u64>,
    /// The approximate number of [`Member`]s with an active session in the
    /// related [`Guild`].
    ///
    /// An active session is defined as an open, heartbeating WebSocket connection.
    /// These include [invisible][`OnlineStatus::Invisible`] members.
    ///
    /// [`OnlineStatus::Invisible`]: enum.OnlineStatus.html#variant.Invisible
    pub approximate_presence_count: Option<u64>,
    /// The unique code for the invite.
    pub code: String,
    /// A representation of the minimal amount of information needed about the
    /// [`GuildChannel`] being invited to.
    ///
    /// [`GuildChannel`]: struct.GuildChannel.html
    pub channel: InviteChannel,
    /// a representation of the minimal amount of information needed about the
    /// [`Guild`] being invited to.
    pub guild: InviteGuild,
}

impl Invite {
    /// Creates an invite for a [`GuildChannel`], providing a builder so that
    /// fields may optionally be set.
    ///
    /// See the documentation for the [`CreateInvite`] builder for information
    /// on how to use this and the default values that it provides.
    ///
    /// Requires the [Create Invite] permission.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, returns a [`ClientError::InvalidPermissions`]
    /// if the current user does not have the required [permission].
    ///
    /// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
    /// [`CreateInvite`]: ../utils/builder/struct.CreateInvite.html
    /// [`GuildChannel`]: struct.GuildChannel.html
    /// [Create Invite]: permissions/constant.CREATE_INVITE.html
    /// [permission]: permissions/index.html
    pub fn create<C, F>(channel_id: C, f: F) -> Result<RichInvite>
        where C: Into<ChannelId>, F: FnOnce(CreateInvite) -> CreateInvite {
        let channel_id = channel_id.into();

        #[cfg(feature="cache")]
        {
            let req = permissions::CREATE_INVITE;

            if !model_utils::user_has_perms(channel_id, req)? {
                return Err(Error::Client(ClientError::InvalidPermissions(req)));
            }
        }

        rest::create_invite(channel_id.0, &f(CreateInvite::default()).0)
    }

    /// Deletes the invite.
    ///
    /// **Note**: Requires the [Manage Guild] permission.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, returns a [`ClientError::InvalidPermissions`]
    /// if the current user does not have the required [permission].
    ///
    /// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
    /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
    /// [permission]: permissions/index.html
    pub fn delete(&self) -> Result<Invite> {
        #[cfg(feature="cache")]
        {
            let req = permissions::MANAGE_GUILD;

            if !model_utils::user_has_perms(self.channel.id, req)? {
                return Err(Error::Client(ClientError::InvalidPermissions(req)));
            }
        }

        rest::delete_invite(&self.code)
    }

    /// Gets the information about an invite.
    pub fn get(code: &str, stats: bool) -> Result<Invite> {
        rest::get_invite(utils::parse_invite(code), stats)
    }

    /// Returns a URL to use for the invite.
    ///
    /// # Examples
    ///
    /// Retrieve the URL for an invite with the code `WxZumR`:
    ///
    /// ```rust
    /// # use serenity::model::*;
    /// #
    /// # let invite = Invite {
    /// #     code: "WxZumR".to_owned(),
    /// #     channel: InviteChannel {
    /// #         id: ChannelId(1),
    /// #         name: "foo".to_owned(),
    /// #         kind: ChannelType::Text,
    /// #     },
    /// #     guild: InviteGuild {
    /// #         id: GuildId(2),
    /// #         icon: None,
    /// #         name: "bar".to_owned(),
    /// #         splash_hash: None,
    /// #     },
    /// # };
    /// #
    /// assert_eq!(invite.url(), "https://discord.gg/WxZumR");
    /// ```
    pub fn url(&self) -> String {
        format!("https://discord.gg/{}", self.code)
    }
}

/// A inimal information about the channel an invite points to.
#[derive(Clone, Debug, Deserialize)]
pub struct InviteChannel {
    pub id: ChannelId,
    pub name: String,
    #[serde(rename="type")]
    pub kind: ChannelType,
}

/// A minimal amount of information about the guild an invite points to.
#[derive(Clone, Debug, Deserialize)]
pub struct InviteGuild {
    pub id: GuildId,
    pub icon: Option<String>,
    pub name: String,
    pub splash_hash: Option<String>,
    pub text_channel_count: Option<u64>,
    pub voice_channel_count: Option<u64>,
}

impl InviteGuild {
    /// Returns the Id of the shard associated with the guild.
    ///
    /// When the cache is enabled this will automatically retrieve the total
    /// number of shards.
    ///
    /// **Note**: When the cache is enabled, this function unlocks the cache to
    /// retrieve the total number of shards in use. If you already have the
    /// total, consider using [`utils::shard_id`].
    ///
    /// [`utils::shard_id`]: ../utils/fn.shard_id.html
    #[cfg(feature="cache")]
    #[inline]
    pub fn shard_id(&self) -> u64 {
        self.id.shard_id()
    }

    /// Returns the Id of the shard associated with the guild.
    ///
    /// When the cache is enabled this will automatically retrieve the total
    /// number of shards.
    ///
    /// When the cache is not enabled, the total number of shards being used
    /// will need to be passed.
    ///
    /// # Examples
    ///
    /// Retrieve the Id of the shard for a guild with Id `81384788765712384`,
    /// using 17 shards:
    ///
    /// ```rust,ignore
    /// use serenity::utils;
    ///
    /// // assumes a `guild` has already been bound
    ///
    /// assert_eq!(guild.shard_id(17), 7);
    /// ```
    #[cfg(not(feature="cache"))]
    #[inline]
    pub fn shard_id(&self, shard_count: u64) -> u64 {
        self.id.shard_id(shard_count)
    }
}

/// Detailed information about an invite.
/// This information can only be retrieved by anyone with the [Manage Guild]
/// permission. Otherwise, a minimal amount of information can be retrieved via
/// the [`Invite`] struct.
///
/// [`Invite`]: struct.Invite.html
/// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
#[derive(Clone, Debug, Deserialize)]
pub struct RichInvite {
    /// A representation of the minimal amount of information needed about the
    /// channel being invited to.
    pub channel: InviteChannel,
    /// The unique code for the invite.
    pub code: String,
    /// When the invite was created.
    pub created_at: String,
    /// A representation of the minimal amount of information needed about the
    /// guild being invited to.
    pub guild: InviteGuild,
    /// The user that created the invite.
    pub inviter: User,
    /// The maximum age of the invite in seconds, from when it was created.
    pub max_age: u64,
    /// The maximum number of times that an invite may be used before it expires.

    /// Note that this does not supercede the [`max_age`] value, if the value of
    /// [`temporary`] is `true`. If the value of `temporary` is `false`, then the
    /// invite _will_ self-expire after the given number of max uses.

    /// If the value is `0`, then the invite is permanent.
    ///
    /// [`max_age`]: #structfield.max_age
    /// [`temporary`]: #structfield.temporary
    pub max_uses: u64,
    /// Indicator of whether the invite self-expires after a certain amount of
    /// time or uses.
    pub temporary: bool,
    /// The amount of times that an invite has been used.
    pub uses: u64,
}

impl RichInvite {
    /// Deletes the invite.
    ///
    /// Refer to [`rest::delete_invite`] for more information.
    ///
    /// **Note**: Requires the [Manage Guild] permission.
    ///
    /// # Errors
    ///
    /// If the `cache` feature is enabled, then this returns a
    /// [`ClientError::InvalidPermissions`] if the current user does not have
    /// the required [permission].
    ///
    /// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions
    /// [`Invite::delete`]: struct.Invite.html#method.delete
    /// [`rest::delete_invite`]: ../client/rest/fn.delete_invite.html
    /// [Manage Guild]: permissions/constant.MANAGE_GUILD.html
    /// [permission]: permissions/index.html
    pub fn delete(&self) -> Result<Invite> {
        #[cfg(feature="cache")]
        {
            let req = permissions::MANAGE_GUILD;

            if !model_utils::user_has_perms(self.channel.id, req)? {
                return Err(Error::Client(ClientError::InvalidPermissions(req)));
            }
        }

        rest::delete_invite(&self.code)
    }

    /// Returns a URL to use for the invite.
    ///
    /// # Examples
    ///
    /// Retrieve the URL for an invite with the code `WxZumR`:
    ///
    /// ```rust
    /// # use serenity::model::*;
    /// #
    /// # let invite = RichInvite {
    /// #     code: "WxZumR".to_owned(),
    /// #     channel: InviteChannel {
    /// #         id: ChannelId(1),
    /// #         name: "foo".to_owned(),
    /// #         kind: ChannelType::Text,
    /// #     },
    /// #     created_at: "bar".to_owned(),
    /// #     guild: InviteGuild {
    /// #         id: GuildId(2),
    /// #         icon: None,
    /// #         name: "baz".to_owned(),
    /// #         splash_hash: None,
    /// #     },
    /// #     inviter: User {
    /// #         avatar: None,
    /// #         bot: false,
    /// #         discriminator: 3,
    /// #         id: UserId(4),
    /// #         name: "qux".to_owned(),
    /// #     },
    /// #     max_age: 5,
    /// #     max_uses: 6,
    /// #     temporary: true,
    /// #     uses: 7,
    /// # };
    /// #
    /// assert_eq!(invite.url(), "https://discord.gg/WxZumR");
    /// ```
    pub fn url(&self) -> String {
        format!("https://discord.gg/{}", self.code)
    }
}
<|endoftext|>


<commit_before>use std::{
    cmp::Reverse,
    io,
    io::{Cursor, Read, Write},
    ops::AddAssign,
};

use axum::{body::Body, http::Response, response::IntoResponse};
use byteorder::{LittleEndian, ReadBytesExt as _, WriteBytesExt as _};
use rustc_hash::FxHashMap;
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DisplayFromStr, SpaceSeparator, StringWithSeparator};
use shakmaty::{san::SanPlus, uci::Uci, ByColor, Chess, Color, Outcome};
use smallvec::{smallvec, SmallVec};

use crate::{
    model::{read_uci, write_uci, GameId, LaxDate, Stats},
    util::ByColorDef,
};

#[serde_as]
#[derive(Deserialize, Debug)]
pub struct MasterGameWithId {
    #[serde_as(as = "DisplayFromStr")]
    pub id: GameId,
    #[serde(flatten)]
    pub game: MasterGame,
}

#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct MasterGame {
    pub event: String,
    pub site: String,
    #[serde_as(as = "DisplayFromStr")]
    pub date: LaxDate,
    pub round: String,
    #[serde(flatten, with = "ByColorDef")]
    pub players: ByColor<MasterGamePlayer>,
    #[serde_as(as = "Option<DisplayFromStr>")]
    pub winner: Option<Color>,
    #[serde_as(as = "StringWithSeparator<SpaceSeparator, Uci>")]
    pub moves: Vec<Uci>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct MasterGamePlayer {
    pub name: String,
    pub rating: u16,
}

impl MasterGame {
    fn outcome(&self) -> Outcome {
        Outcome::from_winner(self.winner)
    }

    fn write_pgn<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        writeln!(writer, "[Event \"{}\"]", self.event)?;
        writeln!(writer, "[Site \"{}\"]", self.site)?;
        writeln!(writer, "[Date \"{}\"]", self.date)?;
        writeln!(writer, "[Round \"{}\"]", self.round)?;
        writeln!(writer, "[White \"{}\"]", self.players.white.name)?;
        writeln!(writer, "[Black \"{}\"]", self.players.black.name)?;
        writeln!(writer, "[Result \"{}\"]", self.outcome())?;
        writeln!(writer, "[WhiteElo \"{}\"]", self.players.white.rating)?;
        writeln!(writer, "[BlackElo \"{}\"]", self.players.black.rating)?;
        writeln!(writer)?;

        let mut pos = Chess::default();

        for (i, uci) in self.moves.iter().enumerate() {
            let m = uci
                .to_move(&pos)
                .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
            if i % 2 == 0 {
                write!(writer, "{}. ", i / 2 + 1)?;
            } else if i > 0 {
                write!(writer, " ")?;
            }
            let san = SanPlus::from_move_and_play_unchecked(&mut pos, &m);
            write!(writer, "{}", san)?;
        }

        if !self.moves.is_empty() {
            write!(writer, " ")?;
        }
        writeln!(writer, "{}", self.outcome())
    }
}

impl IntoResponse for MasterGame {
    type Body = Body;
    type BodyError = <Body as axum::body::HttpBody>::Error;

    fn into_response(self) -> Response<Body> {
        let mut buf = Cursor::new(Vec::new());
        self.write_pgn(&mut buf).expect("write pgn");

        Response::builder()
            .header(axum::http::header::CONTENT_TYPE, "application/x-chess-pgn")
            .body(Body::from(buf.into_inner()))
            .unwrap()
    }
}

#[derive(Debug, Default)]
struct Group {
    stats: Stats,
    games: SmallVec<[(u16, GameId); 1]>,
}

impl AddAssign for Group {
    fn add_assign(&mut self, rhs: Group) {
        self.stats += rhs.stats;
        self.games.extend(rhs.games);
    }
}

#[derive(Default, Debug)]
pub struct MasterEntry {
    groups: FxHashMap<Uci, Group>,
}

impl MasterEntry {
    pub const SIZE_HINT: usize = 14;

    pub fn new_single(
        uci: Uci,
        id: GameId,
        outcome: Outcome,
        mover_rating: u16,
        opponent_rating: u16,
    ) -> MasterEntry {
        let mut groups = FxHashMap::with_capacity_and_hasher(1, Default::default());
        groups.insert(
            uci,
            Group {
                stats: Stats::new_single(outcome, mover_rating),
                games: smallvec![(mover_rating.saturating_add(opponent_rating), id)],
            },
        );
        MasterEntry { groups }
    }

    pub fn extend_from_reader<R: Read>(&mut self, reader: &mut R) -> io::Result<()> {
        loop {
            let uci = match read_uci(reader) {
                Ok(uci) => uci,
                Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => return Ok(()),
                Err(err) => return Err(err),
            };

            let group = self.groups.entry(uci).or_default();

            group.stats += Stats::read(reader)?;

            let num_games = reader.read_u8()?;
            group.games.reserve_exact(usize::from(num_games));
            for _ in 0..num_games {
                group
                    .games
                    .push((reader.read_u16::<LittleEndian>()?, GameId::read(reader)?));
            }
        }
    }

    pub fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        let mut top_games = Vec::new();
        for group in self.groups.values() {
            top_games.extend(&group.games);
        }
        top_games.sort_by_key(|(sort_key, _)| Reverse(*sort_key));
        top_games.truncate(15);

        for (uci, group) in &self.groups {
            write_uci(writer, uci)?;

            group.stats.write(writer)?;

            let num_games = if group.games.len() == 1 {
                1
            } else {
                group.games.iter().filter(|g| top_games.contains(g)).count()
            };
            writer.write_u8(num_games as u8)?;
            for (sort_key, id) in &group.games {
                writer.write_u16::<LittleEndian>(*sort_key)?;
                id.write(writer)?;
            }
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use shakmaty::Square;

    use super::*;

    #[test]
    fn test_master_entry() {
        let uci = Uci::Normal {
            from: Square::E2,
            to: Square::E4,
            promotion: None,
        };
        let game = "aaaaaaaa".parse().unwrap();
        let a = MasterEntry::new_single(uci.clone(), game, Outcome::Draw, 1600, 1700);

        let mut writer = Cursor::new(Vec::with_capacity(MasterEntry::SIZE_HINT));
        a.write(&mut writer).unwrap();
        assert_eq!(
            writer.position() as usize,
            MasterEntry::SIZE_HINT,
            "optimized for single entries"
        );

        let mut reader = Cursor::new(writer.into_inner());
        let mut deserialized = MasterEntry::default();
        deserialized.extend_from_reader(&mut reader).unwrap();

        let group = deserialized.groups.get(&uci).unwrap();
        assert_eq!(group.stats.draws, 1);
        assert_eq!(group.games[0], (1600 + 1700, game));
    }
}
<commit_msg>fix master pgn formatting<commit_after>use std::{
    cmp::Reverse,
    io,
    io::{Cursor, Read, Write},
    ops::AddAssign,
};

use axum::{body::Body, http::Response, response::IntoResponse};
use byteorder::{LittleEndian, ReadBytesExt as _, WriteBytesExt as _};
use rustc_hash::FxHashMap;
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DisplayFromStr, SpaceSeparator, StringWithSeparator};
use shakmaty::{san::SanPlus, uci::Uci, ByColor, Chess, Color, Outcome};
use smallvec::{smallvec, SmallVec};

use crate::{
    model::{read_uci, write_uci, GameId, LaxDate, Stats},
    util::ByColorDef,
};

#[serde_as]
#[derive(Deserialize, Debug)]
pub struct MasterGameWithId {
    #[serde_as(as = "DisplayFromStr")]
    pub id: GameId,
    #[serde(flatten)]
    pub game: MasterGame,
}

#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
pub struct MasterGame {
    pub event: String,
    pub site: String,
    #[serde_as(as = "DisplayFromStr")]
    pub date: LaxDate,
    pub round: String,
    #[serde(flatten, with = "ByColorDef")]
    pub players: ByColor<MasterGamePlayer>,
    #[serde_as(as = "Option<DisplayFromStr>")]
    pub winner: Option<Color>,
    #[serde_as(as = "StringWithSeparator<SpaceSeparator, Uci>")]
    pub moves: Vec<Uci>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct MasterGamePlayer {
    pub name: String,
    pub rating: u16,
}

impl MasterGame {
    fn outcome(&self) -> Outcome {
        Outcome::from_winner(self.winner)
    }

    fn write_pgn<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        writeln!(writer, "[Event \"{}\"]", self.event)?;
        writeln!(writer, "[Site \"{}\"]", self.site)?;
        writeln!(writer, "[Date \"{}\"]", self.date)?;
        writeln!(writer, "[Round \"{}\"]", self.round)?;
        writeln!(writer, "[White \"{}\"]", self.players.white.name)?;
        writeln!(writer, "[Black \"{}\"]", self.players.black.name)?;
        writeln!(writer, "[Result \"{}\"]", self.outcome())?;
        writeln!(writer, "[WhiteElo \"{}\"]", self.players.white.rating)?;
        writeln!(writer, "[BlackElo \"{}\"]", self.players.black.rating)?;
        writeln!(writer)?;

        let mut pos = Chess::default();

        for (i, uci) in self.moves.iter().enumerate() {
            let m = uci
                .to_move(&pos)
                .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
            if i % 2 == 0 {
                if i > 0 {
                    write!(writer, " ")?;
                }
                write!(writer, "{}.", i / 2 + 1)?;
            }
            let san = SanPlus::from_move_and_play_unchecked(&mut pos, &m);
            write!(writer, " {}", san)?;
        }

        if !self.moves.is_empty() {
            write!(writer, " ")?;
        }
        writeln!(writer, "{}", self.outcome())
    }
}

impl IntoResponse for MasterGame {
    type Body = Body;
    type BodyError = <Body as axum::body::HttpBody>::Error;

    fn into_response(self) -> Response<Body> {
        let mut buf = Cursor::new(Vec::new());
        self.write_pgn(&mut buf).expect("write pgn");

        Response::builder()
            .header(axum::http::header::CONTENT_TYPE, "application/x-chess-pgn")
            .body(Body::from(buf.into_inner()))
            .unwrap()
    }
}

#[derive(Debug, Default)]
struct Group {
    stats: Stats,
    games: SmallVec<[(u16, GameId); 1]>,
}

impl AddAssign for Group {
    fn add_assign(&mut self, rhs: Group) {
        self.stats += rhs.stats;
        self.games.extend(rhs.games);
    }
}

#[derive(Default, Debug)]
pub struct MasterEntry {
    groups: FxHashMap<Uci, Group>,
}

impl MasterEntry {
    pub const SIZE_HINT: usize = 14;

    pub fn new_single(
        uci: Uci,
        id: GameId,
        outcome: Outcome,
        mover_rating: u16,
        opponent_rating: u16,
    ) -> MasterEntry {
        let mut groups = FxHashMap::with_capacity_and_hasher(1, Default::default());
        groups.insert(
            uci,
            Group {
                stats: Stats::new_single(outcome, mover_rating),
                games: smallvec![(mover_rating.saturating_add(opponent_rating), id)],
            },
        );
        MasterEntry { groups }
    }

    pub fn extend_from_reader<R: Read>(&mut self, reader: &mut R) -> io::Result<()> {
        loop {
            let uci = match read_uci(reader) {
                Ok(uci) => uci,
                Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => return Ok(()),
                Err(err) => return Err(err),
            };

            let group = self.groups.entry(uci).or_default();

            group.stats += Stats::read(reader)?;

            let num_games = reader.read_u8()?;
            group.games.reserve_exact(usize::from(num_games));
            for _ in 0..num_games {
                group
                    .games
                    .push((reader.read_u16::<LittleEndian>()?, GameId::read(reader)?));
            }
        }
    }

    pub fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        let mut top_games = Vec::new();
        for group in self.groups.values() {
            top_games.extend(&group.games);
        }
        top_games.sort_by_key(|(sort_key, _)| Reverse(*sort_key));
        top_games.truncate(15);

        for (uci, group) in &self.groups {
            write_uci(writer, uci)?;

            group.stats.write(writer)?;

            let num_games = if group.games.len() == 1 {
                1
            } else {
                group.games.iter().filter(|g| top_games.contains(g)).count()
            };
            writer.write_u8(num_games as u8)?;
            for (sort_key, id) in &group.games {
                writer.write_u16::<LittleEndian>(*sort_key)?;
                id.write(writer)?;
            }
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use shakmaty::Square;

    use super::*;

    #[test]
    fn test_master_entry() {
        let uci = Uci::Normal {
            from: Square::E2,
            to: Square::E4,
            promotion: None,
        };
        let game = "aaaaaaaa".parse().unwrap();
        let a = MasterEntry::new_single(uci.clone(), game, Outcome::Draw, 1600, 1700);

        let mut writer = Cursor::new(Vec::with_capacity(MasterEntry::SIZE_HINT));
        a.write(&mut writer).unwrap();
        assert_eq!(
            writer.position() as usize,
            MasterEntry::SIZE_HINT,
            "optimized for single entries"
        );

        let mut reader = Cursor::new(writer.into_inner());
        let mut deserialized = MasterEntry::default();
        deserialized.extend_from_reader(&mut reader).unwrap();

        let group = deserialized.groups.get(&uci).unwrap();
        assert_eq!(group.stats.draws, 1);
        assert_eq!(group.games[0], (1600 + 1700, game));
    }
}
<|endoftext|>


<commit_before>use rustc_serialize::json;

pub trait MutableJson {
    fn as_object_mut<'a>(&'a mut self) -> Option<&'a mut json::Object>;
    fn as_array_mut<'a>(&'a mut self) -> Option<&'a mut json::Array>;
}

impl MutableJson for json::Json {

    /// If the Json value is an Object, returns the associated BTreeMap.
    /// Returns None otherwise.
    fn as_object_mut<'a>(&'a mut self) -> Option<&'a mut json::Object> {
        match self {
            &mut json::Json::Object(ref mut map) => Some(&mut*map),
            _ => None
        }
    }

    fn as_array_mut<'a>(&'a mut self) -> Option<&'a mut json::Array> {
        match self {
            &mut json::Json::Array(ref mut list) => Some(&mut *list),
            _ => None
        }
    }

}<commit_msg>refactor(mutable_json): fix indirection<commit_after>use rustc_serialize::json;

pub trait MutableJson {
    fn as_object_mut<'a>(&'a mut self) -> Option<&'a mut json::Object>;
    fn as_array_mut<'a>(&'a mut self) -> Option<&'a mut json::Array>;
}

impl MutableJson for json::Json {

    /// If the Json value is an Object, returns the associated BTreeMap.
    /// Returns None otherwise.
    fn as_object_mut<'a>(&'a mut self) -> Option<&'a mut json::Object> {
        match self {
            &mut json::Json::Object(ref mut map) => Some(map),
            _ => None
        }
    }

    fn as_array_mut<'a>(&'a mut self) -> Option<&'a mut json::Array> {
        match self {
            &mut json::Json::Array(ref mut list) => Some(list),
            _ => None
        }
    }

}<|endoftext|>