<commit_before> #![feature(buf_stream)]

#[macro_use]
extern crate log;
extern crate url;
extern crate capnp;

pub mod yak_capnp;

use std::net::TcpStream;
use std::io::{self,BufStream,Write};
use capnp::serialize_packed;
use capnp::{MessageBuilder, MessageReader, MallocMessageBuilder, ReaderOptions};

use url::{Url,SchemeType,UrlParser};

use yak_capnp::{client_request,client_response};

fn yak_url_scheme(_scheme: &str) -> SchemeType {
  SchemeType::Relative(0)
}

pub struct Client {
  connection: BufStream<TcpStream>,
  space: String,
}

#[derive(Debug)]
pub enum YakError {
  UrlParseError(url::ParseError),
  InvalidUrl(Url),
  IoError(io::Error),
  CapnpError(capnp::Error),
  CapnpNotInSchema(capnp::NotInSchema),
  ProtocolError
}

#[derive(PartialEq,Eq,PartialOrd,Ord,Debug)]
pub struct Datum {
  pub content: Vec<u8>
}

pub struct Request {
  space: String,
  operation: Operation,
}
pub enum Operation {
  Truncate ,
  Read { key: Vec<u8> },
  Write { key: Vec<u8>, value: Vec<u8> },
}

impl Request {
  fn encode<B: MessageBuilder>(&self, message: &mut B) {
    match &self.operation {
      &Operation::Truncate => Self::encode_truncate(message, &self.space),
      &Operation::Read { key: ref key } => Self::encode_read(message, &self.space, &key),
      &Operation::Write { key: ref key, value: ref val } => Self::encode_write(message, &self.space, &key, &val),
    }
  }

  fn truncate(space: &str) -> Request {
    Request { space: space.to_string(), operation: Operation::Truncate }
  }

  fn read(space: &str, key: &[u8]) -> Request {
    Request { space: space.to_string(), operation: Operation::Read { key: key.to_vec() } }
  }

  fn write(space: &str, key: &[u8], value: &[u8]) -> Request {
    Request { space: space.to_string(), operation: Operation::Write { key: key.to_owned(), value: value.to_owned() } }
  }

  fn encode_truncate<B: MessageBuilder>(message: &mut B, space: &str) {
    let mut rec = message.init_root::<client_request::Builder>();
    let mut trunc = rec.init_truncate();
    trunc.set_space(space)
  }

  fn encode_write<B: MessageBuilder>(message: &mut B, space: &str, key: &[u8], val: &[u8]) {
    let mut rec = message.init_root::<client_request::Builder>();
    let mut req = rec.init_write();
    req.set_space(space);
    req.set_key(key);
    req.set_value(val);
  }

  fn encode_read<B: MessageBuilder>(message: &mut B, space: &str, key: &[u8]) {
      let mut rec = message.init_root::<client_request::Builder>();
      let mut req = rec.init_read();
      req.set_space(space);
      req.set_key(key)
  }

}

impl Client {
  pub fn connect(loc: &str) -> Result<Client, YakError> {
    let mut p = UrlParser::new();
    p.scheme_type_mapper(yak_url_scheme);
    let url = try!(p.parse(loc));
    debug!("yak:url: {:?}", url);
    let (addr, space) = match (url.domain(), url.port(), url.serialize_path()) {
      (Some(host), Some(port), Some(path)) => ((host, port), path),
      _ => return Err(YakError::InvalidUrl(url.clone()))
    };

    let sock = try!(TcpStream::connect(addr));
    debug!("connected:{:?}", sock);
    Ok(Client { connection: BufStream::new(sock), space: space })
  }

  fn expect_ok<R: MessageReader>(message: &R) -> Result<(), YakError> {
    let msg = try!(message.get_root::<client_response::Reader>());
    debug!("Got response");
    match try!(msg.which()) {
      client_response::Ok(()) => Ok(()),
      other => Err(YakError::ProtocolError)
    }
  }

  fn expect_datum_list<R: MessageReader>(message_reader: &R) -> Result<Vec<Datum>, YakError> {
    let msg = try!(message_reader.get_root::<client_response::Reader>());
    match try!(msg.which()) {
      client_response::OkData(d) => {
        debug!("Got response Data: ");
        let mut data = Vec::with_capacity(try!(d).len() as usize);
        for it in try!(d).iter() {
          let val : Vec<u8> = try!(it.get_value()).iter().map(|v|v.clone()).collect();
          data.push(Datum { content: val });
        }

        Ok(data)
      },
      other => Err(YakError::ProtocolError)
    }
  }

  fn send(&mut self, req: Request) -> Result<(), YakError> {
    let mut message = MallocMessageBuilder::new_default();
    req.encode(&mut message);
    try!(serialize_packed::write_message(&mut self.connection, &mut message));
    try!(self.connection.flush());
    Ok(())
  }

  pub fn truncate(&mut self) -> Result<(), YakError> {
    let req = Request::truncate(&self.space);
    self.send(req);
    debug!("Waiting for response");

    let message_reader = try!(serialize_packed::read_message(&mut self.connection, ReaderOptions::new()));
    Self::expect_ok(&message_reader)
  }

  pub fn write(&mut self, key: &[u8], val: &[u8]) -> Result<(), YakError> {
    let req = Request::write(&self.space, key, val);
    self.send(req);
    debug!("Waiting for response");

    let message_reader = try!(serialize_packed::read_message(&mut self.connection, ReaderOptions::new()));
    Self::expect_ok(&message_reader)
  }

  pub fn read(&mut self, key: &[u8]) -> Result<Vec<Datum>, YakError> {
    let req = Request::read(&self.space, key);
    self.send(req);
    debug!("Waiting for response");

    let message_reader = try!(serialize_packed::read_message(&mut self.connection, ReaderOptions::new()));
    Self::expect_datum_list(&message_reader)
  }
}

impl From<url::ParseError> for YakError {
  fn from(err: url::ParseError) -> YakError {
    YakError::UrlParseError(err)
  }
}

impl From<io::Error> for YakError {
  fn from(err: io::Error) -> YakError {
    YakError::IoError(err)
  }
}

impl From<capnp::Error> for YakError {
  fn from(err: capnp::Error) -> YakError {
    YakError::CapnpError(err)
  }
}

impl From<capnp::NotInSchema> for YakError {
  fn from(err: capnp::NotInSchema) -> YakError {
    YakError::CapnpNotInSchema(err)
  }
}
<commit_msg>Check results from sending commands.<commit_after> #![feature(buf_stream)]

#[macro_use]
extern crate log;
extern crate url;
extern crate capnp;

pub mod yak_capnp;

use std::net::TcpStream;
use std::io::{self,BufStream,Write};
use capnp::serialize_packed;
use capnp::{MessageBuilder, MessageReader, MallocMessageBuilder, ReaderOptions};

use url::{Url,SchemeType,UrlParser};

use yak_capnp::{client_request,client_response};

fn yak_url_scheme(_scheme: &str) -> SchemeType {
  SchemeType::Relative(0)
}

pub struct Client {
  connection: BufStream<TcpStream>,
  space: String,
}

#[derive(Debug)]
pub enum YakError {
  UrlParseError(url::ParseError),
  InvalidUrl(Url),
  IoError(io::Error),
  CapnpError(capnp::Error),
  CapnpNotInSchema(capnp::NotInSchema),
  ProtocolError
}

#[derive(PartialEq,Eq,PartialOrd,Ord,Debug)]
pub struct Datum {
  pub content: Vec<u8>
}

pub struct Request {
  space: String,
  operation: Operation,
}
pub enum Operation {
  Truncate ,
  Read { key: Vec<u8> },
  Write { key: Vec<u8>, value: Vec<u8> },
}

impl Request {
  fn encode<B: MessageBuilder>(&self, message: &mut B) {
    match &self.operation {
      &Operation::Truncate => Self::encode_truncate(message, &self.space),
      &Operation::Read { key: ref key } => Self::encode_read(message, &self.space, &key),
      &Operation::Write { key: ref key, value: ref val } => Self::encode_write(message, &self.space, &key, &val),
    }
  }

  fn truncate(space: &str) -> Request {
    Request { space: space.to_string(), operation: Operation::Truncate }
  }

  fn read(space: &str, key: &[u8]) -> Request {
    Request { space: space.to_string(), operation: Operation::Read { key: key.to_vec() } }
  }

  fn write(space: &str, key: &[u8], value: &[u8]) -> Request {
    Request { space: space.to_string(), operation: Operation::Write { key: key.to_owned(), value: value.to_owned() } }
  }

  fn encode_truncate<B: MessageBuilder>(message: &mut B, space: &str) {
    let mut rec = message.init_root::<client_request::Builder>();
    let mut trunc = rec.init_truncate();
    trunc.set_space(space)
  }

  fn encode_write<B: MessageBuilder>(message: &mut B, space: &str, key: &[u8], val: &[u8]) {
    let mut rec = message.init_root::<client_request::Builder>();
    let mut req = rec.init_write();
    req.set_space(space);
    req.set_key(key);
    req.set_value(val);
  }

  fn encode_read<B: MessageBuilder>(message: &mut B, space: &str, key: &[u8]) {
      let mut rec = message.init_root::<client_request::Builder>();
      let mut req = rec.init_read();
      req.set_space(space);
      req.set_key(key)
  }

}

impl Client {
  pub fn connect(loc: &str) -> Result<Client, YakError> {
    let mut p = UrlParser::new();
    p.scheme_type_mapper(yak_url_scheme);
    let url = try!(p.parse(loc));
    debug!("yak:url: {:?}", url);
    let (addr, space) = match (url.domain(), url.port(), url.serialize_path()) {
      (Some(host), Some(port), Some(path)) => ((host, port), path),
      _ => return Err(YakError::InvalidUrl(url.clone()))
    };

    let sock = try!(TcpStream::connect(addr));
    debug!("connected:{:?}", sock);
    Ok(Client { connection: BufStream::new(sock), space: space })
  }

  fn expect_ok<R: MessageReader>(message: &R) -> Result<(), YakError> {
    let msg = try!(message.get_root::<client_response::Reader>());
    debug!("Got response");
    match try!(msg.which()) {
      client_response::Ok(()) => Ok(()),
      other => Err(YakError::ProtocolError)
    }
  }

