<commit_before>/*
Copyright 2014 Benjamin Elder from https://github.com/BenTheElder/slack-rs

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.
*/
extern crate hyper;
extern crate websocket;
extern crate "rustc-serialize" as rustc_serialize;
extern crate url;

use rustc_serialize::json::{Json};
use std::sync::mpsc::{Sender,channel};
use std::thread::Thread;
use std::sync::atomic::{AtomicIsize, Ordering};
use websocket::message::WebSocketMessage;
use websocket::handshake::WebSocketRequest;
use url::Url;

///Implement this trait in your code to handle message events
pub trait MessageHandler {
	///When a message is received this will be called with self, the slack client,
	///and the json encoded string payload.
	fn on_receive(&mut self, cli: &mut RtmClient, json_str: &str);

	///Called when a ping is received; you do NOT need to handle the reply pong,
	///but you may use this event to track the connection as a keep-alive.
	fn on_ping(&mut self, cli: &mut RtmClient);

	///Called when the connection is closed for any reason.
	fn on_close(&mut self, cli: &mut RtmClient);
}

///Contains information about the team the bot is logged into.
pub struct Team {
	name : String,
	id : String
}

impl Team {
	///private, create empty team.
	fn new() -> Team {
		Team{name: String::new(), id: String::new()}
	}

	///Returns the team's name as a String
	pub fn get_name(&self) -> String {
		self.name.clone()
	}

	///Returns the team's id as a String
	pub fn get_id(&self) -> String {
		self.id.clone()
	}
}

///The actual messaging client.
pub struct RtmClient {
	name : String,
	id : String,
	team : Team,
	msg_num: AtomicIsize,
	outs : Option<Sender<String>>
}

///Error string. (FIXME: better error return values/ custom error type)
static RTM_INVALID : &'static str = "Invalid data returned from slack (rtm.start)";

impl RtmClient {

	///Creates a new empty client.
	pub fn new() -> RtmClient {
		RtmClient{
			name : String::new(),
			id : String::new(),
			team : Team::new(),
			msg_num: AtomicIsize::new(0),
			outs : None
		}
	}

	///Returns the name of the bot/user connected to the client.
	///Only valid after login.
	pub fn get_name(&self) -> String {
		return self.name.clone();
	}

	///Returns the id of the bot/user connected to the client.
	///Only valid after login.
	pub fn get_id(&self) -> String {
		return self.id.clone();
	}

	///Returns the Team struct of the bot/user connected to the client.
	///Only valid after login.
	pub fn get_team<'a>(&'a self) -> &'a Team {
		&self.team
	}

	///Returns a unique identifier to be used in the 'id' field of a message
	///sent to slack.
	pub fn get_msg_uid(&self) -> isize {
		self.msg_num.fetch_add(1, Ordering::SeqCst)
	}

	///Allows sending a json string message over the websocket connection.
	///Note that this only passes the message over a channel to the
	///Messaging task, and therfore a succesful return value does not
	///mean the message has been actually put on the wire yet.
	///Note that you will need to form a valid json reply yourself if you
	///use this method, and you will also need to retrieve a unique id for
	///the message via RtmClient.get_msg_uid()
	///Only valid after login.
	pub fn send(&mut self, s : &str) -> Result<(),String> {
		let tx = match self.outs {
			Some(ref tx) => tx,
			None => return Err("Failed to get tx!".to_string())
		};
		match tx.send(s.to_string()) {
			Ok(_) => {},
			Err(err) => return Err(format!("{:?}", err))
		}
		Ok(())
	}

	///Allows sending a textual string message over the websocket connection,
	///to the requested channel id. Ideal usage would be EG:
	///extract the channel in on_receive and then send back a message to the channel.
	///Note that this only passes the message over a channel to the
	///Messaging task, and therfore a succesful return value does not
	///mean the message has been actually put on the wire yet.
	///This method also handles getting a unique id and formatting the actual json
	///sent.
	///Only valid after login.
	pub fn send_message(&self, chan: &str, msg: &str) -> Result<(),String>{
		let n = self.get_msg_uid();
		let mstr = "{".to_string()+format!(r#""id": {},"type": "message","channel": "{}","text": "{}""#,n,chan,msg).as_slice()+"}";
		let tx = match self.outs {
			Some(ref tx) => tx,
			None => return Err("Failed to get tx!".to_string())
		};
		match tx.send(mstr) {
			Ok(_) => {},
			Err(err) => return Err(format!("{:?}", err))
		}
		Ok(())
	}

	///Runs the main loop for the client after logging in to slack,
	///returns an error if the process fails at an point, or an Ok(()) on succesful
	///close.
	///Takes a MessageHandler (implemented by the user) to call events handlers on.
	///once the first on_receive() or on_ping is called on the MessageHandler, you
	///can soon the 'Only valid after login' methods are safe to use.
	///Sending is run in a thread in parallel while the receive loop runs on the main thread.
	///Both loops should end on return.
	///Sending should be thread safe as the messages are passed in via a channel in
	///RtmClient.send and RtmClient.send_message
	pub fn login_and_run<T: MessageHandler>(&mut self, handler: &mut T, token : &str) -> Result<(),String> {
		//Slack real time api url
		let url = "https://slack.com/api/rtm.start?token=".to_string()+token;

		//Create http client and send request to slack
		let mut client = hyper::Client::new();
		let mut res = match client.get(url.as_slice()).send() {
			Ok(res) => res,
			Err(err) => return Err(format!("Hyper Error: {:?}", err))
		};

		//Read result string
		let res_str = match res.read_to_string() {
			Ok(res_str) => res_str,
			Err(err) => return Err(format!("{:?}", err))
		};

		//Start parsing json. We do not map to a structure,
		//because slack makes no guarantee that there won't be extra fields.
		let js = match Json::from_str(res_str.as_slice()) {
			Ok(js) => js,
			Err(err) => return Err(format!("{:?}", err))
		};

		if !js.is_object() {
			return Err(RTM_INVALID.to_string())
		}
		let jo = js.as_object().unwrap();

		match jo.get("ok") {
			Some(v) => {
				if !(v.is_boolean() && v.as_boolean().unwrap() == true) {
					return Err(RTM_INVALID.to_string())
				}
			},
			None => return Err(RTM_INVALID.to_string())
		}

		let wss_url_string = match jo.get("url") {
			Some(wss_url) => {
				if wss_url.is_string() {
					wss_url.as_string().unwrap()
				}else{
					return Err(RTM_INVALID.to_string())
				}
			},
			None => return Err(RTM_INVALID.to_string())
		};

		let wss_url = match Url::parse(wss_url_string) {
			Ok(url) => url,
			Err(err) => return Err(format!("{:?}", err))
		};

		let jself = match jo.get("self") {
			Some(jself) => {
				if jself.is_object() {
					jself.as_object().unwrap()
				}else{
					return Err(RTM_INVALID.to_string())
				}
			},
			None => return Err(RTM_INVALID.to_string())
		};
		match jself.get("name") {
			Some(jname) => {
				if jname.is_string() {
					self.name = jname.as_string().unwrap().to_string();
				}else{
					return Err(RTM_INVALID.to_string())
				}
			},
			None => return Err(RTM_INVALID.to_string())
		}
		match jself.get("id") {
			Some(jid) => {
				if jid.is_string() {
					self.id = jid.as_string().unwrap().to_string();
				}else{
					return Err(RTM_INVALID.to_string())
				}
			},
			None => return Err(RTM_INVALID.to_string())
		}

		let jteam = match jo.get("team") {
			Some(jteam) => {
				if jteam.is_object() {
					jteam.as_object().unwrap()
				}else{
					return Err(RTM_INVALID.to_string())
				}
			},
			None => return Err(RTM_INVALID.to_string())
		};
		match jteam.get("name") {
			Some(jtname) => {
				if jtname.is_string() {
					self.team.name = jtname.as_string().unwrap().to_string();
				}else{
					return Err(RTM_INVALID.to_string())
				}
			}
			None => return Err(RTM_INVALID.to_string())
		}
		match jteam.get("id") {
			Some(jtid) => {
				if jtid.is_string() {
					self.team.id = jtid.as_string().unwrap().to_string();
				}else{
					return Err(RTM_INVALID.to_string())
				}
			}
			None => return Err(RTM_INVALID.to_string())
		}

		//Make websocket request
		let req = match WebSocketRequest::connect(wss_url) {
			Ok(req) => req,
			Err(err) => return Err(format!("{:?}", err))
		};

		//Get the key so we can verify it later.
		let key = match req.key() {
			Some(key) => key.clone(),
			None => return Err("Request host key match failed.".to_string())
		};

		//Connect via tls, do websocket handshake.
		let res = match req.send() {
			Ok(res) => res,
			Err(err) => return Err(format!("{:?}", err))
		};

		match res.validate(&key) {
			Ok(()) => { }
			Err(err) => return Err(format!("{:?}", err))
		}

		let mut client = res.begin();

		//for sending messages
		let (tx,rx) = channel::<String>();
		self.outs = Some(tx);

		let mut captured_client = client.clone();

		//websocket send loop
		let guard = Thread::spawn(move || -> () {
			loop {
				let m = match rx.recv() {
					Ok(m) => m,
					Err(err) => panic!(format!("{:?}", err))
				};
			 	let msg = WebSocketMessage::Text(m);
			 	match captured_client.send_message(msg) {
			 		Ok(_) => {},
			 		Err(err) => panic!(format!("{:?}", err))
			 	}
			 }
		});

		let mut sending_client = client.clone();

		//receive loop
		for message in client.incoming_messages() {
			let message = match message {
				Ok(message) => message,
				Err(err) => return Err(format!("{:?}", err))
			};

			match message {
				WebSocketMessage::Text(data) => {
					handler.on_receive(self, data.as_slice());
				},
				WebSocketMessage::Ping(data) => {
					handler.on_ping(self);
					let message = WebSocketMessage::Pong(data);
					match sending_client.send_message(message) {
						Ok(_) => {},
						Err(err) => { return Err(format!("{:?}", err)); }
					}
				},
				WebSocketMessage::Close(data) => {
					handler.on_close(self);
					let message = WebSocketMessage::Close(data);
					match sending_client.send_message(message) {
						Ok(_) => {},
						Err(err) => { return Err(format!("{:?}", err)); }
					}
					return Ok(());
				},
				_ => {}
			}
		}

		Ok(())
	}
}
<commit_msg>error debug info<commit_after>/*
Copyright 2014 Benjamin Elder from https://github.com/BenTheElder/slack-rs

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.
*/
extern crate hyper;
extern crate websocket;
extern crate "rustc-serialize" as rustc_serialize;
extern crate url;

use rustc_serialize::json::{Json};
use std::sync::mpsc::{Sender,channel};
use std::thread::Thread;
use std::sync::atomic::{AtomicIsize, Ordering};
use websocket::message::WebSocketMessage;
use websocket::handshake::WebSocketRequest;
use url::Url;

///Implement this trait in your code to handle message events
pub trait MessageHandler {
	///When a message is received this will be called with self, the slack client,
	///and the json encoded string payload.
	fn on_receive(&mut self, cli: &mut RtmClient, json_str: &str);

	///Called when a ping is received; you do NOT need to handle the reply pong,
	///but you may use this event to track the connection as a keep-alive.
	fn on_ping(&mut self, cli: &mut RtmClient);

	///Called when the connection is closed for any reason.
	fn on_close(&mut self, cli: &mut RtmClient);
}

///Contains information about the team the bot is logged into.
pub struct Team {
	name : String,
	id : String
}

impl Team {
	///private, create empty team.
	fn new() -> Team {
		Team{name: String::new(), id: String::new()}
	}

	///Returns the team's name as a String
	pub fn get_name(&self) -> String {
		self.name.clone()
	}

	///Returns the team's id as a String
	pub fn get_id(&self) -> String {
		self.id.clone()
	}
}

///The actual messaging client.
pub struct RtmClient {
	name : String,
	id : String,
	team : Team,
	msg_num: AtomicIsize,
	outs : Option<Sender<String>>
}

///Error string. (FIXME: better error return values/ custom error type)
static RTM_INVALID : &'static str = "Invalid data returned from slack (rtm.start)";