  fn expect_datum_list<R: MessageReader>(message_reader: &R) -> Result<Vec<Datum>, YakError> {
    let msg = try!(message_reader.get_root::<client_response::Reader>());
    match try!(msg.which()) {
      client_response::OkData(d) => {
        debug!("Got response Data: ");
        let mut data = Vec::with_capacity(try!(d).len() as usize);
        for it in try!(d).iter() {
          let val : Vec<u8> = try!(it.get_value()).iter().map(|v|v.clone()).collect();
          data.push(Datum { content: val });
        }

        Ok(data)
      },
      other => Err(YakError::ProtocolError)
    }
  }

  fn send(&mut self, req: Request) -> Result<(), YakError> {
    let mut message = MallocMessageBuilder::new_default();
    req.encode(&mut message);
    try!(serialize_packed::write_message(&mut self.connection, &mut message));
    try!(self.connection.flush());
    Ok(())
  }

  pub fn truncate(&mut self) -> Result<(), YakError> {
    let req = Request::truncate(&self.space);
    try!(self.send(req));
    debug!("Waiting for response");

    let message_reader = try!(serialize_packed::read_message(&mut self.connection, ReaderOptions::new()));
    Self::expect_ok(&message_reader)
  }

  pub fn write(&mut self, key: &[u8], val: &[u8]) -> Result<(), YakError> {
    let req = Request::write(&self.space, key, val);
    try!(self.send(req));
    debug!("Waiting for response");

    let message_reader = try!(serialize_packed::read_message(&mut self.connection, ReaderOptions::new()));
    Self::expect_ok(&message_reader)
  }

  pub fn read(&mut self, key: &[u8]) -> Result<Vec<Datum>, YakError> {
    let req = Request::read(&self.space, key);
    try!(self.send(req));
    debug!("Waiting for response");

    let message_reader = try!(serialize_packed::read_message(&mut self.connection, ReaderOptions::new()));
    Self::expect_datum_list(&message_reader)
  }
}

impl From<url::ParseError> for YakError {
  fn from(err: url::ParseError) -> YakError {
    YakError::UrlParseError(err)
  }
}

impl From<io::Error> for YakError {
  fn from(err: io::Error) -> YakError {
    YakError::IoError(err)
  }
}

impl From<capnp::Error> for YakError {
  fn from(err: capnp::Error) -> YakError {
    YakError::CapnpError(err)
  }
}

impl From<capnp::NotInSchema> for YakError {
  fn from(err: capnp::NotInSchema) -> YakError {
    YakError::CapnpNotInSchema(err)
  }
}
<|endoftext|>


<commit_before>#![feature(slice_patterns)]
#![feature(path_ext)]
extern crate eve;
extern crate hyper;
extern crate cookie;
extern crate mime;
extern crate url;
extern crate websocket;
extern crate rustc_serialize;
extern crate conduit_mime_types;

use std::io::Read;
use std::io::Write;
use std::fs::File;
use std::error::Error;
use hyper::net::Fresh;
use hyper::server::{Server, Request, Response};
use hyper::uri::RequestUri;
use hyper::Url;
use hyper::header::{Headers,ContentType,Location,SetCookie};
use cookie::Cookie;
use mime::Mime;
use url::SchemeData::Relative;
use rustc_serialize::json;
use websocket::{Message, Sender};
use std::path::Path;
use std::fs::PathExt;
use conduit_mime_types::Types;
use std::str::FromStr;
use std::env;

use eve::client::*;
use eve::server;
use eve::value::Value;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Session {
	client: String,
	id: String,
	user_id: String,
	object: String,
	created_at: f64,
	expires_at: f64,
	ip: String,
	user: User,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct User {
	custom: Custom,
	id: String,
	realm_id: String,
	username: String,
	state: String,
	user_type: String,
	reference: Option<String>,
	name: String,
	email: String,
	object: String,
	last_login_at: f64,
	last_login_on: f64,
	created_at: f64,
	first_name: Option<String>,
	last_name: Option<String>,
	credentials: Vec<Credential>,
	membership_count: f64,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Custom;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Credential {
	id: String,
	credential_type: String,
	object: String,
}

fn main() {

    // TODO high thread-count is a workaround for https://github.com/hyperium/hyper/issues/368
	Server::http("0.0.0.0:8080").unwrap().handle_threads(login, 100).unwrap();
}

fn read_file_bytes(filename: &str) -> Vec<u8> {
    let mut file = File::open(&filename).unwrap();
    let mut contents: Vec<u8> = Vec::new();
	file.read_to_end(&mut contents).unwrap();
	contents
}

fn file_exists(path: &str) -> bool {
	let path_obj = Path::new(path);
	path_obj.is_file() && path_obj.exists()
}

fn serve_local_or_file(mut res: Response<Fresh>, path: &Vec<String>, default_file: &str) {
	let mime_types = Types::new().unwrap();
	let local_path = path[1..].iter().fold("../ui".to_owned(), |end, cur| end + "/" + cur);
	let file;
	let file_path: &str;
	if file_exists(&local_path) {
		file = read_file_bytes(&local_path);
		file_path = &local_path;
	} else {
		let content = read_file_bytes(default_file);
		//@HACK, @TODO: absolutize the html file so that it looks in the right place
		//this allows us to use file:/// locally, while still doing the right thing
		//when we're hooked up to the server
		let mut str = String::from_utf8(content).unwrap();
		str = str.replace("href=\"", "href=\"/app/");
		str = str.replace("src=\"", "src=\"/app/");
		str = str.replace("/app/http", "http");
		file = str.as_bytes().to_owned();
		file_path = default_file;
	}
	let mime: Mime = Mime::from_str(mime_types.mime_for_path(Path::new(&file_path))).unwrap();
	res.headers_mut().set(ContentType(mime));
	let mut res = res.start().unwrap();
	res.write_all(&file).unwrap();
	res.end().unwrap();
}

fn login(req: Request, mut res: Response<Fresh>) {

	// Don't use a port if we're running in local mode
	let mut port = ":8000";
	for argument in env::args() {
    	match &*argument {
    		"local" => {
    			port = "";
    		},
    		_ => continue,
    	}
	}

	match (&req.method.clone(), &req.uri.clone()) {
		(&hyper::Get, &RequestUri::AbsolutePath(ref relative_path)) => {

			// Form a url from the path
			let absolute_path = "http://localhost".to_string() + relative_path;
			let url = Url::parse(&*absolute_path).unwrap();

			// Get the file name
			let scheme_data = &url.scheme_data;

			let requested_file = match scheme_data {
				&Relative(ref rsd) => rsd.path[0].clone(),
				_ => panic!("Expected relative path"),
			};
			let path_info = match scheme_data {
				&Relative(ref rsd) => rsd,
				_ => panic!("Expected relative path"),
			};

			// Parse the query string
			let query_pairs = &url.query_pairs();

			// Handle login
			match &*requested_file {
				"app.html" | "app" => {
					serve_local_or_file(res, &path_info.path, "../ui/app.html");
				},
				"editor.html" | "editor" => {
					serve_local_or_file(res, &path_info.path, "../ui/editor.html");
				},
				"login.html" => {
					println!("Authenticating User");

					let referer = format!("{}",req.headers.get::<hyper::header::Referer>().unwrap());
					let referer_url = Url::parse(&*referer).unwrap();

					let pairs = query_pairs.clone().unwrap();
					match &pairs[..] {
						[(_ , ref page), (ref token_type, ref token), ..] if token_type.clone() == "token".to_string() => {

							// We have a login token, now to authenticate
							let client = hyper::client::Client::new();
							let api_call = "https://api-e1.authrocket.com/v1/sessions/".to_string() + token;
							let req = client.request(hyper::method::Method::Get,&*api_call);

							// Set the appropriate headers for authorocket
							let mut headers = Headers::new();
							let json: Mime = "application/json".parse().unwrap();
							let content_type = ContentType(json);
							headers.set_raw("X-Authrocket-Account",vec!["org_0vC7wPw9XphPGQnSqYB6bz".to_string().into_bytes()]);
							headers.set_raw("X-Authrocket-Api-Key",vec!["key_jtnCRWxQvDD0p5HATR9RBIe4WnxnwV6pWNzwmZQLnSZ".to_string().into_bytes()]);
							headers.set_raw("X-Authrocket-Realm",vec!["rl_0vC7wd03CqwhpK7kT8fvAc".to_string().into_bytes()]);
							headers.set_raw("Accept",vec!["application/json".to_string().into_bytes()]);
							headers.set(content_type);

							// Send the request and receive a response with session data
							let mut client_res = req.headers(headers).send().unwrap();

							match client_res.status_raw() {

								&hyper::http::RawStatus(200,_) => {

									let mut body = String::new();
									client_res.read_to_string(&mut body).unwrap();
									let session_data: Session = json::decode(&body).unwrap();
									println!("Welcome to Eve, {:?}!",session_data.user.username);
									println!("Login Successful. Redirecting to user area.");

									// Connect to the Eve runtime and add the user to the eveusers table
									let ws_result = open_websocket("ws://0.0.0.0:2794");
									match ws_result {
										// If things went okay, redirect to the Eve UI
										Ok(mut sender) => {
											// Form the response
											*res.status_mut() = hyper::status::StatusCode::PermanentRedirect;

											// Form the response headers
											let mut headers = Headers::new();
														//let foo = req.headers.get::<hyper::header::Host>();
											let redirect_url = referer_url.scheme.clone() + "://" + referer_url.domain().unwrap().clone() + port + "/" + page;
											let location = Location(redirect_url);
											//let location = Location("http://192.168.106.142:8000/editor".to_owned());
											//headers.set(Host{hostname:"192.168.106.142".to_owned(),port:Some(8000)});
											let user_cookie = Cookie::new("userid".to_string(),session_data.user.id.clone());
											let cookies = SetCookie(vec![user_cookie]);
											headers.set(location);
											headers.set(cookies);
											*res.headers_mut() = headers;

											// Create eveusers table and insert the new user
											let table_name = "eveusers";
											let table_fields = vec!["id","username"];

											let row_data = vec![
																Value::String(session_data.user.id.clone()),
																Value::String(session_data.user.username.clone())
														   	   ];
											let insert_user = insert_fact(&table_name,&table_fields,&row_data,None);
											send_event(&insert_user,&mut sender);
											let _ = sender.send_message(Message::Close(None));
										}
										// Otherwise, throw an error... maybe redirect to a special page.
										Err(e) => {
											println!("ERROR: Had trouble connecting to the Eve runtime: {}. Is the server running?",e);
											*res.status_mut() = hyper::status::StatusCode::NotFound;
											panic!("Oh no!");
											//serve_file("404.html",res);
										}
									}

									println!("Login complete.");
								}
								_ => {
									println!("ERROR: Could not authenticate user with token {}",token);
									*res.status_mut() = hyper::status::StatusCode::Forbidden;
									panic!("Oh no!");
									//serve_file("404.html",res);
								}
							};
						},
						_ => panic!("Oh no!"), //serve_file("404.html",res),
					}
				},
				"logout.html" => {
					println!("Logging out...");
					let user_id = server::get_user_id(req.headers.get::<hyper::header::Cookie>());
                	println!("{:?}",user_id);
				},
				"favicon.ico" => (),
				other => panic!("Cannot serve {}",other), //serve_file(&*requested_file,res),
			};
		}
		_ => panic!("Oh no!"),
	}
}<commit_msg>Delete dead code<commit_after>#![feature(slice_patterns)]
#![feature(path_ext)]
extern crate eve;
extern crate hyper;
extern crate cookie;
extern crate mime;
extern crate url;
extern crate websocket;
extern crate rustc_serialize;
extern crate conduit_mime_types;

use std::io::Read;
use std::io::Write;
use std::fs::File;
use std::error::Error;
use hyper::net::Fresh;
use hyper::server::{Server, Request, Response};
use hyper::uri::RequestUri;
use hyper::Url;
use hyper::header::{Headers,ContentType,Location,SetCookie};
use cookie::Cookie;
use mime::Mime;
use url::SchemeData::Relative;
use rustc_serialize::json;
use websocket::{Message, Sender};
use std::path::Path;
use std::fs::PathExt;
use conduit_mime_types::Types;
use std::str::FromStr;
use std::env;

use eve::client::*;
use eve::server;
use eve::value::Value;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Session {
	client: String,
	id: String,
	user_id: String,
	object: String,
	created_at: f64,
	expires_at: f64,
	ip: String,
	user: User,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct User {
	custom: Custom,
	id: String,
	realm_id: String,
	username: String,
	state: String,
	user_type: String,
	reference: Option<String>,
	name: String,
	email: String,
	object: String,
	last_login_at: f64,
	last_login_on: f64,
	created_at: f64,
	first_name: Option<String>,
	last_name: Option<String>,
	credentials: Vec<Credential>,
	membership_count: f64,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Custom;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Credential {
	id: String,
	credential_type: String,
	object: String,
}

fn main() {

    // TODO high thread-count is a workaround for https://github.com/hyperium/hyper/issues/368
	Server::http("0.0.0.0:8080").unwrap().handle_threads(login, 100).unwrap();
}

fn read_file_bytes(filename: &str) -> Vec<u8> {
    let mut file = File::open(&filename).unwrap();
    let mut contents: Vec<u8> = Vec::new();
	file.read_to_end(&mut contents).unwrap();
	contents
}

fn file_exists(path: &str) -> bool {
	let path_obj = Path::new(path);
	path_obj.is_file() && path_obj.exists()
}

fn serve_local_or_file(mut res: Response<Fresh>, path: &Vec<String>, default_file: &str) {
	let mime_types = Types::new().unwrap();
	let local_path = path[1..].iter().fold("../ui".to_owned(), |end, cur| end + "/" + cur);
	let file;
	let file_path: &str;
	if file_exists(&local_path) {
		file = read_file_bytes(&local_path);
		file_path = &local_path;
	} else {
		let content = read_file_bytes(default_file);
		//@HACK, @TODO: absolutize the html file so that it looks in the right place
		//this allows us to use file:/// locally, while still doing the right thing
		//when we're hooked up to the server
		let mut str = String::from_utf8(content).unwrap();
		str = str.replace("href=\"", "href=\"/app/");
		str = str.replace("src=\"", "src=\"/app/");
		str = str.replace("/app/http", "http");
		file = str.as_bytes().to_owned();
		file_path = default_file;
	}
	let mime: Mime = Mime::from_str(mime_types.mime_for_path(Path::new(&file_path))).unwrap();
	res.headers_mut().set(ContentType(mime));
	let mut res = res.start().unwrap();
	res.write_all(&file).unwrap();
	res.end().unwrap();
}

fn login(req: Request, mut res: Response<Fresh>) {

	// Don't use a port if we're running in local mode
	let mut port = ":8000";
	for argument in env::args() {
    	match &*argument {
    		"local" => {
    			port = "";
    		},
    		_ => continue,
    	}
	}

	match (&req.method.clone(), &req.uri.clone()) {
		(&hyper::Get, &RequestUri::AbsolutePath(ref relative_path)) => {

			// Form a url from the path
			let absolute_path = "http://localhost".to_string() + relative_path;
			let url = Url::parse(&*absolute_path).unwrap();

			// Get the file name
			let scheme_data = &url.scheme_data;

			let requested_file = match scheme_data {
				&Relative(ref rsd) => rsd.path[0].clone(),
				_ => panic!("Expected relative path"),
			};
			let path_info = match scheme_data {
				&Relative(ref rsd) => rsd,
				_ => panic!("Expected relative path"),
			};

			// Parse the query string
			let query_pairs = &url.query_pairs();

			// Handle login
			match &*requested_file {
				"app.html" | "app" => {
					serve_local_or_file(res, &path_info.path, "../ui/app.html");
				},
				"editor.html" | "editor" => {
					serve_local_or_file(res, &path_info.path, "../ui/editor.html");
				},
				"login.html" => {
					println!("Authenticating User");

					let referer = format!("{}",req.headers.get::<hyper::header::Referer>().unwrap());
					let referer_url = Url::parse(&*referer).unwrap();

					let pairs = query_pairs.clone().unwrap();
					match &pairs[..] {
						[(_ , ref page), (ref token_type, ref token), ..] if token_type.clone() == "token".to_string() => {

							// We have a login token, now to authenticate
							let client = hyper::client::Client::new();
							let api_call = "https://api-e1.authrocket.com/v1/sessions/".to_string() + token;
							let req = client.request(hyper::method::Method::Get,&*api_call);

							// Set the appropriate headers for authorocket
							let mut headers = Headers::new();
							let json: Mime = "application/json".parse().unwrap();
							let content_type = ContentType(json);
							headers.set_raw("X-Authrocket-Account",vec!["org_0vC7wPw9XphPGQnSqYB6bz".to_string().into_bytes()]);
							headers.set_raw("X-Authrocket-Api-Key",vec!["key_jtnCRWxQvDD0p5HATR9RBIe4WnxnwV6pWNzwmZQLnSZ".to_string().into_bytes()]);
							headers.set_raw("X-Authrocket-Realm",vec!["rl_0vC7wd03CqwhpK7kT8fvAc".to_string().into_bytes()]);
							headers.set_raw("Accept",vec!["application/json".to_string().into_bytes()]);
							headers.set(content_type);

							// Send the request and receive a response with session data
							let mut client_res = req.headers(headers).send().unwrap();

							match client_res.status_raw() {

								&hyper::http::RawStatus(200,_) => {

									let mut body = String::new();
									client_res.read_to_string(&mut body).unwrap();
									let session_data: Session = json::decode(&body).unwrap();
									println!("Welcome to Eve, {:?}!",session_data.user.username);
									println!("Login Successful. Redirecting to user area.");

									// Connect to the Eve runtime and add the user to the eveusers table
									let ws_result = open_websocket("ws://0.0.0.0:2794");
									match ws_result {
										// If things went okay, redirect to the Eve UI
										Ok(mut sender) => {
											// Form the response
											*res.status_mut() = hyper::status::StatusCode::PermanentRedirect;

											// Form the response headers
											let mut headers = Headers::new();
											let redirect_url = referer_url.scheme.clone() + "://" + referer_url.domain().unwrap().clone() + port + "/" + page;
											let location = Location(redirect_url);
											let user_cookie = Cookie::new("userid".to_string(),session_data.user.id.clone());
											let cookies = SetCookie(vec![user_cookie]);
											headers.set(location);
											headers.set(cookies);
											*res.headers_mut() = headers;

											// Create eveusers table and insert the new user
											let table_name = "eveusers";
											let table_fields = vec!["id","username"];

											let row_data = vec![
																Value::String(session_data.user.id.clone()),
																Value::String(session_data.user.username.clone())
														   	   ];
											let insert_user = insert_fact(&table_name,&table_fields,&row_data,None);
											send_event(&insert_user,&mut sender);
											let _ = sender.send_message(Message::Close(None));
										}
										// Otherwise, throw an error... maybe redirect to a special page.
										Err(e) => {
											println!("ERROR: Had trouble connecting to the Eve runtime: {}. Is the server running?",e);
											*res.status_mut() = hyper::status::StatusCode::NotFound;
											panic!("Oh no!");
											//serve_file("404.html",res);
										}
									}

									println!("Login complete.");
								}
								_ => {
									println!("ERROR: Could not authenticate user with token {}",token);
									*res.status_mut() = hyper::status::StatusCode::Forbidden;
									panic!("Oh no!");
									//serve_file("404.html",res);
								}
							};
						},
						_ => panic!("Oh no!"), //serve_file("404.html",res),
					}
				},
				"logout.html" => {
					println!("Logging out...");
					let user_id = server::get_user_id(req.headers.get::<hyper::header::Cookie>());
                	println!("{:?}",user_id);
				},
				"favicon.ico" => (),
				other => panic!("Cannot serve {}",other), //serve_file(&*requested_file,res),
			};
		}
		_ => panic!("Oh no!"),
	}
}<|endoftext|>


<commit_before>use std::str::FromStr;

use parsers::ParseError;

/// Defines the units to be used for scaling paint servers, per the [svg specification].
///
/// [svg spec]: https://www.w3.org/TR/SVG/pservers.html
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum PaintServerUnits {
    UserSpaceOnUse,
    ObjectBoundingBox
}

impl FromStr for PaintServerUnits {
    type Err = ParseError;

    fn from_str (s: &str) -> Result<PaintServerUnits, ParseError> {
        match s {
            "userSpaceOnUse"    => Ok (PaintServerUnits::UserSpaceOnUse),
            "objectBoundingBox" => Ok (PaintServerUnits::ObjectBoundingBox),
            _                   => Err (ParseError::new ("expected 'userSpaceOnUse' or 'objectBoundingBox'"))
        }
    }
}

impl Default for PaintServerUnits {
    fn default () -> PaintServerUnits {
        PaintServerUnits::ObjectBoundingBox
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::str::FromStr;

    #[test]
    fn parsing_invalid_strings_yields_error () {
        assert! (PaintServerUnits::from_str ("").is_err ());
        assert! (PaintServerUnits::from_str ("foo").is_err ());
    }

    #[test]
    fn parses_paint_server_units () {
        assert_eq! (PaintServerUnits::from_str ("userSpaceOnUse"), Ok (PaintServerUnits::UserSpaceOnUse));
        assert_eq! (PaintServerUnits::from_str ("objectBoundingBox"), Ok (PaintServerUnits::ObjectBoundingBox));
    }
}
<commit_msg>paint_server.rs: Fix errors<commit_after>use std::str::FromStr;

use error::*;
use parsers::ParseError;

/// Defines the units to be used for scaling paint servers, per the [svg specification].
///
/// [svg spec]: https://www.w3.org/TR/SVG/pservers.html
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum PaintServerUnits {
    UserSpaceOnUse,
    ObjectBoundingBox
}

impl FromStr for PaintServerUnits {
    type Err = AttributeError;

    fn from_str (s: &str) -> Result<PaintServerUnits, AttributeError> {
        match s {
            "userSpaceOnUse"    => Ok (PaintServerUnits::UserSpaceOnUse),
            "objectBoundingBox" => Ok (PaintServerUnits::ObjectBoundingBox),
            _                   => Err (AttributeError::Parse (ParseError::new ("expected 'userSpaceOnUse' or 'objectBoundingBox'")))
        }
    }
}

impl Default for PaintServerUnits {
    fn default () -> PaintServerUnits {
        PaintServerUnits::ObjectBoundingBox
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::str::FromStr;

    #[test]
    fn parsing_invalid_strings_yields_error () {
        assert! (PaintServerUnits::from_str ("").is_err ());
        assert! (PaintServerUnits::from_str ("foo").is_err ());
    }

    #[test]
    fn parses_paint_server_units () {
        assert_eq! (PaintServerUnits::from_str ("userSpaceOnUse"), Ok (PaintServerUnits::UserSpaceOnUse));
        assert_eq! (PaintServerUnits::from_str ("objectBoundingBox"), Ok (PaintServerUnits::ObjectBoundingBox));
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! # ICU collation support for rust
//!
//! This crate provides [collation](https://en.wikipedia.org/wiki/Unicode_collation_algorithm)
//! (locale-sensitive string ordering), based on the collation as implemented by the ICU library.
//! Specifically the functionality exposed through its C API, as available in the [header
//! `ucol.h`](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/ucol_8h.html).
//!
//! The main type is [UCollator], which can be created using `UCollator::try_from` from a `&str`.
//!
//! A detailed discussion of collation is out of scope of source code documentation.  An interested
//! reader can check out the [collation documentation on the ICU user
//! guide](http://userguide.icu-project.org/collation).
//!
//! Are you missing some features from this crate?  Consider [reporting an
//! issue](https://github.com/google/rust_icu/issues) or even [contributing the
//! functionality](https://github.com/google/rust_icu/pulls).
//!
//! ## Examples
//!
//! Some example code for the use of collation is given below.
//!
//! First off, the more low-level API, which uses [ustring::UChar] is the following, which requires
//! a conversion to [ustring::UChar] prior to use.  This function is mostly used in algorithms that
//! compose Unicode functionality.
//!
//! ```
//! use rust_icu_ustring as ustring;
//! use rust_icu_ucol as ucol;
//! use std::convert::TryFrom;
//! let collator = ucol::UCollator::try_from("sr-Latn").expect("collator");
//! let mut mixed_up = vec!["d", "dž", "đ", "a", "b", "c", "č", "ć"];
//! mixed_up.sort_by(|a, b| {
//!    let first = ustring::UChar::try_from(*a).expect("first");
//!    let second = ustring::UChar::try_from(*b).expect("second");
//!    collator.strcoll(&first, &second)
//! });
//! let alphabet = vec!["a", "b", "c", "č", "ć", "d", "dž", "đ"];
//! assert_eq!(alphabet, mixed_up);
//! ```
//! A more rustful API is [UCollator::strcoll_utf8] which can operate on rust `AsRef<str>` and can
//! be used without converting the input data ahead of time.
//!
//! ```
//! use rust_icu_ustring as ustring;
//! use rust_icu_ucol as ucol;
//! use std::convert::TryFrom;
//! let collator = ucol::UCollator::try_from("sr-Latn").expect("collator");
//! let mut mixed_up = vec!["d", "dž", "đ", "a", "b", "c", "č", "ć"];
//! mixed_up.sort_by(|a, b| collator.strcoll_utf8(a, b).expect("strcoll_utf8"));
//! let alphabet = vec!["a", "b", "c", "č", "ć", "d", "dž", "đ"];
//! assert_eq!(alphabet, mixed_up);
//! ```
use {
    rust_icu_common as common, rust_icu_sys as sys,
    rust_icu_sys::versioned_function,
    rust_icu_sys::*,
    rust_icu_ustring as ustring,
    std::{cmp::Ordering, convert::TryFrom, ffi, ptr},
};

#[derive(Debug)]
pub struct UCollator {
    rep: ptr::NonNull<sys::UCollator>,
}

impl Drop for UCollator {
    /// Releases the resources taken up by a single collator.
    ///
    /// Implements `ucol_close`
    fn drop(&mut self) {
        unsafe { versioned_function!(ucol_close)(self.rep.as_ptr()) };
    }
}

impl TryFrom<&str> for UCollator {
    type Error = common::Error;
    /// Makes a new collator from the supplied locale, e.g. `en-US`, or
    /// `de@collation=phonebook`.
    ///
    /// Other examples:
    ///
    /// * `el-u-kf-upper`
    /// * `el@colCaseFirst=upper`
    ///
    /// Implements ucol_open
    fn try_from(locale: &str) -> Result<UCollator, Self::Error> {
        let locale_cstr = ffi::CString::new(locale)?;
        let mut status = common::Error::OK_CODE;
        // Unsafety note: this is the way to create the collator.  We expect all
        // the passed-in values to be well-formed.
        let rep = unsafe {
            assert!(common::Error::is_ok(status));
            versioned_function!(ucol_open)(locale_cstr.as_ptr(), &mut status) as *mut sys::UCollator
        };
        common::Error::ok_or_warning(status)?;
        Ok(UCollator {
            rep: ptr::NonNull::new(rep).unwrap(),
        })
    }
}

impl UCollator {
    /// Compares strings `first` and `second` according to the collation rules in this collator.
    ///
    /// Returns [Ordering::Less] if `first` compares as less than `second`, and for other return
    /// codes respectively.
    ///
    /// Implements `ucol_strcoll`
    pub fn strcoll(&self, first: &ustring::UChar, second: &ustring::UChar) -> Ordering {
        let result = unsafe {
            assert!(first.len() <= std::i32::MAX as usize);
            assert!(second.len() <= std::i32::MAX as usize);
            versioned_function!(ucol_strcoll)(
                self.rep.as_ptr(),
                first.as_c_ptr(),
                first.len() as i32,
                second.as_c_ptr(),
                second.len() as i32,
            )
        };
        UCollator::to_rust_ordering(result)
    }

    /// Compares strings `first` and `second` according to the collation rules in this collator.
    ///
    /// Returns [Ordering::Less] if `first` compares as less than `second`, and for other return
    /// codes respectively.
    ///
    /// In contrast to [UCollator::strcoll], this function requires no string conversions to
    /// compare two rust strings.
    ///
    /// Implements `ucol_strcoll`
    pub fn strcoll_utf8(
        &self,
        first: impl AsRef<str>,
        second: impl AsRef<str>,
    ) -> Result<Ordering, common::Error> {
        let mut status = common::Error::OK_CODE;
        // Unsafety note:
        // - AsRef is always well formed UTF-8 in rust.
        let result = unsafe {
            assert!(first.as_ref().len() <= std::i32::MAX as usize);
            assert!(second.as_ref().len() <= std::i32::MAX as usize);
            versioned_function!(ucol_strcollUTF8)(
                self.rep.as_ptr(),
                first.as_ref().as_ptr() as *const i8,
                first.as_ref().len() as i32,
                second.as_ref().as_ptr() as *const i8,
                second.as_ref().len() as i32,
                &mut status,
            )
        };
        common::Error::ok_or_warning(status)?;
        Ok(UCollator::to_rust_ordering(result))
    }

    // Converts ICU ordering result type to a Rust ordering result type.
    fn to_rust_ordering(result: sys::UCollationResult) -> Ordering {
        match result {
            sys::UCollationResult::UCOL_LESS => Ordering::Less,
            sys::UCollationResult::UCOL_GREATER => Ordering::Greater,
            sys::UCollationResult::UCOL_EQUAL => Ordering::Equal,
        }
    }
}

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

    #[test]
    fn basic() {
        let _ = crate::UCollator::try_from("de@collation=phonebook").expect("collator created");
    }

    #[test]
    fn strcoll_utf8_test() -> Result<(), common::Error> {
        let collator = crate::UCollator::try_from("sr-Latn")?;
        let mut mixed_up = vec!["d", "dž", "đ", "a", "b", "c", "č", "ć"];
        mixed_up.sort_by(|a, b| collator.strcoll_utf8(a, b).expect("strcoll_utf8"));

        let alphabet = vec!["a", "b", "c", "č", "ć", "d", "dž", "đ"];
        assert_eq!(alphabet, mixed_up);
        Ok(())
    }

    #[test]
    fn strcoll_test() -> Result<(), common::Error> {
        let collator = crate::UCollator::try_from("sr-Latn")?;
        let mut mixed_up = vec!["d", "dž", "đ", "a", "b", "c", "č", "ć"];
        mixed_up.sort_by(|a, b| {
            let first = ustring::UChar::try_from(*a).expect("first");
            let second = ustring::UChar::try_from(*b).expect("second");
            collator.strcoll(&first, &second)
        });

        let alphabet = vec!["a", "b", "c", "č", "ć", "d", "dž", "đ"];
        assert_eq!(alphabet, mixed_up);
        Ok(())
    }
}
<commit_msg>Use std::os::raw::c_char instead of hardcoded i8<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! # ICU collation support for rust
//!
//! This crate provides [collation](https://en.wikipedia.org/wiki/Unicode_collation_algorithm)
//! (locale-sensitive string ordering), based on the collation as implemented by the ICU library.
//! Specifically the functionality exposed through its C API, as available in the [header
//! `ucol.h`](https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/ucol_8h.html).
//!
//! The main type is [UCollator], which can be created using `UCollator::try_from` from a `&str`.
//!
//! A detailed discussion of collation is out of scope of source code documentation.  An interested
//! reader can check out the [collation documentation on the ICU user
//! guide](http://userguide.icu-project.org/collation).
//!
//! Are you missing some features from this crate?  Consider [reporting an
//! issue](https://github.com/google/rust_icu/issues) or even [contributing the
//! functionality](https://github.com/google/rust_icu/pulls).
//!
//! ## Examples
//!
//! Some example code for the use of collation is given below.
//!
//! First off, the more low-level API, which uses [ustring::UChar] is the following, which requires
//! a conversion to [ustring::UChar] prior to use.  This function is mostly used in algorithms that
//! compose Unicode functionality.
//!
//! ```
//! use rust_icu_ustring as ustring;
//! use rust_icu_ucol as ucol;
//! use std::convert::TryFrom;
//! let collator = ucol::UCollator::try_from("sr-Latn").expect("collator");
//! let mut mixed_up = vec!["d", "dž", "đ", "a", "b", "c", "č", "ć"];
//! mixed_up.sort_by(|a, b| {
//!    let first = ustring::UChar::try_from(*a).expect("first");
//!    let second = ustring::UChar::try_from(*b).expect("second");
//!    collator.strcoll(&first, &second)
//! });
//! let alphabet = vec!["a", "b", "c", "č", "ć", "d", "dž", "đ"];
//! assert_eq!(alphabet, mixed_up);
//! ```
//! A more rustful API is [UCollator::strcoll_utf8] which can operate on rust `AsRef<str>` and can
//! be used without converting the input data ahead of time.
//!
//! ```
//! use rust_icu_ustring as ustring;
//! use rust_icu_ucol as ucol;
//! use std::convert::TryFrom;
//! let collator = ucol::UCollator::try_from("sr-Latn").expect("collator");
//! let mut mixed_up = vec!["d", "dž", "đ", "a", "b", "c", "č", "ć"];
//! mixed_up.sort_by(|a, b| collator.strcoll_utf8(a, b).expect("strcoll_utf8"));
//! let alphabet = vec!["a", "b", "c", "č", "ć", "d", "dž", "đ"];
//! assert_eq!(alphabet, mixed_up);
//! ```
use {
    rust_icu_common as common, rust_icu_sys as sys,
    rust_icu_sys::versioned_function,
    rust_icu_sys::*,
    rust_icu_ustring as ustring,
    std::{cmp::Ordering, convert::TryFrom, ffi, ptr},
};

#[derive(Debug)]
pub struct UCollator {
    rep: ptr::NonNull<sys::UCollator>,
}

impl Drop for UCollator {
    /// Releases the resources taken up by a single collator.
    ///
    /// Implements `ucol_close`
    fn drop(&mut self) {
        unsafe { versioned_function!(ucol_close)(self.rep.as_ptr()) };
    }
}

impl TryFrom<&str> for UCollator {
    type Error = common::Error;
    /// Makes a new collator from the supplied locale, e.g. `en-US`, or
    /// `de@collation=phonebook`.
    ///
    /// Other examples:
    ///
    /// * `el-u-kf-upper`
    /// * `el@colCaseFirst=upper`
    ///
    /// Implements ucol_open
    fn try_from(locale: &str) -> Result<UCollator, Self::Error> {
        let locale_cstr = ffi::CString::new(locale)?;
        let mut status = common::Error::OK_CODE;
        // Unsafety note: this is the way to create the collator.  We expect all
        // the passed-in values to be well-formed.
        let rep = unsafe {
            assert!(common::Error::is_ok(status));
            versioned_function!(ucol_open)(locale_cstr.as_ptr(), &mut status) as *mut sys::UCollator
        };
        common::Error::ok_or_warning(status)?;
        Ok(UCollator {
            rep: ptr::NonNull::new(rep).unwrap(),
        })
    }
}

impl UCollator {
    /// Compares strings `first` and `second` according to the collation rules in this collator.
    ///
    /// Returns [Ordering::Less] if `first` compares as less than `second`, and for other return
    /// codes respectively.
    ///
    /// Implements `ucol_strcoll`
    pub fn strcoll(&self, first: &ustring::UChar, second: &ustring::UChar) -> Ordering {
        let result = unsafe {
            assert!(first.len() <= std::i32::MAX as usize);
            assert!(second.len() <= std::i32::MAX as usize);
            versioned_function!(ucol_strcoll)(
                self.rep.as_ptr(),
                first.as_c_ptr(),
                first.len() as i32,
                second.as_c_ptr(),
                second.len() as i32,
            )
        };
        UCollator::to_rust_ordering(result)
    }

    /// Compares strings `first` and `second` according to the collation rules in this collator.
    ///
    /// Returns [Ordering::Less] if `first` compares as less than `second`, and for other return
    /// codes respectively.
    ///
    /// In contrast to [UCollator::strcoll], this function requires no string conversions to
    /// compare two rust strings.
    ///
    /// Implements `ucol_strcoll`
    pub fn strcoll_utf8(
        &self,
        first: impl AsRef<str>,
        second: impl AsRef<str>,
    ) -> Result<Ordering, common::Error> {
        let mut status = common::Error::OK_CODE;
        // Unsafety note:
        // - AsRef is always well formed UTF-8 in rust.
        let result = unsafe {
            assert!(first.as_ref().len() <= std::i32::MAX as usize);
            assert!(second.as_ref().len() <= std::i32::MAX as usize);
            versioned_function!(ucol_strcollUTF8)(
                self.rep.as_ptr(),
                first.as_ref().as_ptr() as *const ::std::os::raw::c_char,
                first.as_ref().len() as i32,
                second.as_ref().as_ptr() as *const ::std::os::raw::c_char,
                second.as_ref().len() as i32,
                &mut status,
            )
        };
        common::Error::ok_or_warning(status)?;
        Ok(UCollator::to_rust_ordering(result))
    }

    // Converts ICU ordering result type to a Rust ordering result type.
    fn to_rust_ordering(result: sys::UCollationResult) -> Ordering {
        match result {
            sys::UCollationResult::UCOL_LESS => Ordering::Less,
            sys::UCollationResult::UCOL_GREATER => Ordering::Greater,
            sys::UCollationResult::UCOL_EQUAL => Ordering::Equal,
        }
    }
}

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

    #[test]
    fn basic() {
        let _ = crate::UCollator::try_from("de@collation=phonebook").expect("collator created");
    }

    #[test]
    fn strcoll_utf8_test() -> Result<(), common::Error> {
        let collator = crate::UCollator::try_from("sr-Latn")?;
        let mut mixed_up = vec!["d", "dž", "đ", "a", "b", "c", "č", "ć"];
        mixed_up.sort_by(|a, b| collator.strcoll_utf8(a, b).expect("strcoll_utf8"));

        let alphabet = vec!["a", "b", "c", "č", "ć", "d", "dž", "đ"];
        assert_eq!(alphabet, mixed_up);
        Ok(())
    }

    #[test]
    fn strcoll_test() -> Result<(), common::Error> {
        let collator = crate::UCollator::try_from("sr-Latn")?;
        let mut mixed_up = vec!["d", "dž", "đ", "a", "b", "c", "č", "ć"];
        mixed_up.sort_by(|a, b| {
            let first = ustring::UChar::try_from(*a).expect("first");
            let second = ustring::UChar::try_from(*b).expect("second");
            collator.strcoll(&first, &second)
        });

        let alphabet = vec!["a", "b", "c", "č", "ć", "d", "dž", "đ"];
        assert_eq!(alphabet, mixed_up);
        Ok(())
    }
}
<|endoftext|>


<commit_before>use super::super::api;

pub struct Tree {
    root: Box<Node>
}

struct Node {
    left: Option<Box<Node>>,
    right: Option<Box<Node>>,
    criterion: Option<usize>,
    target: Option<api::Target>
}

pub fn id3<T>(data: &api::DataSet<T>, solver: &api::Solver<T>, criterions: &Vec<Box<api::Criterion<T>>>) -> Tree {
    Tree {
        root: create_node(data, &api::all_view(data), solver, criterions)
    }
}

fn create_node<T>(data: &api::DataSet<T>, view: &api::DataSetView, solver: &api::Solver<T>, criterions: &Vec<Box<api::Criterion<T>>>) -> Box<Node> {
    let mut max = 0f64;
    let mut index = 0usize;
    for (i, criterion) in criterions.iter().enumerate() {
    let current = solver(data, view, &**criterion);
    if max < current {
        max = current;
        index = i;
    }
    }
    let criterion = &criterions[index];
    let mut left_records = Vec::new();
    let mut right_records = Vec::new();
    for i in view.iter() {
    let record = &data.records[*i];
    if criterion(&record.0) {
        right_records.push(*i)
    } else {
        left_records.push(*i)
    }
    }
    if right_records.is_empty() || left_records.is_empty() {
    let target = if right_records.len() < left_records.len() {
        calculate_target(data, &left_records)
    } else {
        calculate_target(data, &right_records)
    };
    Box::new(Node{left: None, right: None, criterion: None, target: Some(target)})
    } else {
    Box::new(Node{
        left: Some(create_node(data, &left_records, solver, criterions)),
        right: Some(create_node(data, &right_records, solver, criterions)),
        criterion: Some(index),
        target: None
    })
    }
}

fn calculate_target<T>(data: &api::DataSet<T>, view: &api::DataSetView) -> api::Target {
    let mut classes = vec![0; data.target_count];
    for index in view.iter() {
    let record = &data.records[*index];
    classes[record.1 as usize] += 1;
    }
    let mut max_class = 0;
    let mut target = 0;
    for (i, class) in classes.iter().enumerate() {
    if max_class < *class {
        max_class = *class;
        target = i;
    }
    }
    target as u32
}

fn apply_node<T>(node: &Box<Node>, record: &T, criterions: &Vec<Box<api::Criterion<T>>>) -> api::Target {
    match node.target {
        Some(target) => target,
        None => {
            let criterion = node.criterion.unwrap();
            if criterions[criterion](record) {
            match node.right {
                Some(ref nnode) => apply_node(nnode, record, criterions),
                None => panic!("assimetric tree")
            }
            } else {
            match node.left {
                Some(ref nnode) => apply_node(nnode, record, criterions),
                None => panic!("assimetric tree")
            }
            }
        }
    }
}

impl Tree {

    pub fn apply<T>(&self, record: &T, criterions: &Vec<Box<api::Criterion<T>>>) -> api::Target {
        apply_node(&self.root, record, criterions)
    }
}
<commit_msg>formatting<commit_after>use super::super::api;

pub struct Tree {
    root: Box<Node>
}

struct Node {
    left: Option<Box<Node>>,
    right: Option<Box<Node>>,
    criterion: Option<usize>,
    target: Option<api::Target>
}

pub fn id3<T>(data: &api::DataSet<T>, solver: &api::Solver<T>, criterions: &Vec<Box<api::Criterion<T>>>) -> Tree {
    Tree {
        root: create_node(data, &api::all_view(data), solver, criterions)
    }
}

fn create_node<T>(data: &api::DataSet<T>, view: &api::DataSetView, solver: &api::Solver<T>, criterions: &Vec<Box<api::Criterion<T>>>) -> Box<Node> {
    let mut max = 0f64;
    let mut index = 0usize;
    for (i, criterion) in criterions.iter().enumerate() {
        let current = solver(data, view, &**criterion);
        if max < current {
            max = current;
            index = i;
        }
    }
    let criterion = &criterions[index];
    let mut left_records = Vec::new();
    let mut right_records = Vec::new();
    for i in view.iter() {
        let record = &data.records[*i];
        if criterion(&record.0) {
            right_records.push(*i)
        } else {
            left_records.push(*i)
        }
    }
    if right_records.is_empty() || left_records.is_empty() {
        let target = if right_records.len() < left_records.len() {
            calculate_target(data, &left_records)
        } else {
            calculate_target(data, &right_records)
        };
        Box::new(Node{left: None, right: None, criterion: None, target: Some(target)})
    } else {
        Box::new(Node{
            left: Some(create_node(data, &left_records, solver, criterions)),
            right: Some(create_node(data, &right_records, solver, criterions)),
            criterion: Some(index),
            target: None
        })
    }
}

fn calculate_target<T>(data: &api::DataSet<T>, view: &api::DataSetView) -> api::Target {
    let mut classes = vec![0; data.target_count];
    for index in view.iter() {
        let record = &data.records[*index];
        classes[record.1 as usize] += 1;
    }
    let mut max_class = 0;
    let mut target = 0;
    for (i, class) in classes.iter().enumerate() {
        if max_class < *class {
            max_class = *class;
            target = i;
        }
    }
    target as u32
}

fn apply_node<T>(node: &Box<Node>, record: &T, criterions: &Vec<Box<api::Criterion<T>>>) -> api::Target {
    match node.target {
        Some(target) => target,
        None => {
            let criterion = node.criterion.unwrap();
            if criterions[criterion](record) {
                match node.right {
                    Some(ref nnode) => apply_node(nnode, record, criterions),
                    None => panic!("assimetric tree")
                }
            } else {
                match node.left {
                    Some(ref nnode) => apply_node(nnode, record, criterions),
                    None => panic!("assimetric tree")
                }
            }
        }
    }
}

impl Tree {

    pub fn apply<T>(&self, record: &T, criterions: &Vec<Box<api::Criterion<T>>>) -> api::Target {
        apply_node(&self.root, record, criterions)
    }
}
<|endoftext|>


<commit_before>//! The fast sweeping method for the eikonal equation.
//!
//! This is an implementation of the fast sweeping method proposed by Zhao (2004). It solves the
//! eikonal equation
//!
//! ‖∇u‖ = 1,
//!
//! where ‖.‖ denotes a norm, by performing 2^N Gauss-Seidel sweeps in alternating directions. Here
//! N is the dimension. Zhao showed that the accuracy for the Euclidean norm is O(h log h).

/// Computes the solution of the eikonal equation in 3D using the fast sweeping algorithm.
///
/// `d` should be initialized to a large value at the unknown nodes.
///
/// `inv_dual_norm(d, [d1, d2, d3], [s1, s2, s3]) -> t` needs to solve the "inverse problem" for the norm:
/// Given values `d_i` at points `-s_i e_i`, find the largest value `t ≤ d` at the origin such that
/// `||p|| ≤ 1`, where `p_i = (s_i (t - d_i))_+` and `||p||` is the __dual__ anisotropic norm.
pub fn fast_sweep_3d<F>(d: &mut [f64], dim: (usize, usize, usize), mut inv_dual_norm: F)
where
    F: FnMut(f64, [f64; 3], [f64; 3]) -> f64,
{
    let (nx, ny, nz) = dim;
    assert_eq!(nx * ny * nz, d.len());
    let (sx, sy, _sz) = (ny * nz, nz, 1);
    // see fast_sweep_2d for discussion
    for p in 1..nx {
        for dir in 0..2 {
            let (di_plane, djk, isign) = if dir == 0 {
                let (low, high) = d.split_at_mut(p * sx);
                (&low[(p - 1) * sx..][..sx], &mut high[..sx], 1.)
            } else {
                let i = nx - 1 - p;
                let (low, high) = d.split_at_mut((i + 1) * sx);
                (&high[..sx], &mut low[i * sx..][..sx], -1.)
            };
            for q in 1..ny {
                for dir in 0..2 {
                    let (di, dj, dk, jsign) = if dir == 0 {
                        let j = q;
                        let (low, high) = djk.split_at_mut(j * sy);
                        (
                            &di_plane[j * sy..][..sy],
                            &low[(j - 1) * sy..][..sy],
                            &mut high[..sy],
                            1.,
                        )
                    } else {
                        let j = ny - 1 - q;
                        let (low, high) = djk.split_at_mut((j + 1) * sy);
                        (
                            &di_plane[j * sy..][..sy],
                            &high[..sy],
                            &mut low[j * sy..][..sy],
                            -1.,
                        )
                    };
                    for r in 1..nz {
                        let k = r;
                        dk[k] = inv_dual_norm(dk[k], [di[k], dj[k], dk[k - 1]], [isign, jsign, 1.]);
                        let k = nz - 1 - r;
                        dk[k] =
                            inv_dual_norm(dk[k], [di[k], dj[k], dk[k + 1]], [isign, jsign, -1.]);
                    }
                }
            }
        }
    }
}

/// Computes the solution of the eikonal equation in 2D using the fast sweeping algorithm.
///
/// `inv_dual_norm(d, [d1, d2], [s1, s2]) -> t` needs to solve the "inverse problem" for the norm:
/// Given values `d_i` at points `-s_i e_i`, find the largest value `t ≤ d` at the origin such that
/// `||p|| ≤ 1`, where `p_i = (s_i (t - d_i))_+` and `||p||` is the __dual__ anisotropic norm.
pub fn fast_sweep_2d<F>(d: &mut [f64], dim: (usize, usize), mut inv_dual_norm: F)
where
    F: FnMut(f64, [f64; 2], [f64; 2]) -> f64,
{
    let (nx, ny) = dim;
    let (sx, _sy) = (ny, 1);
    assert_eq!(nx * ny, d.len());
    // sweep in 4 directions
    // for m in 0..4 {
    //     for p in 1..nx {
    //         let (i, ip, isign) = if m & 0b001 == 0 {
    //             (nx - 1 - p, nx - 1 - p + 1, -1.)
    //         } else {
    //             (p, p - 1, 1.)
    //         };
    //         for q in 1..ny {
    //             let (j, jp, jsign) = if m & 0b010 == 0 {
    //                 (ny - 1 - q, ny - 1 - q + 1, -1.)
    //             } else {
    //                 (q, q - 1, 1.)
    //             };
    //
    //             let s = i * sx + j * sy;
    //
    //             d[s] = inv_dual_norm(
    //                 d[s],
    //                 [d[ip * sx + j * sy], d[i * sx + jp * sy]],
    //                 [isign, jsign],
    //             );
    //         }
    //     }
    // }

    // sweep in 4 directions
    // try to avoid bounds checks and impove cache locality (about 45% faster than the above version)
    for p in 1..nx {
        let (di, dj) = d.split_at_mut(p * sx);
        let di = &di[(p - 1) * sx..][..ny];
        let dj = &mut dj[..ny];
        for q in 1..ny {
            let j = q;
            // Two independent computations (both forward and reversed sweep at once). Instruction
            // level parallelism! Major performance gain.
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j - 1]], [1., 1.]);
            // rust 1.30 cannot optimize away 2 bounds checks here :(
            let j = ny - 1 - q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j + 1]], [1., -1.]);
        }
        // The following code avoids bounds checks, but cannot exploit instruction level parallelism in the
        // above loop.
        // let mut prev = dj[0];
        // for (dj, di) in (&mut dj[1..]).into_iter().zip(di[1..].into_iter()) {
        //     prev = inv_dual_norm(*dj, [*di, prev], [1., 1.]);
        //     *dj = prev;
        // }
        // let mut prev = dj[ny - 1];
        // for (dj, di) in (&mut dj[..ny-1]).into_iter().zip(di[..ny-1].into_iter()).rev() {
        //     prev = inv_dual_norm(*dj, [*di, prev], [1., -1.]);
        //     *dj = prev;
        // }
    }
    for p in (0..nx - 1).rev() {
        let (dj, di) = d.split_at_mut((p + 1) * sx);
        let di = &di[..ny];
        let dj = &mut dj[p * sx..][..ny];
        for q in 1..ny {
            let j = q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j - 1]], [-1., 1.]);
            let j = ny - 1 - q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j + 1]], [-1., -1.]);
        }
    }
}
<commit_msg>Reordr<commit_after>//! The fast sweeping method for the eikonal equation.
//!
//! This is an implementation of the fast sweeping method proposed by Zhao (2004). It solves the
//! eikonal equation
//!
//! ‖∇u‖ = 1,
//!
//! where ‖.‖ denotes a norm, by performing 2^N Gauss-Seidel sweeps in alternating directions. Here
//! N is the dimension. Zhao showed that the accuracy for the Euclidean norm is O(h log h).