impl RtmClient {

	///Creates a new empty client.
	pub fn new() -> RtmClient {
		RtmClient{
			name : String::new(),
			id : String::new(),
			team : Team::new(),
			msg_num: AtomicIsize::new(0),
			outs : None
		}
	}

	///Returns the name of the bot/user connected to the client.
	///Only valid after login.
	pub fn get_name(&self) -> String {
		return self.name.clone();
	}

	///Returns the id of the bot/user connected to the client.
	///Only valid after login.
	pub fn get_id(&self) -> String {
		return self.id.clone();
	}

	///Returns the Team struct of the bot/user connected to the client.
	///Only valid after login.
	pub fn get_team<'a>(&'a self) -> &'a Team {
		&self.team
	}

	///Returns a unique identifier to be used in the 'id' field of a message
	///sent to slack.
	pub fn get_msg_uid(&self) -> isize {
		self.msg_num.fetch_add(1, Ordering::SeqCst)
	}

	///Allows sending a json string message over the websocket connection.
	///Note that this only passes the message over a channel to the
	///Messaging task, and therfore a succesful return value does not
	///mean the message has been actually put on the wire yet.
	///Note that you will need to form a valid json reply yourself if you
	///use this method, and you will also need to retrieve a unique id for
	///the message via RtmClient.get_msg_uid()
	///Only valid after login.
	pub fn send(&mut self, s : &str) -> Result<(),String> {
		let tx = match self.outs {
			Some(ref tx) => tx,
			None => return Err("Failed to get tx!".to_string())
		};
		match tx.send(s.to_string()) {
			Ok(_) => {},
			Err(err) => return Err(format!("{:?}", err))
		}
		Ok(())
	}

	///Allows sending a textual string message over the websocket connection,
	///to the requested channel id. Ideal usage would be EG:
	///extract the channel in on_receive and then send back a message to the channel.
	///Note that this only passes the message over a channel to the
	///Messaging task, and therfore a succesful return value does not
	///mean the message has been actually put on the wire yet.
	///This method also handles getting a unique id and formatting the actual json
	///sent.
	///Only valid after login.
	pub fn send_message(&self, chan: &str, msg: &str) -> Result<(),String>{
		let n = self.get_msg_uid();
		let mstr = "{".to_string()+format!(r#""id": {},"type": "message","channel": "{}","text": "{}""#,n,chan,msg).as_slice()+"}";
		let tx = match self.outs {
			Some(ref tx) => tx,
			None => return Err("Failed to get tx!".to_string())
		};
		match tx.send(mstr) {
			Ok(_) => {},
			Err(err) => return Err(format!("{:?}", err))
		}
		Ok(())
	}

	///Runs the main loop for the client after logging in to slack,
	///returns an error if the process fails at an point, or an Ok(()) on succesful
	///close.
	///Takes a MessageHandler (implemented by the user) to call events handlers on.
	///once the first on_receive() or on_ping is called on the MessageHandler, you
	///can soon the 'Only valid after login' methods are safe to use.
	///Sending is run in a thread in parallel while the receive loop runs on the main thread.
	///Both loops should end on return.
	///Sending should be thread safe as the messages are passed in via a channel in
	///RtmClient.send and RtmClient.send_message
	pub fn login_and_run<T: MessageHandler>(&mut self, handler: &mut T, token : &str) -> Result<(),String> {
		//Slack real time api url
		let url = "https://slack.com/api/rtm.start?token=".to_string()+token;

		//Create http client and send request to slack
		let mut client = hyper::Client::new();
		let mut res = match client.get(url.as_slice()).send() {
			Ok(res) => res,
			Err(err) => return Err(format!("Hyper Error: {:?}", err))
		};

		//Read result string
		let res_str = match res.read_to_string() {
			Ok(res_str) => res_str,
			Err(err) => return Err(format!("{:?}", err))
		};

		//Start parsing json. We do not map to a structure,
		//because slack makes no guarantee that there won't be extra fields.
		let js = match Json::from_str(res_str.as_slice()) {
			Ok(js) => js,
			Err(err) => return Err(format!("{:?}", err))
		};

		if !js.is_object() {
			return Err(format!("{} : json is not an object.", RTM_INVALID))
		}
		let jo = js.as_object().unwrap();

		match jo.get("ok") {
			Some(v) => {
				if !(v.is_boolean() && v.as_boolean().unwrap() == true) {
					return Err(format!("{} : js.get(\"ok\") != true : {:?}", RTM_INVALID, jo))
				}
			},
			None => return Err(format!("{} : jo.get(\"ok\") returned None. : {:?}", RTM_INVALID, jo))
		}

		let wss_url_string = match jo.get("url") {
			Some(wss_url) => {
				if wss_url.is_string() {
					wss_url.as_string().unwrap()
				}else{
					return Err(format!("{} : jo.get(\"url\") failed! : {:?}", RTM_INVALID, jo))
				}
			},
			None => return Err(format!("{} : jo.get(\"url\") returned None. : {:?}", RTM_INVALID, jo))
		};

		let wss_url = match Url::parse(wss_url_string) {
			Ok(url) => url,
			Err(err) => return Err(format!("{:?}", err))
		};

		let jself = match jo.get("self") {
			Some(jself) => {
				if jself.is_object() {
					jself.as_object().unwrap()
				}else{
					return Err(RTM_INVALID.to_string())
				}
			},
			None => return Err(RTM_INVALID.to_string())
		};
		match jself.get("name") {
			Some(jname) => {
				if jname.is_string() {
					self.name = jname.as_string().unwrap().to_string();
				}else{
					return Err(RTM_INVALID.to_string())
				}
			},
			None => return Err(RTM_INVALID.to_string())
		}
		match jself.get("id") {
			Some(jid) => {
				if jid.is_string() {
					self.id = jid.as_string().unwrap().to_string();
				}else{
					return Err(RTM_INVALID.to_string())
				}
			},
			None => return Err(RTM_INVALID.to_string())
		}

		let jteam = match jo.get("team") {
			Some(jteam) => {
				if jteam.is_object() {
					jteam.as_object().unwrap()
				}else{
					return Err(RTM_INVALID.to_string())
				}
			},
			None => return Err(RTM_INVALID.to_string())
		};
		match jteam.get("name") {
			Some(jtname) => {
				if jtname.is_string() {
					self.team.name = jtname.as_string().unwrap().to_string();
				}else{
					return Err(RTM_INVALID.to_string())
				}
			}
			None => return Err(RTM_INVALID.to_string())
		}
		match jteam.get("id") {
			Some(jtid) => {
				if jtid.is_string() {
					self.team.id = jtid.as_string().unwrap().to_string();
				}else{
					return Err(RTM_INVALID.to_string())
				}
			}
			None => return Err(RTM_INVALID.to_string())
		}

		//Make websocket request
		let req = match WebSocketRequest::connect(wss_url) {
			Ok(req) => req,
			Err(err) => return Err(format!("{:?}", err))
		};

		//Get the key so we can verify it later.
		let key = match req.key() {
			Some(key) => key.clone(),
			None => return Err("Request host key match failed.".to_string())
		};

		//Connect via tls, do websocket handshake.
		let res = match req.send() {
			Ok(res) => res,
			Err(err) => return Err(format!("{:?}", err))
		};

		match res.validate(&key) {
			Ok(()) => { }
			Err(err) => return Err(format!("{:?}", err))
		}

		let mut client = res.begin();

		//for sending messages
		let (tx,rx) = channel::<String>();
		self.outs = Some(tx);

		let mut captured_client = client.clone();

		//websocket send loop
		let guard = Thread::spawn(move || -> () {
			loop {
				let m = match rx.recv() {
					Ok(m) => m,
					Err(err) => panic!(format!("{:?}", err))
				};
			 	let msg = WebSocketMessage::Text(m);
			 	match captured_client.send_message(msg) {
			 		Ok(_) => {},
			 		Err(err) => panic!(format!("{:?}", err))
			 	}
			 }
		});

		let mut sending_client = client.clone();

		//receive loop
		for message in client.incoming_messages() {
			let message = match message {
				Ok(message) => message,
				Err(err) => return Err(format!("{:?}", err))
			};

			match message {
				WebSocketMessage::Text(data) => {
					handler.on_receive(self, data.as_slice());
				},
				WebSocketMessage::Ping(data) => {
					handler.on_ping(self);
					let message = WebSocketMessage::Pong(data);
					match sending_client.send_message(message) {
						Ok(_) => {},
						Err(err) => { return Err(format!("{:?}", err)); }
					}
				},
				WebSocketMessage::Close(data) => {
					handler.on_close(self);
					let message = WebSocketMessage::Close(data);
					match sending_client.send_message(message) {
						Ok(_) => {},
						Err(err) => { return Err(format!("{:?}", err)); }
					}
					return Ok(());
				},
				_ => {}
			}
		}

		Ok(())
	}
}
<|endoftext|>


<commit_before>mod key;
mod rangeset;

use key::Key;
use rangeset::{Range, RangeSet};
use std::collections::HashMap;

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
struct VKeyMarker;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
struct EKeyMarker;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
struct FKeyMarker;
pub type VKey = Key<VKeyMarker>;
pub type EKey = Key<EKeyMarker>;
pub type FKey = Key<FKeyMarker>;
pub type FaceLen = u32;

/// Editable mesh with persistent adjacency data. Modeled loosely
/// after Blender's BMesh:
///
/// http://wiki.blender.org/index.php/Dev:2.6/Source/Modeling/BMesh/Design
pub struct Mesh<VData, EData, FData> {
    verts: HashMap<VKey, Vert<VData>>,
    edges: HashMap<EKey, Edge<EData>>,
    faces: HashMap<FKey, Face<FData>>,

    vert_range_set: RangeSet,
    edge_range_set: RangeSet,
    face_range_set: RangeSet
}

// TODO
fn new_key_range_set() -> RangeSet {
    RangeSet::new(Range::new(0, 0xffffffff - 1))
}

impl<VData: Clone, EData: Clone, FData: Clone> Mesh<VData, EData, FData> {
    pub fn new() -> Mesh<VData, EData, FData> {
        Mesh {
            verts: HashMap::new(),
            edges: HashMap::new(),
            faces: HashMap::new(),

            vert_range_set: new_key_range_set(),
            edge_range_set: new_key_range_set(),
            face_range_set: new_key_range_set()
        }
    }

    pub fn get_vert(&self, vk: VKey) -> Option<&Vert<VData>> {
        self.verts.get(&vk)
    }

    pub fn get_edge(&self, ek: EKey) -> Option<&Edge<EData>> {
        self.edges.get(&ek)
    }

    pub fn get_face(&self, fk: FKey) -> Option<&Face<FData>> {
        self.faces.get(&fk)
    }

    pub fn get_vert_data(&mut self, vk: VKey) -> Option<&mut Vert<VData>> {
        self.verts.get_mut(&vk)
    }

    pub fn get_edge_data(&mut self, ek: EKey) -> Option<&mut Edge<EData>> {
        self.edges.get_mut(&ek)
    }

    pub fn get_face_data(&mut self, fk: FKey) -> Option<&mut Face<FData>> {
        self.faces.get_mut(&fk)
    }

    /// Return the edge between two verts, or None if no such edge
    /// exists.
    pub fn find_edge(&self, vk0: VKey, vk1: VKey) -> Option<EKey> {
        for ek in self.verts[&vk0].edges.iter() {
            if self.edges[ek].is_vert_adjacent(vk1) {
                return Some(*ek)
            }
        }
        None
    }

    /// Get all faces adjacent to the specified vertex. The order is
    /// arbitrary.
    pub fn vert_adjacent_faces(&self, vk: VKey) -> Vec<FKey> {
        let mut adj = Vec::new();
        for ek in self.verts[&vk].edges.iter() {
            for fk in self.edges[ek].faces.iter() {
                if !adj.contains(fk) {
                    adj.push(*fk);
                }
            }
        }
        adj
    }