/// Computes the solution of the eikonal equation in 2D using the fast sweeping algorithm.
///
/// `inv_dual_norm(d, [d1, d2], [s1, s2]) -> t` needs to solve the "inverse problem" for the norm:
/// Given values `d_i` at points `-s_i e_i`, find the largest value `t ≤ d` at the origin such that
/// `||p|| ≤ 1`, where `p_i = (s_i (t - d_i))_+` and `||p||` is the __dual__ anisotropic norm.
pub fn fast_sweep_2d<F>(d: &mut [f64], dim: (usize, usize), mut inv_dual_norm: F)
where
    F: FnMut(f64, [f64; 2], [f64; 2]) -> f64,
{
    let (nx, ny) = dim;
    let (sx, _sy) = (ny, 1);
    assert_eq!(nx * ny, d.len());
    // sweep in 4 directions
    // for m in 0..4 {
    //     for p in 1..nx {
    //         let (i, ip, isign) = if m & 0b001 == 0 {
    //             (nx - 1 - p, nx - 1 - p + 1, -1.)
    //         } else {
    //             (p, p - 1, 1.)
    //         };
    //         for q in 1..ny {
    //             let (j, jp, jsign) = if m & 0b010 == 0 {
    //                 (ny - 1 - q, ny - 1 - q + 1, -1.)
    //             } else {
    //                 (q, q - 1, 1.)
    //             };
    //
    //             let s = i * sx + j * sy;
    //
    //             d[s] = inv_dual_norm(
    //                 d[s],
    //                 [d[ip * sx + j * sy], d[i * sx + jp * sy]],
    //                 [isign, jsign],
    //             );
    //         }
    //     }
    // }

    // sweep in 4 directions
    // try to avoid bounds checks and impove cache locality (about 45% faster than the above version)
    for p in 1..nx {
        let (di, dj) = d.split_at_mut(p * sx);
        let di = &di[(p - 1) * sx..][..ny];
        let dj = &mut dj[..ny];
        for q in 1..ny {
            let j = q;
            // Two independent computations (both forward and reversed sweep at once). Instruction
            // level parallelism! Major performance gain.
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j - 1]], [1., 1.]);
            // rust 1.30 cannot optimize away 2 bounds checks here :(
            let j = ny - 1 - q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j + 1]], [1., -1.]);
        }
        // The following code avoids bounds checks, but cannot exploit instruction level parallelism in the
        // above loop.
        // let mut prev = dj[0];
        // for (dj, di) in (&mut dj[1..]).into_iter().zip(di[1..].into_iter()) {
        //     prev = inv_dual_norm(*dj, [*di, prev], [1., 1.]);
        //     *dj = prev;
        // }
        // let mut prev = dj[ny - 1];
        // for (dj, di) in (&mut dj[..ny-1]).into_iter().zip(di[..ny-1].into_iter()).rev() {
        //     prev = inv_dual_norm(*dj, [*di, prev], [1., -1.]);
        //     *dj = prev;
        // }
    }
    for p in (0..nx - 1).rev() {
        let (dj, di) = d.split_at_mut((p + 1) * sx);
        let di = &di[..ny];
        let dj = &mut dj[p * sx..][..ny];
        for q in 1..ny {
            let j = q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j - 1]], [-1., 1.]);
            let j = ny - 1 - q;
            dj[j] = inv_dual_norm(dj[j], [di[j], dj[j + 1]], [-1., -1.]);
        }
    }
}