    /// Get edges that are one face removed from the specified
    /// vertex. The order is arbitrary.
    pub fn vert_edge_ring_soup(&self, vk: VKey) -> Vec<EKey> {
        let mut edges = Vec::new();
        for fk in self.vert_adjacent_faces(vk).iter() {
            for lp in self.faces[fk].get_loops() {
                if !(self.edges[&lp.edge].is_vert_adjacent(vk) ||
                     edges.contains(&lp.edge)) {
                    edges.push(lp.edge);
                }
            }
        }
        edges
    }

    pub fn separate_connected_edges(&self, mut input: Vec<EKey>) -> Vec<Vec<EKey>> {
        let mut groups = Vec::new();

        while !input.is_empty() {
            let mut stack = Vec::new();
            let mut visited = Vec::new();
            let mut group = Vec::new();
            stack.push(self.edges[&input[0]].verts[0]);
            while let Some(vk) = stack.pop() {
                if !visited.contains(&vk) {
                    visited.push(vk);
                    for ek in self.verts[&vk].edges.iter() {
                        if input.contains(ek) {
                            stack.push(self.edges[ek].other_vert(vk).unwrap());
                            group.push(*ek);
                            input.retain(|elem| elem != ek);
                        }
                    }
                }
            }
            groups.push(group);
        }

        groups
    }

    /// Add a new isolated vertex and return its key. Fail and return
    /// None if there are no more vertex keys available.
    pub fn add_vert(&mut self, vdata: VData) -> Option<VKey> {
        if let Some(val) = self.vert_range_set.take_any_one() {
            let vkey = VKey::new(val);
            self.verts.insert(vkey, Vert::new(vdata));
            Some(vkey)
        } else {
            None
        }
    }

    pub fn add_edge(&mut self, vk0: VKey, vk1: VKey, edata: EData) -> Option<EKey> {
        // TODO(nicholasbishop): check that the verts are in the mesh,
        if vk0 == vk1 {
            None
        } else if let Some(ek) = self.find_edge(vk0, vk1) {
            Some(ek)
        } else {
            if let Some(val) = self.edge_range_set.take_any_one() {
                let ekey = EKey::new(val);
                self.verts.get_mut(&vk0).unwrap().push_edge(ekey);
                self.verts.get_mut(&vk1).unwrap().push_edge(ekey);
                self.edges.insert(ekey, Edge::new(vk0, vk1, edata));
                Some(ekey)
            } else {
                None
            }
        }
    }

    pub fn add_face(&mut self, vk: &[VKey], edata: EData, fdata: FData) -> Option<FKey> {
        let mut loops = Vec::with_capacity(vk.len());
        for i in 0..vk.len() {
            let vk0 = vk[i];
            let vk1 = vk[if i < (vk.len() - 1) { i + 1 } else { 0 }];
            // TODO(nicholasbishop): do more checking up front so that
            // edges don't get created on failure, or delete them after.
            if let Some(ek) = self.add_edge(vk0, vk1, edata.clone()) {
                loops.push(Loop { vert: vk0, edge: ek });
            } else {
                // Error: failed to create edge
                return None;
            }
        }
        if let Some(val) = self.face_range_set.take_any_one() {
            let fk = FKey::new(val);
            for lp in loops.iter() {
                self.edges.get_mut(&lp.edge).unwrap().push_face(fk);
            }
            self.faces.insert(fk, Face::new(loops, fdata));
            Some(fk)
        } else {
            None
        }
    }

    pub fn delete_face(&mut self, fk: FKey) {
        self.faces.remove(&fk);
        self.face_range_set.release_one(fk.value());
    }
}

pub struct Vert<VData> {
    pub vdata: VData,
    edges: Vec<EKey>
}

impl<VData> Vert<VData> {
    fn new(vdata: VData) -> Vert<VData> {
        Vert { vdata: vdata, edges: Vec::new() }
    }

    /// Check if the edge is in the set of edges adjacent to this vert.
    pub fn is_edge_adjacent(&self, ek: EKey) -> bool {
        self.edges.contains(&ek)
    }

    pub fn get_edges(&self) -> &Vec<EKey> {
        &self.edges
    }

    /// Add edge to set of edges adjacent to the vert. Does nothing if
    /// the edge is already in the set.
    fn push_edge(&mut self, ek: EKey) {
        if !self.is_edge_adjacent(ek) {
            self.edges.push(ek);
        }
    }
}

pub struct Edge<EData> {
    pub edata: EData,
    verts: [VKey; 2],
    faces: Vec<FKey>
}

impl<EData> Edge<EData> {
    fn new(vk0: VKey, vk1: VKey, edata: EData) -> Edge<EData> {
        Edge { edata: edata, verts: [vk0, vk1], faces: Vec::new() }
    }

    /// Check if the vert is one of the two verts adjacent to this edge.
    fn is_vert_adjacent(&self, vk: VKey) -> bool {
        self.verts.contains(&vk)
    }

    /// Check if the face is in the set of edges adjacent to this edge.
    pub fn is_face_adjacent(&self, fk: FKey) -> bool {
        self.faces.contains(&fk)
    }

    pub fn get_verts(&self) -> &[VKey; 2] {
        &self.verts
    }

    pub fn get_faces(&self) -> &Vec<FKey> {
        &self.faces
    }

    /// Given one of the edge's verts, return the other one. If the
    /// input is not one if the edge's verts, return None.
    pub fn other_vert(&self, vk: VKey) -> Option<VKey> {
        if vk == self.verts[0] {
            Some(self.verts[1])
        } else if vk == self.verts[1] {
            Some(self.verts[0])
        } else {
            None
        }
    }

    /// Add face to set of faces adjacent to the edge. Does nothing if
    /// the face is already in the set.
    fn push_face(&mut self, fk: FKey) {
        if !self.is_face_adjacent(fk) {
            self.faces.push(fk);
        }
    }
}

pub struct Loop {
    pub vert: VKey,
    pub edge: EKey
}

pub struct Face<FData> {
    pub fdata: FData,
    loops: Vec<Loop>
}

impl<FData> Face<FData> {
    fn new(loops: Vec<Loop>, fdata: FData) -> Face<FData> {
        Face { fdata: fdata, loops: loops }
    }

    pub fn get_loops(&self) -> &Vec<Loop> {
        &self.loops
    }
}

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

    // Placeholder for vert/edge/face data
    const DAT: () = ();

    #[test]
    fn test_add_vert() {
        let mut mesh = Mesh::<_, (), ()>::new();
        assert!(mesh.add_vert(DAT).is_some());
        assert!(!mesh.verts.is_empty());
    }

    #[test]
    fn test_add_edge() {
        let mut mesh = Mesh::<_, _, ()>::new();
        let a = mesh.add_vert(DAT).unwrap();
        let b = mesh.add_vert(DAT).unwrap();

        // Add a valid edge
        let e = mesh.add_edge(a, b, DAT).unwrap();
        assert!(mesh.verts[&a].edges.contains(&e));
        assert!(mesh.verts[&b].edges.contains(&e));

        // Edge from a vertex to the same vertex is not allowed
        assert!(mesh.add_edge(a, a, DAT).is_none());

        // Duplicate edge should return the existing edge
        assert_eq!(mesh.add_edge(a, b, DAT).unwrap(), e);
        assert_eq!(mesh.add_edge(b, a, DAT).unwrap(), e);
    }

    #[test]
    fn test_add_face() {
        let mut mesh = Mesh::new();
        let a = mesh.add_vert(DAT).unwrap();
        let b = mesh.add_vert(DAT).unwrap();
        let c = mesh.add_vert(DAT).unwrap();

        // Add a valid triangle
        let fk = mesh.add_face(&[a, b, c], DAT, DAT).unwrap();
        assert_eq!(mesh.edges.len(), 3);
        for lp in mesh.faces[&fk].loops.iter() {
            assert!(mesh.edges[&lp.edge].is_face_adjacent(fk));
        }

        // Add an invalid triangle with invalid edge
        assert!(mesh.add_face(&[a, b, b], DAT, DAT).is_none());
    }

    #[test]
    fn test_vert_adjacent_faces() {
        // Create a bow-tie mesh
        let mut mesh = Mesh::new();
        let middle = mesh.add_vert(DAT).unwrap();
        let l0 = mesh.add_vert(DAT).unwrap();
        let l1 = mesh.add_vert(DAT).unwrap();
        let r0 = mesh.add_vert(DAT).unwrap();
        let r1 = mesh.add_vert(DAT).unwrap();
        let fk0 = mesh.add_face(&[middle, l0, l1], DAT, DAT).unwrap();
        let fk1 = mesh.add_face(&[middle, r0, r1], DAT, DAT).unwrap();

        let adj = mesh.vert_adjacent_faces(middle);
        assert_eq!(adj.len(), 2);
        assert!(adj.contains(&fk0));
        assert!(adj.contains(&fk1));
    }

    #[test]
    fn test_ngon() {
        let mut mesh = Mesh::new();
        let a = mesh.add_vert(DAT).unwrap();
        let b = mesh.add_vert(DAT).unwrap();
        let c = mesh.add_vert(DAT).unwrap();
        let d = mesh.add_vert(DAT).unwrap();
        let e = mesh.add_vert(DAT).unwrap();

        let fk = mesh.add_face(&[a, b, c, d, e], DAT, DAT).unwrap();
        let face = &mesh.faces[&fk];

        assert_eq!(face.loops.len(), 5);
    }

    #[test]
    fn test_separate_connected_edges() {
        let mut mesh = Mesh::<_, _, ()>::new();
        let vk0 = mesh.add_vert(DAT).unwrap();
        let vk1 = mesh.add_vert(DAT).unwrap();
        let ek0 = mesh.add_edge(vk0, vk1, DAT).unwrap();

        let vk2 = mesh.add_vert(DAT).unwrap();
        let vk3 = mesh.add_vert(DAT).unwrap();
        let vk4 = mesh.add_vert(DAT).unwrap();
        let vk5 = mesh.add_vert(DAT).unwrap();
        let ek1 = mesh.add_edge(vk2, vk3, DAT).unwrap();
        let ek2 = mesh.add_edge(vk3, vk4, DAT).unwrap();
        let ek3 = mesh.add_edge(vk3, vk5, DAT).unwrap();

        let ce = mesh.separate_connected_edges(vec![ek0, ek1, ek2, ek3]);
        assert_eq!(ce.len(), 2);
        assert!(ce[0].len() == 1 || ce[1].len() == 1);
        let g0 = if ce[0].len() == 1 { &ce[0] } else { &ce[1] };
        let g1 = if ce[0].len() == 1 { &ce[1] } else { &ce[0] };

        assert_eq!(g0, &[ek0]);
        assert_eq!(g1.len(), 3);
        assert!(g1.contains(&ek1));
        assert!(g1.contains(&ek2));
        assert!(g1.contains(&ek3));
    }
}
<commit_msg>Fix a private in public error<commit_after>mod key;
mod rangeset;

use key::Key;
use rangeset::{Range, RangeSet};
use std::collections::HashMap;

mod detail {
    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
    pub struct VKeyMarker;
    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
    pub struct EKeyMarker;
    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
    pub struct FKeyMarker;
}
pub type VKey = Key<detail::VKeyMarker>;
pub type EKey = Key<detail::EKeyMarker>;
pub type FKey = Key<detail::FKeyMarker>;
pub type FaceLen = u32;

/// Editable mesh with persistent adjacency data. Modeled loosely
/// after Blender's BMesh:
///
/// http://wiki.blender.org/index.php/Dev:2.6/Source/Modeling/BMesh/Design
pub struct Mesh<VData, EData, FData> {
    verts: HashMap<VKey, Vert<VData>>,
    edges: HashMap<EKey, Edge<EData>>,
    faces: HashMap<FKey, Face<FData>>,

    vert_range_set: RangeSet,
    edge_range_set: RangeSet,
    face_range_set: RangeSet
}

// TODO
fn new_key_range_set() -> RangeSet {
    RangeSet::new(Range::new(0, 0xffffffff - 1))
}

impl<VData: Clone, EData: Clone, FData: Clone> Mesh<VData, EData, FData> {
    pub fn new() -> Mesh<VData, EData, FData> {
        Mesh {
            verts: HashMap::new(),
            edges: HashMap::new(),
            faces: HashMap::new(),

            vert_range_set: new_key_range_set(),
            edge_range_set: new_key_range_set(),
            face_range_set: new_key_range_set()
        }
    }

    pub fn get_vert(&self, vk: VKey) -> Option<&Vert<VData>> {
        self.verts.get(&vk)
    }

    pub fn get_edge(&self, ek: EKey) -> Option<&Edge<EData>> {
        self.edges.get(&ek)
    }

    pub fn get_face(&self, fk: FKey) -> Option<&Face<FData>> {
        self.faces.get(&fk)
    }

    pub fn get_vert_data(&mut self, vk: VKey) -> Option<&mut Vert<VData>> {
        self.verts.get_mut(&vk)
    }

    pub fn get_edge_data(&mut self, ek: EKey) -> Option<&mut Edge<EData>> {
        self.edges.get_mut(&ek)
    }

    pub fn get_face_data(&mut self, fk: FKey) -> Option<&mut Face<FData>> {
        self.faces.get_mut(&fk)
    }

    /// Return the edge between two verts, or None if no such edge
    /// exists.
    pub fn find_edge(&self, vk0: VKey, vk1: VKey) -> Option<EKey> {
        for ek in self.verts[&vk0].edges.iter() {
            if self.edges[ek].is_vert_adjacent(vk1) {
                return Some(*ek)
            }
        }
        None
    }

    /// Get all faces adjacent to the specified vertex. The order is
    /// arbitrary.
    pub fn vert_adjacent_faces(&self, vk: VKey) -> Vec<FKey> {
        let mut adj = Vec::new();
        for ek in self.verts[&vk].edges.iter() {
            for fk in self.edges[ek].faces.iter() {
                if !adj.contains(fk) {
                    adj.push(*fk);
                }
            }
        }
        adj
    }

    /// Get edges that are one face removed from the specified
    /// vertex. The order is arbitrary.
    pub fn vert_edge_ring_soup(&self, vk: VKey) -> Vec<EKey> {
        let mut edges = Vec::new();
        for fk in self.vert_adjacent_faces(vk).iter() {
            for lp in self.faces[fk].get_loops() {
                if !(self.edges[&lp.edge].is_vert_adjacent(vk) ||
                     edges.contains(&lp.edge)) {
                    edges.push(lp.edge);
                }
            }
        }
        edges
    }

    pub fn separate_connected_edges(&self, mut input: Vec<EKey>) -> Vec<Vec<EKey>> {
        let mut groups = Vec::new();

        while !input.is_empty() {
            let mut stack = Vec::new();
            let mut visited = Vec::new();
            let mut group = Vec::new();
            stack.push(self.edges[&input[0]].verts[0]);
            while let Some(vk) = stack.pop() {
                if !visited.contains(&vk) {
                    visited.push(vk);
                    for ek in self.verts[&vk].edges.iter() {
                        if input.contains(ek) {
                            stack.push(self.edges[ek].other_vert(vk).unwrap());
                            group.push(*ek);
                            input.retain(|elem| elem != ek);
                        }
                    }
                }
            }
            groups.push(group);
        }

        groups
    }

    /// Add a new isolated vertex and return its key. Fail and return
    /// None if there are no more vertex keys available.
    pub fn add_vert(&mut self, vdata: VData) -> Option<VKey> {
        if let Some(val) = self.vert_range_set.take_any_one() {
            let vkey = VKey::new(val);
            self.verts.insert(vkey, Vert::new(vdata));
            Some(vkey)
        } else {
            None
        }
    }

    pub fn add_edge(&mut self, vk0: VKey, vk1: VKey, edata: EData) -> Option<EKey> {
        // TODO(nicholasbishop): check that the verts are in the mesh,
        if vk0 == vk1 {
            None
        } else if let Some(ek) = self.find_edge(vk0, vk1) {
            Some(ek)
        } else {
            if let Some(val) = self.edge_range_set.take_any_one() {
                let ekey = EKey::new(val);
                self.verts.get_mut(&vk0).unwrap().push_edge(ekey);
                self.verts.get_mut(&vk1).unwrap().push_edge(ekey);
                self.edges.insert(ekey, Edge::new(vk0, vk1, edata));
                Some(ekey)
            } else {
                None
            }
        }
    }

    pub fn add_face(&mut self, vk: &[VKey], edata: EData, fdata: FData) -> Option<FKey> {
        let mut loops = Vec::with_capacity(vk.len());
        for i in 0..vk.len() {
            let vk0 = vk[i];
            let vk1 = vk[if i < (vk.len() - 1) { i + 1 } else { 0 }];
            // TODO(nicholasbishop): do more checking up front so that
            // edges don't get created on failure, or delete them after.
            if let Some(ek) = self.add_edge(vk0, vk1, edata.clone()) {
                loops.push(Loop { vert: vk0, edge: ek });
            } else {
                // Error: failed to create edge
                return None;
            }
        }
        if let Some(val) = self.face_range_set.take_any_one() {
            let fk = FKey::new(val);
            for lp in loops.iter() {
                self.edges.get_mut(&lp.edge).unwrap().push_face(fk);
            }
            self.faces.insert(fk, Face::new(loops, fdata));
            Some(fk)
        } else {
            None
        }
    }

    pub fn delete_face(&mut self, fk: FKey) {
        self.faces.remove(&fk);
        self.face_range_set.release_one(fk.value());
    }
}

pub struct Vert<VData> {
    pub vdata: VData,
    edges: Vec<EKey>
}

impl<VData> Vert<VData> {
    fn new(vdata: VData) -> Vert<VData> {
        Vert { vdata: vdata, edges: Vec::new() }
    }

    /// Check if the edge is in the set of edges adjacent to this vert.
    pub fn is_edge_adjacent(&self, ek: EKey) -> bool {
        self.edges.contains(&ek)
    }

    pub fn get_edges(&self) -> &Vec<EKey> {
        &self.edges
    }

    /// Add edge to set of edges adjacent to the vert. Does nothing if
    /// the edge is already in the set.
    fn push_edge(&mut self, ek: EKey) {
        if !self.is_edge_adjacent(ek) {
            self.edges.push(ek);
        }
    }
}

pub struct Edge<EData> {
    pub edata: EData,
    verts: [VKey; 2],
    faces: Vec<FKey>
}

impl<EData> Edge<EData> {
    fn new(vk0: VKey, vk1: VKey, edata: EData) -> Edge<EData> {
        Edge { edata: edata, verts: [vk0, vk1], faces: Vec::new() }
    }

    /// Check if the vert is one of the two verts adjacent to this edge.
    fn is_vert_adjacent(&self, vk: VKey) -> bool {
        self.verts.contains(&vk)
    }

    /// Check if the face is in the set of edges adjacent to this edge.
    pub fn is_face_adjacent(&self, fk: FKey) -> bool {
        self.faces.contains(&fk)
    }

    pub fn get_verts(&self) -> &[VKey; 2] {
        &self.verts
    }

    pub fn get_faces(&self) -> &Vec<FKey> {
        &self.faces
    }

    /// Given one of the edge's verts, return the other one. If the
    /// input is not one if the edge's verts, return None.
    pub fn other_vert(&self, vk: VKey) -> Option<VKey> {
        if vk == self.verts[0] {
            Some(self.verts[1])
        } else if vk == self.verts[1] {
            Some(self.verts[0])
        } else {
            None
        }
    }

    /// Add face to set of faces adjacent to the edge. Does nothing if
    /// the face is already in the set.
    fn push_face(&mut self, fk: FKey) {
        if !self.is_face_adjacent(fk) {
            self.faces.push(fk);
        }
    }
}

pub struct Loop {
    pub vert: VKey,
    pub edge: EKey
}

pub struct Face<FData> {
    pub fdata: FData,
    loops: Vec<Loop>
}

impl<FData> Face<FData> {
    fn new(loops: Vec<Loop>, fdata: FData) -> Face<FData> {
        Face { fdata: fdata, loops: loops }
    }

    pub fn get_loops(&self) -> &Vec<Loop> {
        &self.loops
    }
}

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

    // Placeholder for vert/edge/face data
    const DAT: () = ();

    #[test]
    fn test_add_vert() {
        let mut mesh = Mesh::<_, (), ()>::new();
        assert!(mesh.add_vert(DAT).is_some());
        assert!(!mesh.verts.is_empty());
    }

    #[test]
    fn test_add_edge() {
        let mut mesh = Mesh::<_, _, ()>::new();
        let a = mesh.add_vert(DAT).unwrap();
        let b = mesh.add_vert(DAT).unwrap();

        // Add a valid edge
        let e = mesh.add_edge(a, b, DAT).unwrap();
        assert!(mesh.verts[&a].edges.contains(&e));
        assert!(mesh.verts[&b].edges.contains(&e));

        // Edge from a vertex to the same vertex is not allowed
        assert!(mesh.add_edge(a, a, DAT).is_none());

        // Duplicate edge should return the existing edge
        assert_eq!(mesh.add_edge(a, b, DAT).unwrap(), e);
        assert_eq!(mesh.add_edge(b, a, DAT).unwrap(), e);
    }

    #[test]
    fn test_add_face() {
        let mut mesh = Mesh::new();
        let a = mesh.add_vert(DAT).unwrap();
        let b = mesh.add_vert(DAT).unwrap();
        let c = mesh.add_vert(DAT).unwrap();

        // Add a valid triangle
        let fk = mesh.add_face(&[a, b, c], DAT, DAT).unwrap();
        assert_eq!(mesh.edges.len(), 3);
        for lp in mesh.faces[&fk].loops.iter() {
            assert!(mesh.edges[&lp.edge].is_face_adjacent(fk));
        }

        // Add an invalid triangle with invalid edge
        assert!(mesh.add_face(&[a, b, b], DAT, DAT).is_none());
    }

    #[test]
    fn test_vert_adjacent_faces() {
        // Create a bow-tie mesh
        let mut mesh = Mesh::new();
        let middle = mesh.add_vert(DAT).unwrap();
        let l0 = mesh.add_vert(DAT).unwrap();
        let l1 = mesh.add_vert(DAT).unwrap();
        let r0 = mesh.add_vert(DAT).unwrap();
        let r1 = mesh.add_vert(DAT).unwrap();
        let fk0 = mesh.add_face(&[middle, l0, l1], DAT, DAT).unwrap();
        let fk1 = mesh.add_face(&[middle, r0, r1], DAT, DAT).unwrap();

        let adj = mesh.vert_adjacent_faces(middle);
        assert_eq!(adj.len(), 2);
        assert!(adj.contains(&fk0));
        assert!(adj.contains(&fk1));
    }

    #[test]
    fn test_ngon() {
        let mut mesh = Mesh::new();
        let a = mesh.add_vert(DAT).unwrap();
        let b = mesh.add_vert(DAT).unwrap();
        let c = mesh.add_vert(DAT).unwrap();
        let d = mesh.add_vert(DAT).unwrap();
        let e = mesh.add_vert(DAT).unwrap();

        let fk = mesh.add_face(&[a, b, c, d, e], DAT, DAT).unwrap();
        let face = &mesh.faces[&fk];

        assert_eq!(face.loops.len(), 5);
    }

    #[test]
    fn test_separate_connected_edges() {
        let mut mesh = Mesh::<_, _, ()>::new();
        let vk0 = mesh.add_vert(DAT).unwrap();
        let vk1 = mesh.add_vert(DAT).unwrap();
        let ek0 = mesh.add_edge(vk0, vk1, DAT).unwrap();

        let vk2 = mesh.add_vert(DAT).unwrap();
        let vk3 = mesh.add_vert(DAT).unwrap();
        let vk4 = mesh.add_vert(DAT).unwrap();
        let vk5 = mesh.add_vert(DAT).unwrap();
        let ek1 = mesh.add_edge(vk2, vk3, DAT).unwrap();
        let ek2 = mesh.add_edge(vk3, vk4, DAT).unwrap();
        let ek3 = mesh.add_edge(vk3, vk5, DAT).unwrap();

        let ce = mesh.separate_connected_edges(vec![ek0, ek1, ek2, ek3]);
        assert_eq!(ce.len(), 2);
        assert!(ce[0].len() == 1 || ce[1].len() == 1);
        let g0 = if ce[0].len() == 1 { &ce[0] } else { &ce[1] };
        let g1 = if ce[0].len() == 1 { &ce[1] } else { &ce[0] };

        assert_eq!(g0, &[ek0]);
        assert_eq!(g1.len(), 3);
        assert!(g1.contains(&ek1));
        assert!(g1.contains(&ek2));
        assert!(g1.contains(&ek3));
    }
}
<|endoftext|>