/// Computes the solution of the eikonal equation in 3D using the fast sweeping algorithm.
///
/// `d` should be initialized to a large value at the unknown nodes.
///
/// `inv_dual_norm(d, [d1, d2, d3], [s1, s2, s3]) -> t` needs to solve the "inverse problem" for the norm:
/// Given values `d_i` at points `-s_i e_i`, find the largest value `t ≤ d` at the origin such that
/// `||p|| ≤ 1`, where `p_i = (s_i (t - d_i))_+` and `||p||` is the __dual__ anisotropic norm.
pub fn fast_sweep_3d<F>(d: &mut [f64], dim: (usize, usize, usize), mut inv_dual_norm: F)
where
    F: FnMut(f64, [f64; 3], [f64; 3]) -> f64,
{
    let (nx, ny, nz) = dim;
    assert_eq!(nx * ny * nz, d.len());
    let (sx, sy, _sz) = (ny * nz, nz, 1);
    // see fast_sweep_2d for discussion
    for p in 1..nx {
        for dir in 0..2 {
            let (di_plane, djk, isign) = if dir == 0 {
                let (low, high) = d.split_at_mut(p * sx);
                (&low[(p - 1) * sx..][..sx], &mut high[..sx], 1.)
            } else {
                let i = nx - 1 - p;
                let (low, high) = d.split_at_mut((i + 1) * sx);
                (&high[..sx], &mut low[i * sx..][..sx], -1.)
            };
            for q in 1..ny {
                for dir in 0..2 {
                    let (di, dj, dk, jsign) = if dir == 0 {
                        let j = q;
                        let (low, high) = djk.split_at_mut(j * sy);
                        (
                            &di_plane[j * sy..][..sy],
                            &low[(j - 1) * sy..][..sy],
                            &mut high[..sy],
                            1.,
                        )
                    } else {
                        let j = ny - 1 - q;
                        let (low, high) = djk.split_at_mut((j + 1) * sy);
                        (
                            &di_plane[j * sy..][..sy],
                            &high[..sy],
                            &mut low[j * sy..][..sy],
                            -1.,
                        )
                    };
                    for r in 1..nz {
                        let k = r;
                        dk[k] = inv_dual_norm(dk[k], [di[k], dj[k], dk[k - 1]], [isign, jsign, 1.]);
                        let k = nz - 1 - r;
                        dk[k] =
                            inv_dual_norm(dk[k], [di[k], dj[k], dk[k + 1]], [isign, jsign, -1.]);
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>
#[derive(Debug)]
#[derive(Clone)]
#[derive(PartialEq)]
pub enum AddOp {
  Add,
  Subtract,
}

#[derive(Debug)]
#[derive(Clone)]
#[derive(PartialEq)]
pub enum MultOp {
  Multiply,
  Divide,
  Modulo,
}

#[derive(Clone)]
#[derive(Debug)]
#[derive(PartialEq)]
pub struct AddTerm(pub AddOp, pub Expr);

#[derive(Clone)]
#[derive(Debug)]
#[derive(PartialEq)]
pub struct MultTerm(pub MultOp, pub Expr);

#[derive(Debug)]
#[derive(Clone)]
#[derive(PartialEq)]
pub enum Expr {
  Variable(String),
  Num(i32),
  AddSub(Vec<AddTerm>), //a + b - c + d becomes [(+ a) (+ b) (- c) (+ d)]
  MultDiv(Vec<MultTerm>),
}

//for now this is it's own type and not a statement
#[derive(Debug)]
#[derive(Clone)]
#[derive(PartialEq)]
pub struct Block(pub Vec<Statement>);

#[derive(Debug)]
#[derive(Clone)]
#[derive(PartialEq)]
pub enum Statement {
  Assign(String, Expr),
  Output(Expr),
  If(Expr, Comparator, Expr, Block, Option<Block>),
  While(Expr, Comparator, Expr, Block),
}

#[derive(Debug)]
#[derive(Clone)]
#[derive(Eq)]
#[derive(PartialEq)]
pub enum Comparator {
  CEq,  // ==
  CGt,  // >
  CLt,  // <
  CNeq, // !=
  CGeq, // >=
  CLeq, // <=
}

#[derive(Debug)]
#[derive(Eq)]
#[derive(PartialEq)]
#[derive(Clone)]
pub enum Token {
  Equals,
  Ident(String),
  Number(i32),
  PlusSign,
  MinusSign,
  MultSign,
  DivideSign,
  ModuloSign,
  OutputCmd,
  NewLine,
  OpenParen,
  CloseParen,
  OpenBrace,
  CloseBrace,
  IfKeyword,
  ElseKeyword,
  WhileKeyword,
  Cmp(Comparator),
}

<commit_msg>Added grammar for IR code<commit_after>
#[derive(Debug)]
#[derive(Clone)]
#[derive(PartialEq)]
pub enum AddOp {
  Add,
  Subtract,
}

#[derive(Debug)]
#[derive(Clone)]
#[derive(PartialEq)]
pub enum MultOp {
  Multiply,
  Divide,
  Modulo,
}

#[derive(Clone)]
#[derive(Debug)]
#[derive(PartialEq)]
pub struct AddTerm(pub AddOp, pub Expr);

#[derive(Clone)]
#[derive(Debug)]
#[derive(PartialEq)]
pub struct MultTerm(pub MultOp, pub Expr);

#[derive(Debug)]
#[derive(Clone)]
#[derive(PartialEq)]
pub enum Expr {
  Variable(String),
  Num(i32),
  AddSub(Vec<AddTerm>), //a + b - c + d becomes [(+ a) (+ b) (- c) (+ d)]
  MultDiv(Vec<MultTerm>),
}

//for now this is it's own type and not a statement
#[derive(Debug)]
#[derive(Clone)]
#[derive(PartialEq)]
pub struct Block(pub Vec<Statement>);

#[derive(Debug)]
#[derive(Clone)]
#[derive(PartialEq)]
pub enum Statement {
  Assign(String, Expr),
  Output(Expr),
  If(Expr, Comparator, Expr, Block, Option<Block>),
  While(Expr, Comparator, Expr, Block),
}

#[derive(Debug)]
#[derive(Clone)]
#[derive(Eq)]
#[derive(PartialEq)]
pub enum Comparator {
  CEq,  // ==
  CGt,  // >
  CLt,  // <
  CNeq, // !=
  CGeq, // >=
  CLeq, // <=
}

#[derive(Debug)]
#[derive(Eq)]
#[derive(PartialEq)]
#[derive(Clone)]
pub enum Token {
  Equals,
  Ident(String),
  Number(i32),
  PlusSign,
  MinusSign,
  MultSign,
  DivideSign,
  ModuloSign,
  OutputCmd,
  NewLine,
  OpenParen,
  CloseParen,
  OpenBrace,
  CloseBrace,
  IfKeyword,
  ElseKeyword,
  WhileKeyword,
  Cmp(Comparator),
}

#[derive(Debug, Eq, PartialEq, CLone)]
pub enum AsmOp{
    Add(Register, AsmOperand),
    Mov(Register, AsmOperand),
}

#[derive(Debug, Eq, PartialEq, CLone)]
pub enum AsmOperand{
    Register(Register),
    Value(i32),
}

#[derive(Debug, Eq, PartialEq, CLone)]
pub enum Register{
    RAX,
}
<|endoftext|>


<commit_before>use js::value::{Value, VNumber, VInteger, VFunction, VObject, ResultValue};
use js::function::{NativeFunction, NativeFunc};
use js::object::ObjectData;
use collections::treemap::TreeMap;
use rand::random;
use std::io::stdio;
use std::f64;
use std::gc::Gc;
use std::cell::RefCell;

/// Get the absolute value of a number
pub fn abs(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().abs()
	} else {
		f64::NAN
	})))
}
/// Get the arccos of a number
pub fn acos(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().acos()
	} else {
		f64::NAN
	})))
}
/// Get the arcsine of a number
pub fn asin(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().asin()
	} else {
		f64::NAN
	})))
}
/// Get the arctangent of a number
pub fn atan(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().atan()
	} else {
		f64::NAN
	})))
}
/// Get the arctangent of a numbers
pub fn atan2(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().atan2(&args.get(1).borrow().to_num())
	} else {
		f64::NAN
	})))
}
/// Get the cubic root of a number
pub fn cbrt(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().cbrt()
	} else {
		f64::NAN
	})))
}
/// Get lowest integer above a number
pub fn ceil(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().ceil()
	} else {
		f64::NAN
	})))
}
/// Get the cosine of a number
pub fn cos(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().cos()
	} else {
		f64::NAN
	})))
}
/// Get the power to raise the natural logarithm to get the number
pub fn exp(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().exp()
	} else {
		f64::NAN
	})))
}
/// Get the highest integer below a number
pub fn floor(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().floor()
	} else {
		f64::NAN
	})))
}
/// Get the natural logarithm of a number
pub fn log(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().log(&f64::consts::E)
	} else {
		f64::NAN
	})))
}
/// Get the maximum of several numbers
pub fn max(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let mut max = f64::NEG_INFINITY;
	for arg in args.iter() {
		let num = arg.borrow().to_num();
		max = max.max(num);
	}
	Ok(Gc::new(VNumber(max)))
}
/// Get the minimum of several numbers
pub fn min(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let mut max = f64::INFINITY;
	for arg in args.iter() {
		let num = arg.borrow().to_num();
		max = max.min(num);
	}
	Ok(Gc::new(VNumber(max)))
}
/// Raise a number to a power
pub fn pow(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 2 {
		let num = args.get(0);
		let power = args.get(1);
		num.borrow().to_num().powf(&power.borrow().to_num())
	} else {
		f64::NAN
	})))
}
/// Generate a random floating-point number between 0 and 1
pub fn _random(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(random())))
}
/// Get the sine of a number
pub fn sin(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().sin()
	} else {
		f64::NAN
	})))
}
/// Get the tangent of a number
pub fn tan(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().tan()
	} else {
		f64::NAN
	})))
}
/// Create a new 'Math' object
pub fn _create() -> Value {
	let mut math = TreeMap::new();
	math.insert(~"E", Gc::new(VNumber(f64::consts::E)));
	math.insert(~"LN2", Gc::new(VNumber(f64::consts::LN_2)));
	math.insert(~"LN10", Gc::new(VNumber(f64::consts::LN_10)));
	math.insert(~"LOG2E", Gc::new(VNumber(f64::consts::LOG2_E)));
	math.insert(~"LOG10E", Gc::new(VNumber(f64::consts::LOG10_E)));
	math.insert(~"SQRT1_2", Gc::new(VNumber(0.5f64.sqrt())));
	math.insert(~"SQRT2", Gc::new(VNumber(f64::consts::SQRT2)));
	math.insert(~"PI", Gc::new(VNumber(f64::consts::PI)));
	math.insert(~"abs", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(abs, 1))))));
	math.insert(~"acos", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(acos, 1))))));
	math.insert(~"asin", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(asin, 1))))));
	math.insert(~"atan", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(atan, 1))))));
	math.insert(~"atan2", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(atan2, 2))))));
	math.insert(~"cbrt", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(cbrt, 1))))));
	math.insert(~"ceil", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(ceil, 1))))));
	math.insert(~"cos", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(cos, 1))))));
	math.insert(~"exp", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(exp, 1))))));
	math.insert(~"floor", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(floor, 1))))));
	math.insert(~"log", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(log, 1))))));
	math.insert(~"max", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(max, 2))))));
	math.insert(~"min", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(min, 2))))));
	math.insert(~"pow", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(pow, 2))))));
	math.insert(~"random", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(_random, 0))))));
	math.insert(~"sin", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(sin, 1))))));
	math.insert(~"tan", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(tan, 1))))));
	Gc::new(VObject(RefCell::new(math)))
}<commit_msg>Add Math.sqrt(num)<commit_after>use js::value::{Value, VNumber, VInteger, VFunction, VObject, ResultValue};
use js::function::{NativeFunction, NativeFunc};
use js::object::ObjectData;
use collections::treemap::TreeMap;
use rand::random;
use std::io::stdio;
use std::f64;
use std::gc::Gc;
use std::cell::RefCell;