<commit_before>#![crate_id = "knuckle#knuckle"]
#![crate_type = "lib"]
#![desc = "TODO: write me"]
#![license = "MIT"]

#![feature(globs)]
// #[deny(missing_doc)]

//! `knuckle` is an opinionated Rust language interface to the
//! already opinionated NaCl project.
//!
//! Specifically, knuckle uses `tweetnacl`, a minimal implementation
//! of NaCl that's implemented as a standalone C file. Theoretically, the
//! backend could be trivially switched to either full NaCl or the
//! derivative `libsodium` project.
//!
//! It provides several useful abstractions around NaCl's primitives,
//! but also exposes direct bindings to the C library (via the `bindings`
//! module).
//!
//! ## Primitives
//!
//! The following cryptographic primitives are used with this library.
//!
//! Module        | Primitive
//! ------------- | -------------
//! cryptobox     | Curve25519/Salsa20/Poly1305
//! hash          | SHA-512
//! secretbox     | Salsa20/Poly1305
//! sign          | Ed25519
//! stream        | Salsa20

extern crate libc;

pub use bindings::*;

/// Exposes direct Rust bindings to the C NaCl interface.
#[allow(dead_code)]
pub mod bindings;

/// Exposes the crypto_box functionality of NaCl.
pub mod cryptobox;

/// Exposes the crypto_hash functionality of NaCl.
pub mod hash;

/// Exposes the crypto_secretbox functionality of NaCl.
pub mod secretbox;

/// Exposes the crypto_sign functionality of NaCl.
pub mod sign;

/// Exposes the crypto_stream functionality of NaCl.
pub mod stream;
<commit_msg>crate_id -> crate_name<commit_after>#![crate_name = "knuckle"]
#![crate_type = "lib"]
#![desc = "TODO: write me"]
#![license = "MIT"]

#![feature(globs)]
// #[deny(missing_doc)]

//! `knuckle` is an opinionated Rust language interface to the
//! already opinionated NaCl project.
//!
//! Specifically, knuckle uses `tweetnacl`, a minimal implementation
//! of NaCl that's implemented as a standalone C file. Theoretically, the
//! backend could be trivially switched to either full NaCl or the
//! derivative `libsodium` project.
//!
//! It provides several useful abstractions around NaCl's primitives,
//! but also exposes direct bindings to the C library (via the `bindings`
//! module).
//!
//! ## Primitives
//!
//! The following cryptographic primitives are used with this library.
//!
//! Module        | Primitive
//! ------------- | -------------
//! cryptobox     | Curve25519/Salsa20/Poly1305
//! hash          | SHA-512
//! secretbox     | Salsa20/Poly1305
//! sign          | Ed25519
//! stream        | Salsa20

extern crate libc;

pub use bindings::*;

/// Exposes direct Rust bindings to the C NaCl interface.
#[allow(dead_code)]
pub mod bindings;

/// Exposes the crypto_box functionality of NaCl.
pub mod cryptobox;

/// Exposes the crypto_hash functionality of NaCl.
pub mod hash;

/// Exposes the crypto_secretbox functionality of NaCl.
pub mod secretbox;

/// Exposes the crypto_sign functionality of NaCl.
pub mod sign;

/// Exposes the crypto_stream functionality of NaCl.
pub mod stream;
<|endoftext|>


<commit_before>// Many of my decisions were based off the following document
// https://web.archive.org/web/20140727185616/http://algs4.cs.princeton.edu/33balanced/

// TODO:
// Collection trait
// convert this to Key/Value K/V

use Direction::{Left, Middle, Right, Leaf};
use InsertResult::{Fit, Split};

/// SplitNode
enum SplitNode<V: Ord> {
    Four(V, V, V, Box<Node<V>>, Box<Node<V>>, Box<Node<V>>, Box<Node<V>>),
    LeafFour(V, V, V),
}

impl <V: Ord> SplitNode<V> {
    fn to_two(self) -> Two<V> {
        match self {
            SplitNode::LeafFour(v1, v2, v3) =>
                Two(v2,
                    box Node::LeafTwo(LeafTwo(v1)),
                    box Node::LeafTwo(LeafTwo(v3))),
            SplitNode::Four(v1, v2, v3, n1, n2, n3, n4) =>
                Two(v2,
                    box Node::Two(Two(v1, n1, n2)),
                    box Node::Two(Two(v3, n3, n4))),
        }
    }
}

/// InsertResult
enum InsertResult<V: Ord> {
    Fit(Node<V>),
    Split(SplitNode<V>),
}

/// Direction
enum Direction {
    Left,
    Middle,
    Right,
    Leaf,
}

/// Two
pub struct Two<V: Ord>(pub V, pub Box<Node<V>>, pub Box<Node<V>>);

impl <V: Ord> Two<V> {
    fn as_node(self) -> Node<V> { Node::Two(self) }

    fn to_three(self, other_value: V, other_node: Box<Node<V>>) -> Three<V> {
        let Two(self_value, self_left, self_middle) = self;
        if self_value > other_value {
            Three(other_value, self_value, other_node, self_left, self_middle)
        } else {
            Three(self_value, other_value, self_left, self_middle, other_node)
        }
    }
}

/// Three
pub struct Three<V: Ord>(pub V, pub V, pub Box<Node<V>>, pub Box<Node<V>>, pub Box<Node<V>>);

impl <V: Ord> Three<V> {
    fn as_node(self) -> Node<V> { Node::Three(self) }

    fn to_split_node(self, other_value: V, other_node: Box<Node<V>>) -> SplitNode<V> {
        let Three(self_value1, self_value2, self_left, self_middle, self_right) = self;
        if other_value < self_value1 {
            SplitNode::Four(other_value, self_value1, self_value2, other_node, self_left, self_middle, self_right)
        } else {
            SplitNode::Four(self_value1, self_value2, other_value, self_left, self_middle, self_right, other_node)
        }
    }
}

/// LeafTwo
pub struct LeafTwo<V: Ord>(pub V);

impl <V: Ord> LeafTwo<V> {
    fn to_three(self, other_value: V) -> LeafThree<V> {
        let LeafTwo(self_value) = self;
        if self_value > other_value {
            LeafThree(other_value, self_value)
        } else {
            LeafThree(self_value, other_value)
        }
    }
}

/// LeafThree
pub struct LeafThree<V: Ord>(pub V, pub V);

impl <V: Ord> LeafThree<V> {
    fn as_node(self) -> Node<V> { Node::LeafThree(self) }

    fn to_split_node(self, value: V) -> SplitNode<V> {
        let LeafThree(value1, value2) = self;
        if value > value2      { SplitNode::LeafFour(value1, value2, value) }
        else if value < value1 { SplitNode::LeafFour(value, value1, value2) }
        else                   { SplitNode::LeafFour(value1, value, value2) }
    }
}

/// Node
pub enum Node<V: Ord> {
    LeafTwo(LeafTwo<V>),
    LeafThree(LeafThree<V>),
    Two(Two<V>),
    Three(Three<V>),
}

impl <V: Ord> Node<V> {
    fn next_direction(&self, to_insert: &V) -> Direction {
        match self {
            &Node::Two(Two(ref value, _, _)) =>
                if to_insert < value { Left }
                else                 { Middle },
            &Node::Three(Three(ref value1, ref value2, _, _, _)) =>
                if      to_insert < value1 { Left }
                else if to_insert > value2 { Right }
                else                       { Middle },
            _ => Leaf,
        }
    }

    fn contains_node(&self, to_check: &V) -> bool {
        match self {
            &Node::Two(Two(ref v, _, _)) |
                &Node::LeafTwo(LeafTwo(ref v)) if to_check == v => true,

            &Node::Three(Three(ref v1, ref v2, _, _, _)) |
                &Node::LeafThree(LeafThree(ref v1, ref v2)) if to_check == v1 || to_check == v2 => true,

            _ => false
        }
    }

    fn insert(self, to_insert: V) -> InsertResult<V> {
        // If value is already in this node, we're done (prevent duplicates)
        if self.contains_node(&to_insert) { return Fit(self); }

        let next_direction = self.next_direction(&to_insert);

        match self {
            // Insert if leaf TwoNode
            Node::LeafTwo(leaf_two) => {
                let three_node = leaf_two.to_three(to_insert);
                Fit(three_node.as_node())
            },

            // Split if leaf ThreeNode
            Node::LeafThree(leaf_three) => {
                let split_node = leaf_three.to_split_node(to_insert);
                Split(split_node)
            },

            // Recurse down if internal Node and handle results
            Node::Two(Two(value, box left, box middle)) => {

                // Determine which node we'll recurse next
                let (next_node, other_node) = match next_direction {
                    Left => (left, middle),
                    Middle => (middle, left),
                    _ => panic!(""),
                };

                // Recurse, save the result of the insert
                let insert_result = next_node.insert(to_insert);

                // Handle the result of the insert
                let new_node = match insert_result {
                    Fit(returned_node) =>
                        match next_direction {
                            Left =>   Two(value, box returned_node, box other_node),
                            Middle => Two(value, box other_node, box returned_node),
                            _ => panic!(""),
                        }.as_node(),
                    Split(split_node) => split_node.to_two().to_three(value, box other_node).as_node(),
                };

                Fit(new_node)
            },

            // Recurse down if internal Node and handle results
            Node::Three(Three(value1, value2, left, middle, right)) => {

                // Determine which node we'll recurse next
                let (next_node, other_node1, other_node2) = match next_direction {
                    Left => (left, middle, right),
                    Middle => (middle, left, right),
                    Right => (right, left, middle),
                    _ => panic!(""),
                };

                let insert_result = next_node.insert(to_insert);

                match insert_result {
                    Fit(returned_node) => {
                        let three = match next_direction {
                            Left =>   Three(value1, value2, box returned_node, other_node1, other_node2),
                            Middle => Three(value1, value2, other_node1, box returned_node, other_node2),
                            Right =>  Three(value1, value2, other_node1, other_node2, box returned_node),
                            _ => panic!(""),
                        };
                        Fit(three.as_node())
                    },
                    Split(split_node) => {
                        let two = split_node.to_two();
                        let new_node = match next_direction {
                            Left =>   two.to_three(value1, other_node1).to_split_node(value2, other_node2),
                            Middle => two.to_three(value1, other_node1).to_split_node(value2, other_node2),
                            Right =>  two.to_three(value2, other_node2).to_split_node(value1, other_node1),
                            _ => panic!(""),
                        };
                        Split(new_node)
                    }
                }
            }
        }
    }
}

/// TTTree
pub struct TTTree<V: Ord> {
    pub root: Option<Node<V>>,
}

impl <V: Ord> TTTree<V> {
    pub fn new() -> TTTree<V> {
        TTTree { root: None }
    }

    pub fn insert(&mut self, value: V) -> () {
        let root: Option<Node<V>> = self.root.take();
        let new_root: Node<V> = match root {
            None => Node::LeafTwo(LeafTwo(value)),
            Some(root) => {
                let result = root.insert(value);
                match result {
                    Fit(node) => node,
                    Split(split_node) => split_node.to_two().as_node(),
                }
            }
        };
        self.root = Some(new_root);
    }
}
<commit_msg>Clean up some logic<commit_after>// Many of my decisions were based off the following document
// https://web.archive.org/web/20140727185616/http://algs4.cs.princeton.edu/33balanced/

// TODO:
// Collection trait
// convert this to Key/Value K/V

use Direction::{Left, Middle, Right, Leaf};
use InsertResult::{Fit, Split};

/// SplitNode
enum SplitNode<V: Ord> {
    Four(V, V, V, Box<Node<V>>, Box<Node<V>>, Box<Node<V>>, Box<Node<V>>),
    LeafFour(V, V, V),
}

impl <V: Ord> SplitNode<V> {
    fn to_two(self) -> Two<V> {
        match self {
            SplitNode::LeafFour(v1, v2, v3) =>
                Two(v2,
                    box Node::LeafTwo(LeafTwo(v1)),
                    box Node::LeafTwo(LeafTwo(v3))),
            SplitNode::Four(v1, v2, v3, n1, n2, n3, n4) =>
                Two(v2,
                    box Node::Two(Two(v1, n1, n2)),
                    box Node::Two(Two(v3, n3, n4))),
        }
    }
}

/// InsertResult
enum InsertResult<V: Ord> {
    Fit(Node<V>),
    Split(SplitNode<V>),
}

/// Direction
enum Direction {
    Left,
    Middle,
    Right,
    Leaf,
}

/// Two
pub struct Two<V: Ord>(pub V, pub Box<Node<V>>, pub Box<Node<V>>);

impl <V: Ord> Two<V> {
    fn as_node(self) -> Node<V> { Node::Two(self) }

    fn to_three(self, other_value: V, other_node: Box<Node<V>>) -> Three<V> {
        let Two(self_value, self_left, self_middle) = self;
        if self_value > other_value {
            Three(other_value, self_value, other_node, self_left, self_middle)
        } else {
            Three(self_value, other_value, self_left, self_middle, other_node)
        }
    }

    fn has_value(&self, value: &V) -> bool {
        let &Two(ref self_value, _, _) = self;
        *self_value == *value
    }
}

/// Three
pub struct Three<V: Ord>(pub V, pub V, pub Box<Node<V>>, pub Box<Node<V>>, pub Box<Node<V>>);

impl <V: Ord> Three<V> {
    fn as_node(self) -> Node<V> { Node::Three(self) }

    fn to_split_node(self, other_value: V, other_node: Box<Node<V>>) -> SplitNode<V> {
        let Three(self_value1, self_value2, self_left, self_middle, self_right) = self;
        if other_value < self_value1 {
            SplitNode::Four(other_value, self_value1, self_value2, other_node, self_left, self_middle, self_right)
        } else {
            SplitNode::Four(self_value1, self_value2, other_value, self_left, self_middle, self_right, other_node)
        }
    }

    fn has_value(&self, value: &V) -> bool {
        let &Three(ref self_value1, ref self_value2, _, _, _) = self;
        *self_value1 == *value || *self_value2 == *value
    }
}

/// LeafTwo
pub struct LeafTwo<V: Ord>(pub V);

impl <V: Ord> LeafTwo<V> {
    fn to_three(self, other_value: V) -> LeafThree<V> {
        let LeafTwo(self_value) = self;
        if self_value > other_value {
            LeafThree(other_value, self_value)
        } else {
            LeafThree(self_value, other_value)
        }
    }

    fn has_value(&self, value: &V) -> bool {
        let &LeafTwo(ref self_value) = self;
        *self_value == *value
    }
}

/// LeafThree
pub struct LeafThree<V: Ord>(pub V, pub V);

impl <V: Ord> LeafThree<V> {
    fn as_node(self) -> Node<V> { Node::LeafThree(self) }

    fn to_split_node(self, value: V) -> SplitNode<V> {
        let LeafThree(value1, value2) = self;
        if value > value2      { SplitNode::LeafFour(value1, value2, value) }
        else if value < value1 { SplitNode::LeafFour(value, value1, value2) }
        else                   { SplitNode::LeafFour(value1, value, value2) }
    }

    fn has_value(&self, value: &V) -> bool {
        let &LeafThree(ref self_value1, ref self_value2) = self;
        *self_value1 == *value || *self_value2 == *value
    }
}

/// Node
pub enum Node<V: Ord> {
    LeafTwo(LeafTwo<V>),
    LeafThree(LeafThree<V>),
    Two(Two<V>),
    Three(Three<V>),
}

impl <V: Ord> Node<V> {
    fn next_direction(&self, to_insert: &V) -> Direction {
        match self {
            &Node::Two(Two(ref value, _, _)) =>
                if to_insert < value { Left }
                else                 { Middle },
            &Node::Three(Three(ref value1, ref value2, _, _, _)) =>
                if      to_insert < value1 { Left }
                else if to_insert > value2 { Right }
                else                       { Middle },
            _ => Leaf,
        }
    }

    fn has_value(&self, value: &V) -> bool {
        match self {
            &Node::LeafTwo(ref n)   => n.has_value(value),
            &Node::LeafThree(ref n) => n.has_value(value),
            &Node::Two(ref n)       => n.has_value(value),
            &Node::Three(ref n)     => n.has_value(value),
        }
    }

    fn insert(self, to_insert: V) -> InsertResult<V> {
        // If value is already in this node, we're done (prevent duplicates)
        if self.has_value(&to_insert) { return Fit(self); }

        let next_direction = self.next_direction(&to_insert);

        match self {
            // Insert if leaf TwoNode
            Node::LeafTwo(leaf_two) => {
                let three_node = leaf_two.to_three(to_insert);
                Fit(three_node.as_node())
            },

            // Split if leaf ThreeNode
            Node::LeafThree(leaf_three) => {
                let split_node = leaf_three.to_split_node(to_insert);
                Split(split_node)
            },

            // Recurse down if internal Node and handle results
            Node::Two(Two(value, box left, box middle)) => {

                // Determine which node we'll recurse next
                let (next_node, other_node) = match next_direction {
                    Left => (left, middle),
                    Middle => (middle, left),
                    _ => panic!(""),
                };

                // Recurse, save the result of the insert
                let insert_result = next_node.insert(to_insert);

                // Handle the result of the insert
                let new_node = match insert_result {
                    Fit(returned_node) =>
                        match next_direction {
                            Left =>   Two(value, box returned_node, box other_node),
                            Middle => Two(value, box other_node, box returned_node),
                            _ => panic!(""),
                        }.as_node(),
                    Split(split_node) => split_node.to_two().to_three(value, box other_node).as_node(),
                };

                Fit(new_node)
            },

            // Recurse down if internal Node and handle results
            Node::Three(Three(value1, value2, left, middle, right)) => {

                // Determine which node we'll recurse next
                let (next_node, other_node1, other_node2) = match next_direction {
                    Left => (left, middle, right),
                    Middle => (middle, left, right),
                    Right => (right, left, middle),
                    _ => panic!(""),
                };

                let insert_result = next_node.insert(to_insert);

                match insert_result {
                    Fit(returned_node) => {
                        let three = match next_direction {
                            Left =>   Three(value1, value2, box returned_node, other_node1, other_node2),
                            Middle => Three(value1, value2, other_node1, box returned_node, other_node2),
                            Right =>  Three(value1, value2, other_node1, other_node2, box returned_node),
                            _ => panic!(""),
                        };
                        Fit(three.as_node())
                    },
                    Split(split_node) => {
                        let two = split_node.to_two();
                        let new_node = match next_direction {
                            Left =>   two.to_three(value1, other_node1).to_split_node(value2, other_node2),
                            Middle => two.to_three(value1, other_node1).to_split_node(value2, other_node2),
                            Right =>  two.to_three(value2, other_node2).to_split_node(value1, other_node1),
                            _ => panic!(""),
                        };
                        Split(new_node)
                    }
                }
            }
        }
    }
}

/// TTTree
pub struct TTTree<V: Ord> {
    pub root: Option<Node<V>>,
}

impl <V: Ord> TTTree<V> {
    pub fn new() -> TTTree<V> {
        TTTree { root: None }
    }

    pub fn insert(&mut self, value: V) -> () {
        let root: Option<Node<V>> = self.root.take();
        let new_root: Node<V> = match root {
            None => Node::LeafTwo(LeafTwo(value)),
            Some(root) => {
                let result = root.insert(value);
                match result {
                    Fit(node) => node,
                    Split(split_node) => split_node.to_two().as_node(),
                }
            }
        };
        self.root = Some(new_root);
    }
}
<|endoftext|>


<commit_before>extern crate toml;

// Import traits
use std::io::prelude::Read;

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}

pub fn test() {
    println!("Hello from lib.rs");
}

#[derive(Debug)]
enum OnSuccess {
    Continue,
    Warn {message: String},
    Abort {message: String},
}

#[derive(Debug)]
enum OnFailure {
    Continue,
    Warn {message: String},
    Abort {message: String},
}

#[derive(Debug)]
enum Step {
    Echo {name: String, message: String},
    Run {name: String, command: String, arguments: String, on_success: OnSuccess, on_failure: OnFailure},
    Shell,
    SetEnv,
}

fn parse_toml(filename: &str) -> Vec<Step> {

    println!("Reading toml file {}", filename);

    // Read toml file content
    let mut input = String::new();
    std::fs::File::open(&filename).and_then(|mut f| {
        f.read_to_string(&mut input)
    }).unwrap();

    // Pase toml file
    let mut parser = toml::Parser::new(&input);

    let toml = parser.parse().unwrap_or_else(|| {
        for err in &parser.errors {
            let (loline, locol) = parser.to_linecol(err.lo);
            let (hiline, hicol) = parser.to_linecol(err.hi);
            println!("{}:{}:{}-{}:{} error: {}",
                     filename, loline, locol, hiline, hicol, err.desc);
        }
        panic!("Error parsing toml file.");
    });

    // println!("toml: {:#?}", toml);

    // Parse "variables" table
    // unimplemented!();

    // Parse "steps" table
    let mut steps = Vec::<Step>::with_capacity(10);

    for step in toml.get("step").unwrap().as_slice().unwrap() {
        let action = step.as_table().unwrap().get("action").unwrap().as_str().unwrap();
        let name = step.as_table().unwrap().get("name").unwrap().as_str().unwrap().to_string();
        let details = step.as_table().unwrap().get("details").unwrap().as_table().unwrap();
        let step = match action {
            "echo" => {
                let message = details.get("message").unwrap().as_str().unwrap().to_string();
                Step::Echo {name: name, message: message}
            },
            "run" => {
                let command = details.get("command").unwrap().as_str().unwrap().to_string();
                let arguments = details.get("arguments").unwrap().as_str().unwrap().to_string();

                let on_success = match details.get("on_success") {
                    None => {
                        println!("WARNING: No 'on_success' set for {:?}, default of 'OnSuccess::Continue'", name);
                        OnSuccess::Continue
                    },
                    Some(toml_value) => {
                        let table = toml_value.as_table().unwrap();
                        let (message_type, message) = table.iter().nth(0).unwrap();
                        match message_type.as_ref() {
                            "warn" => OnSuccess::Warn {message: message.as_str().unwrap().to_string()},
                            "abort" => OnSuccess::Abort {message: message.as_str().unwrap().to_string()},
                            _ => unimplemented!()
                        }
                    }
                };

                let on_failure = match details.get("on_failure") {
                    None => {
                        println!("WARNING: No 'on_failure' set for {:?}, default of 'OnFailure::Continue'", name);
                        OnFailure::Continue
                    },
                    Some(toml_value) => {
                        let table = toml_value.as_table().unwrap();
                        let (message_type, message) = table.iter().nth(0).unwrap();
                        match message_type.as_ref() {
                            "warn" => OnFailure::Warn {message: message.as_str().unwrap().to_string()},
                            "abort" => OnFailure::Abort {message: message.as_str().unwrap().to_string()},
                            _ => unimplemented!()
                        }
                    }
                };

                Step::Run {name: name, command: command, arguments: arguments, on_success: on_success, on_failure: on_failure}
            },
            // "shell" => {
            // },
            // "setenv" => {
            // },
            _ => {
                println!("Unknown action '{}' in toml file", action);
                unimplemented!();
            },
        };
        // println!("Step: {:?}", step);

        steps.push(step);
    }

    steps
}

pub fn execute_steps(filename: &str) {

    let steps = parse_toml(filename);

    println!("Steps: {:#?}", steps);

    // Loop over steps
    let nb_steps = steps.len();
    for (idx, step) in steps.into_iter().enumerate() {
        // println!("Step {}/{} -- ", idx+1, nb_steps);
        match step {
            Step::Echo {name, message} => {
                // FIXME: Replace environment variables in 'message'
                println!("{}", message);
            },
            Step::Run {name, command, arguments, on_success, on_failure} => {},
            _ => unimplemented!(),
        }
    }

}
<commit_msg>Allow non-existing 'arguments' field, defaulting to empty string.<commit_after>extern crate toml;