/// Get the absolute value of a number
pub fn abs(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().abs()
	} else {
		f64::NAN
	})))
}
/// Get the arccos of a number
pub fn acos(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().acos()
	} else {
		f64::NAN
	})))
}
/// Get the arcsine of a number
pub fn asin(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().asin()
	} else {
		f64::NAN
	})))
}
/// Get the arctangent of a number
pub fn atan(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().atan()
	} else {
		f64::NAN
	})))
}
/// Get the arctangent of a numbers
pub fn atan2(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().atan2(&args.get(1).borrow().to_num())
	} else {
		f64::NAN
	})))
}
/// Get the cubic root of a number
pub fn cbrt(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().cbrt()
	} else {
		f64::NAN
	})))
}
/// Get lowest integer above a number
pub fn ceil(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().ceil()
	} else {
		f64::NAN
	})))
}
/// Get the cosine of a number
pub fn cos(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().cos()
	} else {
		f64::NAN
	})))
}
/// Get the power to raise the natural logarithm to get the number
pub fn exp(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().exp()
	} else {
		f64::NAN
	})))
}
/// Get the highest integer below a number
pub fn floor(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().floor()
	} else {
		f64::NAN
	})))
}
/// Get the natural logarithm of a number
pub fn log(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().log(&f64::consts::E)
	} else {
		f64::NAN
	})))
}
/// Get the maximum of several numbers
pub fn max(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let mut max = f64::NEG_INFINITY;
	for arg in args.iter() {
		let num = arg.borrow().to_num();
		max = max.max(num);
	}
	Ok(Gc::new(VNumber(max)))
}
/// Get the minimum of several numbers
pub fn min(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let mut max = f64::INFINITY;
	for arg in args.iter() {
		let num = arg.borrow().to_num();
		max = max.min(num);
	}
	Ok(Gc::new(VNumber(max)))
}
/// Raise a number to a power
pub fn pow(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 2 {
		let num = args.get(0);
		let power = args.get(1);
		num.borrow().to_num().powf(&power.borrow().to_num())
	} else {
		f64::NAN
	})))
}
/// Generate a random floating-point number between 0 and 1
pub fn _random(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(random())))
}
/// Get the sine of a number
pub fn sin(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().sin()
	} else {
		f64::NAN
	})))
}
/// Get the square root of a number
pub fn sqrt(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().sqrt()
	} else {
		f64::NAN
	})))
}
/// Get the tangent of a number
pub fn tan(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VNumber(if args.len() >= 1 {
		args.get(0).borrow().to_num().tan()
	} else {
		f64::NAN
	})))
}
/// Create a new 'Math' object
pub fn _create() -> Value {
	let mut math = TreeMap::new();
	math.insert(~"E", Gc::new(VNumber(f64::consts::E)));
	math.insert(~"LN2", Gc::new(VNumber(f64::consts::LN_2)));
	math.insert(~"LN10", Gc::new(VNumber(f64::consts::LN_10)));
	math.insert(~"LOG2E", Gc::new(VNumber(f64::consts::LOG2_E)));
	math.insert(~"LOG10E", Gc::new(VNumber(f64::consts::LOG10_E)));
	math.insert(~"SQRT1_2", Gc::new(VNumber(0.5f64.sqrt())));
	math.insert(~"SQRT2", Gc::new(VNumber(f64::consts::SQRT2)));
	math.insert(~"PI", Gc::new(VNumber(f64::consts::PI)));
	math.insert(~"abs", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(abs, 1))))));
	math.insert(~"acos", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(acos, 1))))));
	math.insert(~"asin", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(asin, 1))))));
	math.insert(~"atan", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(atan, 1))))));
	math.insert(~"atan2", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(atan2, 2))))));
	math.insert(~"cbrt", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(cbrt, 1))))));
	math.insert(~"ceil", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(ceil, 1))))));
	math.insert(~"cos", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(cos, 1))))));
	math.insert(~"exp", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(exp, 1))))));
	math.insert(~"floor", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(floor, 1))))));
	math.insert(~"log", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(log, 1))))));
	math.insert(~"max", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(max, 2))))));
	math.insert(~"min", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(min, 2))))));
	math.insert(~"pow", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(pow, 2))))));
	math.insert(~"random", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(_random, 0))))));
	math.insert(~"sin", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(sin, 1))))));
	math.insert(~"sqrt", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(sqrt, 1))))));
	math.insert(~"tan", Gc::new(VFunction(RefCell::new(NativeFunc(NativeFunction::new(tan, 1))))));
	Gc::new(VObject(RefCell::new(math)))
}<|endoftext|>