// Import traits
use std::io::prelude::Read;

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}

pub fn test() {
    println!("Hello from lib.rs");
}

#[derive(Debug)]
enum OnSuccess {
    Continue,
    Warn {message: String},
    Abort {message: String},
}

#[derive(Debug)]
enum OnFailure {
    Continue,
    Warn {message: String},
    Abort {message: String},
}

#[derive(Debug)]
enum Step {
    Echo {name: String, message: String},
    Run {name: String, command: String, arguments: String, on_success: OnSuccess, on_failure: OnFailure},
    Shell,
    SetEnv,
}

fn parse_toml(filename: &str) -> Vec<Step> {

    println!("Reading toml file {}", filename);

    // Read toml file content
    let mut input = String::new();
    std::fs::File::open(&filename).and_then(|mut f| {
        f.read_to_string(&mut input)
    }).unwrap();

    // Pase toml file
    let mut parser = toml::Parser::new(&input);

    let toml = parser.parse().unwrap_or_else(|| {
        for err in &parser.errors {
            let (loline, locol) = parser.to_linecol(err.lo);
            let (hiline, hicol) = parser.to_linecol(err.hi);
            println!("{}:{}:{}-{}:{} error: {}",
                     filename, loline, locol, hiline, hicol, err.desc);
        }
        panic!("Error parsing toml file.");
    });

    // println!("toml: {:#?}", toml);

    // Parse "variables" table
    // unimplemented!();

    // Parse "steps" table
    let mut steps = Vec::<Step>::with_capacity(10);

    for step in toml.get("step").unwrap().as_slice().unwrap() {
        let action = step.as_table().unwrap().get("action").unwrap().as_str().unwrap();
        let name = step.as_table().unwrap().get("name").unwrap().as_str().unwrap().to_string();
        let details = step.as_table().unwrap().get("details").unwrap().as_table().unwrap();
        let step = match action {
            "echo" => {
                let message = details.get("message").unwrap().as_str().unwrap().to_string();
                Step::Echo {name: name, message: message}
            },
            "run" => {
                let command = details.get("command").unwrap().as_str().unwrap().to_string();

                // Allow non-existing 'arguments' field, defaulting to empty string.
                let arguments_option = details.get("arguments");
                let arguments = match arguments_option {
                    None => String::new(),
                    Some(arguments_toml_value) => arguments_toml_value.as_str().unwrap().to_string(),
                };

                let on_success = match details.get("on_success") {
                    None => {
                        println!("WARNING: No 'on_success' set for {:?}, default of 'OnSuccess::Continue'", name);
                        OnSuccess::Continue
                    },
                    Some(toml_value) => {
                        let table = toml_value.as_table().unwrap();
                        let (message_type, message) = table.iter().nth(0).unwrap();
                        match message_type.as_ref() {
                            "warn" => OnSuccess::Warn {message: message.as_str().unwrap().to_string()},
                            "abort" => OnSuccess::Abort {message: message.as_str().unwrap().to_string()},
                            _ => unimplemented!()
                        }
                    }
                };

                let on_failure = match details.get("on_failure") {
                    None => {
                        println!("WARNING: No 'on_failure' set for {:?}, default of 'OnFailure::Continue'", name);
                        OnFailure::Continue
                    },
                    Some(toml_value) => {
                        let table = toml_value.as_table().unwrap();
                        let (message_type, message) = table.iter().nth(0).unwrap();
                        match message_type.as_ref() {
                            "warn" => OnFailure::Warn {message: message.as_str().unwrap().to_string()},
                            "abort" => OnFailure::Abort {message: message.as_str().unwrap().to_string()},
                            _ => unimplemented!()
                        }
                    }
                };

                Step::Run {name: name, command: command, arguments: arguments, on_success: on_success, on_failure: on_failure}
            },
            // "shell" => {
            // },
            // "setenv" => {
            // },
            _ => {
                println!("Unknown action '{}' in toml file", action);
                unimplemented!();
            },
        };
        // println!("Step: {:?}", step);

        steps.push(step);
    }

    steps
}

pub fn execute_steps(filename: &str) {

    let steps = parse_toml(filename);

    println!("Steps: {:#?}", steps);

    // Loop over steps
    let nb_steps = steps.len();
    for (idx, step) in steps.into_iter().enumerate() {
        // println!("Step {}/{} -- ", idx+1, nb_steps);
        match step {
            Step::Echo {name, message} => {
                // FIXME: Replace environment variables in 'message'
                println!("{}", message);
            },
            Step::Run {name, command, arguments, on_success, on_failure} => {},
            _ => unimplemented!(),
        }
    }

}
<|endoftext|>


<commit_before>//! A simple `io::stdout` and `io::stderr` writing `Logger` implementation from the
//! `log` crate, using the `ansi_term` crate for colors and configured at runtime,
//! or at compile time with simple function calls. Designed for simple CLIs.
//!
//! This library only comes with 3 public ways to initialize the global logger.
//! Ensure you call one of these exactly once early in your rust program as shown
//! in one of the examples below.
//!
//! ## Example
//! The standard example with `clap` as the arg parser.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate clap;
//! extern crate loggerv;
//!
//! use clap::{Arg, App};
//!
//! fn main() {
//!     let args = App::new("app")
//!                    .arg(Arg::with_name("v")
//!                             .short("v")
//!                             .multiple(true)
//!                             .help("Sets the level of verbosity"))
//!                    .get_matches();
//!
//!     loggerv::init_with_verbosity(args.occurrences_of("v")).unwrap();
//!
//!     error!("this is always printed");
//!     warn!("this too, and it's printed to stderr");
//!     info!("this is optional");  // for ./app -v or higher
//!     debug!("this is optional"); // for ./app -vv or higher
//!     trace!("this is optional"); // for ./app -vvv
//! }
//! ```
//!
//! But obviously use whatever argument parsing methods you prefer.
//!
//! ## Example
//! For a compile time switch, all you really need is `log` (for the macros)
//! and `loggerv` for how to print what's being sent to the macros.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! use log::LogLevel;
//!
//! fn main() {
//!     loggerv::init_with_level(LogLevel::Info).unwrap();
//!     debug!("this is a debug {}", "message");
//!     error!("this is printed by default");
//! }
//! ```
//!
//! # Example
//! If you don't really care at all you could just use the plain `init_quiet` function
//! to only show warnings and errors:
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! fn main() {
//!     loggerv::init_quiet().unwrap();
//!     info!("hidden");
//!     error!("this is printed by default");
//! }
//! ```
//!
//!
//! See the documentation for the log crate for more information about its API.
//!

#[cfg(test)]
#[macro_use]
extern crate log;

#[cfg(not(test))]
extern crate log;

extern crate atty;
extern crate ansi_term;

use log::{Log, LogLevel, LogMetadata, LogRecord, SetLoggerError};
use std::io::{self, Write};
use ansi_term::Colour;

pub const DEFAULT_COLORS: bool = true;
pub const DEFAULT_SEPARATOR: &str = ": ";
pub const DEFAULT_LEVEL: LogLevel = LogLevel::Warn;
pub const DEFAULT_LINE_NUMBERS: bool = false;
pub const DEFAULT_MODULE_PATH: bool = true;

#[derive(Debug, Clone, PartialEq)]
pub struct Logger {
    colors: bool,
    line_numbers: bool,
    level: LogLevel,
    module_path: bool,
    separator: String,
    error_color: Colour,
    warn_color: Colour,
    info_color: Colour,
    debug_color: Colour,
    trace_color: Colour,
}

impl Logger {
    /// Creates a new instance of the verbosity-based logger.
    ///
    /// The default level is WARN. Color is enabled if the parent application or library is running
    /// from a terminal, i.e. running a tty. The default separator is the ": " string. The default
    /// output format is `LEVEL [module path]: message`.
    pub fn new() -> Logger {
        Logger {
            colors: DEFAULT_COLORS && atty::is(atty::Stream::Stdout) && atty::is(atty::Stream::Stderr),
            line_numbers: DEFAULT_LINE_NUMBERS,
            level: DEFAULT_LEVEL,
            module_path: DEFAULT_MODULE_PATH,
            separator: String::from(DEFAULT_SEPARATOR),
            error_color: Colour::Fixed(9), // bright red
            warn_color: Colour::Fixed(11), // bright yellow
            info_color: Colour::Fixed(10), // bright green
            debug_color: Colour::Fixed(7), // light grey
            trace_color: Colour::Fixed(8), // grey
        }
    }

    /// Sets the output color for the ERROR level. The default is bright red.
    pub fn error_color(mut self, c: Colour) -> Self {
        self.error_color = c;
        self
    }

    /// Sets the output color for the WARN level. The default is bright yellow.
    pub fn warn_color(mut self, c: Colour) -> Self {
        self.warn_color = c;
        self
    }

    /// Sets the output color for the INFO level. The default is bright green.
    pub fn info_color(mut self, c: Colour) -> Self {
        self.info_color = c;
        self
    }

    /// Sets the output color for the DEBUG level. The default is light grey.
    pub fn debug_color(mut self, c: Colour) -> Self {
        self.debug_color = c;
        self
    }

    /// Sets the output color for the TRACE level. The default is grey.
    pub fn trace_color(mut self, c: Colour) -> Self {
        self.trace_color = c;
        self
    }

    /// Gets the color to use for the log statement's tag based on level.
    fn color(&self, l: &LogLevel) -> Colour {
        match *l {
            LogLevel::Error => self.error_color,
            LogLevel::Warn => self.warn_color,
            LogLevel::Info => self.info_color,
            LogLevel::Debug => self.debug_color,
            LogLevel::Trace => self.trace_color,
        }
    }

    /// Sets the separator string.
    ///
    /// The separator is the string between the "tag" and the message that make up a log statement.
    /// The tag will be colorized if enabled, while the message will not. The default is `: `.
    pub fn separator(mut self, s: &str) -> Self {
        self.separator = String::from(s);
        self
    }

    /// Enables or disables colorizing the output.
    ///
    /// If the logger is _not_ used in a terminal, then
    /// the output is _not_ colorized regardless of the parameter value.
    pub fn colors(mut self, c: bool) -> Self {
        self.colors = c && atty::is(atty::Stream::Stdout) && atty::is(atty::Stream::Stderr);
        self
    }

    /// Enables or disables including line numbers in the "tag" portion of the log statement. The
    /// tag is the text to the left of the separator.
    pub fn line_numbers(mut self, l: bool) -> Self {
        self.line_numbers = l;
        self
    }

    /// Explicitly sets the log level instead through a verbosity.
    pub fn level(mut self, l: LogLevel) -> Self {
        self.level = l;
        self
    }

    /// Enables or disables including the module path in the "tag" portion of the log statement.
    /// The tag is the text to the left of the separator.
    pub fn module_path(mut self, m: bool) -> Self {
        self.module_path = m;
        self
    }

    /// Converts the verbosity to a log level.
    ///
    /// A verbosity of zero (0) is the default, which means ERROR and WARN log statements are
    /// printed to `stderr`. No other log statements are printed on any of the standard streams
    /// (`stdout` or `stderr`). As the verbosity is increased, the log level is increased and more
    /// log statements will be printed to `stdout`. A verbosity of 1 will print INFO log statements
    /// to `stdout` in addition to ERROR and WARN. A verbosity of 2 will print INFO and DEBUG log
    /// statements to `stdout`. A verbosity of 3 or higher will print INFO, DEBUG, and TRACE
    /// log statements to `stdout` with ERROR and WARN statements printed to `stderr`.
    pub fn verbosity(mut self, v: u64) -> Self {
        self.level = match v {
                0 => LogLevel::Warn,  // default
                1 => LogLevel::Info,  // -v
                2 => LogLevel::Debug, // -vv
                _ => LogLevel::Trace, // -vvv and above
        };
        self
    }

    /// Initializes the logger.
    ///
    /// This also consumes the logger and cannot no longer be modified after initialization.
    pub fn init(self) -> Result<(), SetLoggerError> {
        log::set_logger(|max_level| {
            max_level.set(self.level.to_log_level_filter());
            Box::new(self)
        })
    }
}

impl Log for Logger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let level = record.level();
            let module_path = if self.module_path {
                format!(" [{}]", record.location().module_path())
            } else {
                String::new()
            };
            let line = if self.line_numbers {
                format!(" (line {})", record.location().line())
            } else {
                String::new()
            };
            let tag = if self.colors {
                self.color(&level).paint(format!("{}{}{}", level, module_path, line)).to_string()
            } else {
                format!("{}{}{}", level, module_path, line)
            };
            if level <= LogLevel::Warn {
                let _ = writeln!(&mut io::stderr(), "{}{}{}", tag, self.separator, record.args());
            } else {
                println!("{}{}{}", tag, self.separator, record.args());
            }
        }
    }
}

impl Default for Logger {
    fn default() -> Logger {
        Logger::new()
    }
}

/// Initialize loggerv with a maximal log level.
///
/// See the main loggerv documentation page for an example.
pub fn init_with_level(level: LogLevel) -> Result<(), SetLoggerError> {
    Logger::new().level(level).init()
}

/// Initialize loggerv with a verbosity level.
///
/// Intended to be used with an arg parser counting the amount of -v flags.
/// See the main loggerv documentation page for an example.
pub fn init_with_verbosity(verbosity: u64) -> Result<(), SetLoggerError> {
    Logger::new().verbosity(verbosity).init()
}

/// Initializes loggerv with only warnings and errors.
///
/// See the main loggerv documentation page for an example.
pub fn init_quiet() -> Result<(), SetLoggerError> {
    init_with_level(LogLevel::Warn)
}

#[cfg(test)]
mod tests {
    use init_with_verbosity;

    #[test]
    fn init_and_macros() {
        let l = init_with_verbosity(3);
        assert_eq!(l.is_ok(), true);
        error!("error log");
        warn!("warn log");
        info!("info log");
        debug!("debug log");
        trace!("trace log");
    }
}
<commit_msg>Refactor default colors to constants<commit_after>//! A simple `io::stdout` and `io::stderr` writing `Logger` implementation from the
//! `log` crate, using the `ansi_term` crate for colors and configured at runtime,
//! or at compile time with simple function calls. Designed for simple CLIs.
//!
//! This library only comes with 3 public ways to initialize the global logger.
//! Ensure you call one of these exactly once early in your rust program as shown
//! in one of the examples below.
//!
//! ## Example
//! The standard example with `clap` as the arg parser.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate clap;
//! extern crate loggerv;
//!
//! use clap::{Arg, App};
//!
//! fn main() {
//!     let args = App::new("app")
//!                    .arg(Arg::with_name("v")
//!                             .short("v")
//!                             .multiple(true)
//!                             .help("Sets the level of verbosity"))
//!                    .get_matches();
//!
//!     loggerv::init_with_verbosity(args.occurrences_of("v")).unwrap();
//!
//!     error!("this is always printed");
//!     warn!("this too, and it's printed to stderr");
//!     info!("this is optional");  // for ./app -v or higher
//!     debug!("this is optional"); // for ./app -vv or higher
//!     trace!("this is optional"); // for ./app -vvv
//! }
//! ```
//!
//! But obviously use whatever argument parsing methods you prefer.
//!
//! ## Example
//! For a compile time switch, all you really need is `log` (for the macros)
//! and `loggerv` for how to print what's being sent to the macros.
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! use log::LogLevel;
//!
//! fn main() {
//!     loggerv::init_with_level(LogLevel::Info).unwrap();
//!     debug!("this is a debug {}", "message");
//!     error!("this is printed by default");
//! }
//! ```
//!
//! # Example
//! If you don't really care at all you could just use the plain `init_quiet` function
//! to only show warnings and errors:
//!
//! ```
//! #[macro_use] extern crate log;
//! extern crate loggerv;
//!
//! fn main() {
//!     loggerv::init_quiet().unwrap();
//!     info!("hidden");
//!     error!("this is printed by default");
//! }
//! ```
//!
//!
//! See the documentation for the log crate for more information about its API.
//!

#[cfg(test)]
#[macro_use]
extern crate log;

#[cfg(not(test))]
extern crate log;

extern crate atty;
extern crate ansi_term;

use log::{Log, LogLevel, LogMetadata, LogRecord, SetLoggerError};
use std::io::{self, Write};
use ansi_term::Colour;

pub const DEFAULT_COLORS: bool = true;
pub const DEFAULT_SEPARATOR: &str = ": ";
pub const DEFAULT_LEVEL: LogLevel = LogLevel::Warn;
pub const DEFAULT_LINE_NUMBERS: bool = false;
pub const DEFAULT_MODULE_PATH: bool = true;
pub const DEFAULT_ERROR_COLOR: Colour = Colour::Fixed(9); // bright red
pub const DEFAULT_WARN_COLOR: Colour = Colour::Fixed(11); // bright yellow
pub const DEFAULT_INFO_COLOR: Colour = Colour::Fixed(10); // bright green
pub const DEFAULT_DEBUG_COLOR: Colour = Colour::Fixed(7); // light grey
pub const DEFAULT_TRACE_COLOR: Colour = Colour::Fixed(8); // grey

#[derive(Debug, Clone, PartialEq)]
pub struct Logger {
    colors: bool,
    line_numbers: bool,
    level: LogLevel,
    module_path: bool,
    separator: String,
    error_color: Colour,
    warn_color: Colour,
    info_color: Colour,
    debug_color: Colour,
    trace_color: Colour,
}

impl Logger {
    /// Creates a new instance of the verbosity-based logger.
    ///
    /// The default level is WARN. Color is enabled if the parent application or library is running
    /// from a terminal, i.e. running a tty. The default separator is the ": " string. The default
    /// output format is `LEVEL [module path]: message`.
    pub fn new() -> Logger {
        Logger {
            colors: DEFAULT_COLORS && atty::is(atty::Stream::Stdout) && atty::is(atty::Stream::Stderr),
            line_numbers: DEFAULT_LINE_NUMBERS,
            level: DEFAULT_LEVEL,
            module_path: DEFAULT_MODULE_PATH,
            separator: String::from(DEFAULT_SEPARATOR),
            error_color: DEFAULT_ERROR_COLOR,
            warn_color: DEFAULT_WARN_COLOR,
            info_color: DEFAULT_INFO_COLOR,
            debug_color: DEFAULT_DEBUG_COLOR,
            trace_color: DEFAULT_TRACE_COLOR,
        }
    }

    /// Sets the output color for the ERROR level. The default is bright red.
    pub fn error_color(mut self, c: Colour) -> Self {
        self.error_color = c;
        self
    }

    /// Sets the output color for the WARN level. The default is bright yellow.
    pub fn warn_color(mut self, c: Colour) -> Self {
        self.warn_color = c;
        self
    }

    /// Sets the output color for the INFO level. The default is bright green.
    pub fn info_color(mut self, c: Colour) -> Self {
        self.info_color = c;
        self
    }

    /// Sets the output color for the DEBUG level. The default is light grey.
    pub fn debug_color(mut self, c: Colour) -> Self {
        self.debug_color = c;
        self
    }

    /// Sets the output color for the TRACE level. The default is grey.
    pub fn trace_color(mut self, c: Colour) -> Self {
        self.trace_color = c;
        self
    }

    /// Gets the color to use for the log statement's tag based on level.
    fn color(&self, l: &LogLevel) -> Colour {
        match *l {
            LogLevel::Error => self.error_color,
            LogLevel::Warn => self.warn_color,
            LogLevel::Info => self.info_color,
            LogLevel::Debug => self.debug_color,
            LogLevel::Trace => self.trace_color,
        }
    }

    /// Sets the separator string.
    ///
    /// The separator is the string between the "tag" and the message that make up a log statement.
    /// The tag will be colorized if enabled, while the message will not. The default is `: `.
    pub fn separator(mut self, s: &str) -> Self {
        self.separator = String::from(s);
        self
    }

    /// Enables or disables colorizing the output.
    ///
    /// If the logger is _not_ used in a terminal, then
    /// the output is _not_ colorized regardless of the parameter value.
    pub fn colors(mut self, c: bool) -> Self {
        self.colors = c && atty::is(atty::Stream::Stdout) && atty::is(atty::Stream::Stderr);
        self
    }

    /// Enables or disables including line numbers in the "tag" portion of the log statement. The
    /// tag is the text to the left of the separator.
    pub fn line_numbers(mut self, l: bool) -> Self {
        self.line_numbers = l;
        self
    }

    /// Explicitly sets the log level instead through a verbosity.
    pub fn level(mut self, l: LogLevel) -> Self {
        self.level = l;
        self
    }

    /// Enables or disables including the module path in the "tag" portion of the log statement.
    /// The tag is the text to the left of the separator.
    pub fn module_path(mut self, m: bool) -> Self {
        self.module_path = m;
        self
    }

    /// Converts the verbosity to a log level.
    ///
    /// A verbosity of zero (0) is the default, which means ERROR and WARN log statements are
    /// printed to `stderr`. No other log statements are printed on any of the standard streams
    /// (`stdout` or `stderr`). As the verbosity is increased, the log level is increased and more
    /// log statements will be printed to `stdout`. A verbosity of 1 will print INFO log statements
    /// to `stdout` in addition to ERROR and WARN. A verbosity of 2 will print INFO and DEBUG log
    /// statements to `stdout`. A verbosity of 3 or higher will print INFO, DEBUG, and TRACE
    /// log statements to `stdout` with ERROR and WARN statements printed to `stderr`.
    pub fn verbosity(mut self, v: u64) -> Self {
        self.level = match v {
                0 => LogLevel::Warn,  // default
                1 => LogLevel::Info,  // -v
                2 => LogLevel::Debug, // -vv
                _ => LogLevel::Trace, // -vvv and above
        };
        self
    }

    /// Initializes the logger.
    ///
    /// This also consumes the logger and cannot no longer be modified after initialization.
    pub fn init(self) -> Result<(), SetLoggerError> {
        log::set_logger(|max_level| {
            max_level.set(self.level.to_log_level_filter());
            Box::new(self)
        })
    }
}

impl Log for Logger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let level = record.level();
            let module_path = if self.module_path {
                format!(" [{}]", record.location().module_path())
            } else {
                String::new()
            };
            let line = if self.line_numbers {
                format!(" (line {})", record.location().line())
            } else {
                String::new()
            };
            let tag = if self.colors {
                self.color(&level).paint(format!("{}{}{}", level, module_path, line)).to_string()
            } else {
                format!("{}{}{}", level, module_path, line)
            };
            if level <= LogLevel::Warn {
                let _ = writeln!(&mut io::stderr(), "{}{}{}", tag, self.separator, record.args());
            } else {
                println!("{}{}{}", tag, self.separator, record.args());
            }
        }
    }
}

impl Default for Logger {
    fn default() -> Logger {
        Logger::new()
    }
}

/// Initialize loggerv with a maximal log level.
///
/// See the main loggerv documentation page for an example.
pub fn init_with_level(level: LogLevel) -> Result<(), SetLoggerError> {
    Logger::new().level(level).init()
}

/// Initialize loggerv with a verbosity level.
///
/// Intended to be used with an arg parser counting the amount of -v flags.
/// See the main loggerv documentation page for an example.
pub fn init_with_verbosity(verbosity: u64) -> Result<(), SetLoggerError> {
    Logger::new().verbosity(verbosity).init()
}

/// Initializes loggerv with only warnings and errors.
///
/// See the main loggerv documentation page for an example.
pub fn init_quiet() -> Result<(), SetLoggerError> {
    init_with_level(LogLevel::Warn)
}

#[cfg(test)]
mod tests {
    use init_with_verbosity;

    #[test]
    fn init_and_macros() {
        let l = init_with_verbosity(3);
        assert_eq!(l.is_ok(), true);
        error!("error log");
        warn!("warn log");
        info!("info log");
        debug!("debug log");
        trace!("trace log");
    }
}
<|endoftext|>