<commit_before>use byteorder::{BigEndian, ReaderBytesExt, WriterBytesExt};

use rustc_serialize::Encodable;
use rustc_serialize::Encoder;
use rustc_serialize::json;

use openssl;
use openssl::ssl;
use openssl::ssl::SslStream;
use openssl::ssl::error::SslError;

use std::cell::RefCell;
use std::num::Int;
use std::ops::{Range, Index};
use std::old_io::net;
use std::old_io::net::ip::SocketAddr;
use std::old_io::{TcpStream, MemReader};
use std::old_path::posix::Path;
use std::collections::HashMap;

use rand::{self, Rng};
use time;

#[derive(Debug)]
pub struct Payload<'a> {
	pub aps: PayloadAPS<'a>,
	pub info: Option<HashMap<&'a str, &'a str>>
}

#[derive(Debug)]
pub struct PayloadAPS<'a> {
	pub alert: PayloadAPSAlert<'a>,
	pub badge: Option<i32>,
	pub sound: Option<&'a str>,
	pub content_available: Option<i32>
}

#[derive(Debug)]
pub enum PayloadAPSAlert<'a> {
	Plain(&'a str),
	Localized(&'a str, Vec<&'a str>)
}

impl<'a> Encodable for Payload<'a> {
	fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
	    match *self {
			Payload{ref aps, ref info} => {
				if let Some(ref map) = *info {
	    	        encoder.emit_struct("Payload", 1 + map.len(), |encoder| {
						try!(encoder.emit_struct_field( "aps", 0usize, |encoder| aps.encode(encoder)));
						let mut index = 1usize;
						for (key, val) in map.iter() {
							try!(encoder.emit_struct_field(key, index, |encoder| val.encode(encoder)));
							index = index + 1;
						}
						Ok(())
	    	        })
				}
				else {
	    	        encoder.emit_struct("Payload", 1, |encoder| {
						try!(encoder.emit_struct_field( "aps", 0usize, |encoder| aps.encode(encoder)));
						Ok(())
	    	        })
				}
			}
		}
	}
}

impl<'a> Encodable for PayloadAPS<'a> {
	fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
	    match *self {
			PayloadAPS{ref alert, ref badge, ref sound, ref content_available} => {
				let mut count = 1;
				if badge.is_some() { count = count + 1; }
				if sound.is_some() { count = count + 1; }
				if content_available.is_some() { count = count + 1; }

				let mut index = 0usize;
    	        encoder.emit_struct("PayloadAPS", count, |encoder| {
					try!(encoder.emit_struct_field( "alert", index, |encoder| alert.encode(encoder)));
					index = index + 1;
					if badge.is_some() {
						try!(encoder.emit_struct_field( "badge", index, |encoder| badge.unwrap().encode(encoder)));
						index = index + 1;
					}
					if sound.is_some() {
						try!(encoder.emit_struct_field( "sound", index, |encoder| sound.unwrap().encode(encoder)));
						index = index + 1;
					}
					if content_available.is_some() {
						try!(encoder.emit_struct_field( "content-available", index, |encoder| content_available.unwrap().encode(encoder)));
						index = index + 1;
					}
					Ok(())
    	        })
			}
		}
	}
}

impl<'a> Encodable for PayloadAPSAlert<'a> {
	fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
	    match *self {
			PayloadAPSAlert::Plain(ref str) => {
    	        encoder.emit_str(str)
			},
			PayloadAPSAlert::Localized(ref key, ref args) => {
    	        encoder.emit_struct("PayloadAPSAlert", 2, |encoder| {
					try!(encoder.emit_struct_field( "loc-key", 0usize, |encoder| key.encode(encoder)));
					try!(encoder.emit_struct_field( "loc-args", 1usize, |encoder| args.encode(encoder)));
					Ok(())
				})
			}
		}
	}
}

#[allow(dead_code)]
fn hex_to_int(hex: &str) -> u32 {
	let mut total = 0u32;
	let mut n = hex.to_string().len() - 1;

	for c in hex.chars() {
		match c {
			'0'...'9' => {
				total += 16.pow(n) * ((c as u32) - ('0' as u32));
			},
			'a'...'f' => {
				total += 16.pow(n) * ((c as u32) - ('a' as u32) + 10);
			},
			_ => {
			}
		}
		n = n - 1;
	}

	return total;
}

#[allow(dead_code)]
fn convert_to_binary(device_token: &str) -> Vec<u8> {
	let mut device_token_bytes: Vec<u8> = vec![];
	for i in 0..8 {
		let string = device_token.to_string();
		let range = Range{start:i*8, end:i*8+8};
		let sub_str = string.index(&range);

		let sub_str_num = hex_to_int(sub_str);
		let mut sub_str_bytes = vec![];
		let _ = sub_str_bytes.write_u32::<BigEndian>(sub_str_num);

		device_token_bytes.push_all(sub_str_bytes.as_slice());
	}

	return device_token_bytes;
}

#[allow(dead_code)]
pub fn convert_to_token(binary: &[u8]) -> String {
	let mut token = "".to_string();
	for i in 0..8 {
		let range = Range{start:i*4, end:i*4+4};
		let sub_slice = binary.index(&range);

		let mut rdr = MemReader::new(sub_slice.to_vec());
		let num = rdr.read_u32::<BigEndian>().unwrap();

		token = format!("{}{:x}", token, num);
	}
	return token;
}

#[allow(dead_code)]
pub fn convert_to_timestamp(binary: &[u8]) -> u32 {
	let mut rdr = MemReader::new(binary.to_vec());
	let num = rdr.read_u32::<BigEndian>().unwrap();

	return num;
}

pub struct APNS {
	pub sandbox: bool,
	pub certificate: Path,
	pub private_key: Path,
	pub ca_certificate: Path,
	pub ssl_stream: RefCell<Option<SslStream<TcpStream>>>
}

impl APNS {
	pub fn new(sandbox: bool, cert_file: Path, private_key_file: Path, ca_file: Path) -> APNS {
		APNS{sandbox: sandbox, certificate: cert_file, private_key: private_key_file, ca_certificate: ca_file, ssl_stream: RefCell::new(None)}
	}

	#[allow(dead_code)]
    pub fn get_feedback(&self) -> Result<Vec<(u32, String)>, SslError> {
		let apns_feedback_production = "feedback.push.apple.com";
		let apns_feedback_development = "feedback.sandbox.push.apple.com";
		let feedback_port = 2196;

		let apns_feedback_url = if self.sandbox { apns_feedback_development } else { apns_feedback_production };
		let mut stream = try!(get_ssl_stream(apns_feedback_url, feedback_port, &self.certificate, &self.private_key, &self.ca_certificate));

		let mut tokens: Vec<(u32, String)> = Vec::new();
        loop {
			let mut read_buffer = [0u8; 38];
			if let Err(..) = stream.read(&mut read_buffer) {
				break;
/*				return Result::Err(SslError::StreamError(error));*/
            }

			let time_range = Range{start:0, end:4};
			let time_slice = read_buffer.index(&time_range);
			let time = convert_to_timestamp(time_slice);

			let token_range = Range{start:6, end:38};
			let token_slice = read_buffer.index(&token_range);
            let token = convert_to_token(token_slice);

			tokens.push((time, token));
        }

        return Result::Ok(tokens);
    }

	#[allow(dead_code)]
	pub fn send_payload(&self, payload: Payload, device_token: &str) {
		let payload_str = match json::encode(&payload) {
			Ok(json_str) => { json_str.to_string() }
			_ => { return; }
		};

		let payload_bytes = payload_str.into_bytes();
		let device_token_bytes: Vec<u8> = convert_to_binary(device_token);

		let mut notification_buffer: Vec<u8> = vec![];
		let mut message_buffer: Vec<u8> = vec![];

		// Device token
		let mut device_token_length = vec![];
		let _ = device_token_length.write_u16::<BigEndian>(device_token_bytes.len() as u16);

		message_buffer.push(1u8);
		message_buffer.push_all(device_token_length.as_slice());
		message_buffer.push_all(device_token_bytes.as_slice());

		// Payload
		let mut payload_length = vec![];
		let _ = payload_length.write_u16::<BigEndian>(payload_bytes.len() as u16);

		message_buffer.push(2u8);
		message_buffer.push_all(payload_length.as_slice());
		message_buffer.push_all(payload_bytes.as_slice());

		// Notification identifier
		let payload_id = rand::thread_rng().gen();
		let mut payload_id_be = vec![];
		let _ = payload_id_be.write_u32::<BigEndian>(payload_id);

		let mut payload_id_length = vec![];
		let _ = payload_id_length.write_u16::<BigEndian>(payload_id_be.len() as u16);

		message_buffer.push(3u8);
		message_buffer.push_all(payload_id_length.as_slice());
		message_buffer.push_all(payload_id_be.as_slice());

		//	Expiration date
		let time = time::now().to_timespec().sec + 86400;	// expired after one day
		let mut exp_date_be = vec![];
		let _ = exp_date_be.write_u32::<BigEndian>(time as u32);

		let mut exp_date_length = vec![];
		let _ = exp_date_length.write_u16::<BigEndian>(exp_date_be.len() as u16);

		message_buffer.push(4u8);
		message_buffer.push_all(exp_date_length.as_slice());
		message_buffer.push_all(exp_date_be.as_slice());

		// Priority
		let mut priority_length = vec![];
		let _ = priority_length.write_u16::<BigEndian>(1u16);

		message_buffer.push(5u8);
		message_buffer.push_all(priority_length.as_slice());
		message_buffer.push(10u8);

		let mut message_buffer_length = vec![];
		let _ = message_buffer_length.write_u32::<BigEndian>(message_buffer.len() as u32);

		let command = 2u8;
		notification_buffer.push(command);
		notification_buffer.push_all(message_buffer_length.as_slice());
		notification_buffer.push_all(message_buffer.as_slice());

		if self.ssl_stream.borrow().is_none() {
			let mut borrow_ssl_stream = self.ssl_stream.borrow_mut();
			*borrow_ssl_stream = Some(self.init_push_ssl_stream().unwrap());
		}
		else {
			let mut borrow_ssl_stream = self.ssl_stream.borrow_mut();
			let mut retry_count = 3;
			loop {
				{
					if let Some(mut ssl_stream) = borrow_ssl_stream.as_mut() {
						if let Err(error) = ssl_stream.write_all(&notification_buffer) {
							println!("ssl_stream write error {:?}", error);
						}
						else {
							println!("ssl_stream wrote successfully. {}", payload_id);
							break;
						}

						// Response error code
						/*{
							let mut read_buffer = [0u8; 6];
							println!("SslStream read {:?}", ssl_stream.read(&mut read_buffer));

							for c in read_buffer.iter() {
								print!("{}", c);
							}
							println!("");
						}*/
					}
				}

				if retry_count <= 0 { break; }
				retry_count = retry_count - 1;

				*borrow_ssl_stream = Some(self.init_push_ssl_stream().unwrap());
			}
		}
	}

	fn init_push_ssl_stream(&self) -> Result<SslStream<TcpStream>, SslError> {
		let apns_url_production = "gateway.push.apple.com";
		let apns_url_development = "gateway.sandbox.push.apple.com";
		let apns_port = 2195;

		let apns_url = if self.sandbox { apns_url_development } else { apns_url_production };

		get_ssl_stream(apns_url, apns_port, &self.certificate, &self.private_key, &self.ca_certificate)
	}
}

fn get_ssl_stream(url: &str, port: u16, cert_file: &Path, private_key_file: &Path, ca_file: &Path) -> Result<SslStream<TcpStream>, SslError> {
	let mut context = try!(ssl::SslContext::new(ssl::SslMethod::Sslv23));

	if let Some(error) = context.set_CA_file(&ca_file) {
		println!("set_CA_file error {:?}", error);
	}
	if let Some(error) = context.set_certificate_file(&cert_file, openssl::x509::X509FileType::PEM) {
		println!("set_certificate_file error {:?}", error);
	}
	if let Some(error) = context.set_private_key_file(&private_key_file, openssl::x509::X509FileType::PEM) {
		println!("set_private_key_file error {:?}", error);
	}

	let apns_ip = match net::addrinfo::get_host_addresses(url) {
		Ok(results) => { results[0] },
		Err(error) => {
			return Result::Err(SslError::StreamError(error));
		}
	};

	let sock_addr = SocketAddr{ip: apns_ip, port: port};
    let tcp_conn = match TcpStream::connect(sock_addr) {
		Ok(conn) => { conn },
		Err(error) => {
			return Result::Err(SslError::StreamError(error));
		}
	};

	let ssl = try!(ssl::Ssl::new(&context));

	return SslStream::new_from(ssl, tcp_conn);
}

<commit_msg>revert some previous changes<commit_after>use byteorder::{BigEndian, ReaderBytesExt, WriterBytesExt};

use rustc_serialize::Encodable;
use rustc_serialize::Encoder;
use rustc_serialize::json;

use openssl;
use openssl::ssl;
use openssl::ssl::SslStream;
use openssl::ssl::error::SslError;

use std::cell::RefCell;
use std::num::Int;
use std::ops::{Range, Index};
use std::old_io::net;
use std::old_io::net::ip::SocketAddr;
use std::old_io::{TcpStream, MemReader};
use std::old_path::posix::Path;
use std::collections::HashMap;

use rand::{self, Rng};
use time;

#[derive(Debug)]
pub struct Payload<'a> {
	pub aps: PayloadAPS<'a>,
	pub info: Option<HashMap<&'a str, &'a str>>
}

#[derive(Debug)]
pub struct PayloadAPS<'a> {
	pub alert: PayloadAPSAlert<'a>,
	pub badge: Option<i32>,
	pub sound: Option<&'a str>,
	pub content_available: Option<i32>
}

#[derive(Debug)]
pub enum PayloadAPSAlert<'a> {
	Plain(&'a str),
	Localized(&'a str, Vec<&'a str>)
}

impl<'a> Encodable for Payload<'a> {
	fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
	    match *self {
			Payload{ref aps, ref info} => {
				if let Some(ref map) = *info {
	    	        encoder.emit_struct("Payload", 1 + map.len(), |encoder| {
						try!(encoder.emit_struct_field( "aps", 0usize, |encoder| aps.encode(encoder)));
						let mut index = 1usize;
						for (key, val) in map.iter() {
							try!(encoder.emit_struct_field(key, index, |encoder| val.encode(encoder)));
							index = index + 1;
						}
						Ok(())
	    	        })
				}
				else {
	    	        encoder.emit_struct("Payload", 1, |encoder| {
						try!(encoder.emit_struct_field( "aps", 0usize, |encoder| aps.encode(encoder)));
						Ok(())
	    	        })
				}
			}
		}
	}
}

impl<'a> Encodable for PayloadAPS<'a> {
	fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
	    match *self {
			PayloadAPS{ref alert, ref badge, ref sound, ref content_available} => {
				let mut count = 1;
				if badge.is_some() { count = count + 1; }
				if sound.is_some() { count = count + 1; }
				if content_available.is_some() { count = count + 1; }

				let mut index = 0usize;
    	        encoder.emit_struct("PayloadAPS", count, |encoder| {
					try!(encoder.emit_struct_field( "alert", index, |encoder| alert.encode(encoder)));
					index = index + 1;
					if badge.is_some() {
						try!(encoder.emit_struct_field( "badge", index, |encoder| badge.unwrap().encode(encoder)));
						index = index + 1;
					}
					if sound.is_some() {
						try!(encoder.emit_struct_field( "sound", index, |encoder| sound.unwrap().encode(encoder)));
						index = index + 1;
					}
					if content_available.is_some() {
						try!(encoder.emit_struct_field( "content-available", index, |encoder| content_available.unwrap().encode(encoder)));
						index = index + 1;
					}
					Ok(())
    	        })
			}
		}
	}
}

impl<'a> Encodable for PayloadAPSAlert<'a> {
	fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
	    match *self {
			PayloadAPSAlert::Plain(ref str) => {
    	        encoder.emit_str(str)
			},
			PayloadAPSAlert::Localized(ref key, ref args) => {
    	        encoder.emit_struct("PayloadAPSAlert", 2, |encoder| {
					try!(encoder.emit_struct_field( "loc-key", 0usize, |encoder| key.encode(encoder)));
					try!(encoder.emit_struct_field( "loc-args", 1usize, |encoder| args.encode(encoder)));
					Ok(())
				})
			}
		}
	}
}

#[allow(dead_code)]
fn hex_to_int(hex: &str) -> u32 {
	let mut total = 0u32;
	let mut n = hex.to_string().len() - 1;

	for c in hex.chars() {
		match c {
			'0'...'9' => {
				total += 16.pow(n) * ((c as u32) - ('0' as u32));
			},
			'a'...'f' => {
				total += 16.pow(n) * ((c as u32) - ('a' as u32) + 10);
			},
			_ => {
			}
		}
		n = n - 1;
	}

	return total;
}

#[allow(dead_code)]
fn convert_to_binary(device_token: &str) -> Vec<u8> {
	let mut device_token_bytes: Vec<u8> = vec![];
	for i in 0..8 {
		let string = device_token.to_string();
		let range = Range{start:i*8, end:i*8+8};
		let sub_str = string.index(&range);

		let sub_str_num = hex_to_int(sub_str);
		let mut sub_str_bytes = vec![];
		let _ = sub_str_bytes.write_u32::<BigEndian>(sub_str_num);

		device_token_bytes.push_all(sub_str_bytes.as_slice());
	}

	return device_token_bytes;
}

#[allow(dead_code)]
pub fn convert_to_token(binary: &[u8]) -> String {
	let mut token = "".to_string();
	for i in 0..8 {
		let range = Range{start:i*4, end:i*4+4};
		let sub_slice = binary.index(&range);

		let mut rdr = MemReader::new(sub_slice.to_vec());
		let num = rdr.read_u32::<BigEndian>().unwrap();

		token = format!("{}{:x}", token, num);
	}
	return token;
}

#[allow(dead_code)]
pub fn convert_to_timestamp(binary: &[u8]) -> u32 {
	let mut rdr = MemReader::new(binary.to_vec());
	let num = rdr.read_u32::<BigEndian>().unwrap();

	return num;
}

pub struct APNS {
	pub sandbox: bool,
	pub certificate: Path,
	pub private_key: Path,
	pub ca_certificate: Path,
	pub ssl_stream: RefCell<Option<SslStream<TcpStream>>>
}

impl APNS {
	pub fn new(sandbox: bool, cert_file: Path, private_key_file: Path, ca_file: Path) -> APNS {
		APNS{sandbox: sandbox, certificate: cert_file, private_key: private_key_file, ca_certificate: ca_file, ssl_stream: RefCell::new(None)}
	}

	#[allow(dead_code)]
    pub fn get_feedback(&self) -> Result<Vec<(u32, String)>, SslError> {
		let apns_feedback_production = "feedback.push.apple.com";
		let apns_feedback_development = "feedback.sandbox.push.apple.com";
		let feedback_port = 2196;

		let apns_feedback_url = if self.sandbox { apns_feedback_development } else { apns_feedback_production };
		let mut stream = try!(get_ssl_stream(apns_feedback_url, feedback_port, &self.certificate, &self.private_key, &self.ca_certificate));

		let mut tokens: Vec<(u32, String)> = Vec::new();
        loop {
			let mut read_buffer = [0u8; 38];
			if let Err(..) = stream.read(&mut read_buffer) {
				break;
/*				return Result::Err(SslError::StreamError(error));*/
            }

			let time_range = Range{start:0, end:4};
			let time_slice = read_buffer.index(&time_range);
			let time = convert_to_timestamp(time_slice);

			let token_range = Range{start:6, end:38};
			let token_slice = read_buffer.index(&token_range);
            let token = convert_to_token(token_slice);

			tokens.push((time, token));
        }

        return Result::Ok(tokens);
    }

	#[allow(dead_code)]
	pub fn send_payload(&self, payload: Payload, device_token: &str) {
		let payload_str = match json::encode(&payload) {
			Ok(json_str) => { json_str.to_string() }
			_ => { return; }
		};

		let payload_bytes = payload_str.into_bytes();
		let device_token_bytes: Vec<u8> = convert_to_binary(device_token);

		let mut notification_buffer: Vec<u8> = vec![];
		let mut message_buffer: Vec<u8> = vec![];

		// Device token
		let mut device_token_length = vec![];
		let _ = device_token_length.write_u16::<BigEndian>(device_token_bytes.len() as u16);

		message_buffer.push(1u8);
		message_buffer.push_all(device_token_length.as_slice());
		message_buffer.push_all(device_token_bytes.as_slice());

		// Payload
		let mut payload_length = vec![];
		let _ = payload_length.write_u16::<BigEndian>(payload_bytes.len() as u16);

		message_buffer.push(2u8);
		message_buffer.push_all(payload_length.as_slice());
		message_buffer.push_all(payload_bytes.as_slice());

		// Notification identifier
		let payload_id = rand::thread_rng().gen();
		let mut payload_id_be = vec![];
		let _ = payload_id_be.write_u32::<BigEndian>(payload_id);

		let mut payload_id_length = vec![];
		let _ = payload_id_length.write_u16::<BigEndian>(payload_id_be.len() as u16);

		message_buffer.push(3u8);
		message_buffer.push_all(payload_id_length.as_slice());
		message_buffer.push_all(payload_id_be.as_slice());

		//	Expiration date
		let time = time::now().to_timespec().sec + 86400;	// expired after one day
		let mut exp_date_be = vec![];
		let _ = exp_date_be.write_u32::<BigEndian>(time as u32);

		let mut exp_date_length = vec![];
		let _ = exp_date_length.write_u16::<BigEndian>(exp_date_be.len() as u16);

		message_buffer.push(4u8);
		message_buffer.push_all(exp_date_length.as_slice());
		message_buffer.push_all(exp_date_be.as_slice());

		// Priority
		let mut priority_length = vec![];
		let _ = priority_length.write_u16::<BigEndian>(1u16);

		message_buffer.push(5u8);
		message_buffer.push_all(priority_length.as_slice());
		message_buffer.push(10u8);

		let mut message_buffer_length = vec![];
		let _ = message_buffer_length.write_u32::<BigEndian>(message_buffer.len() as u32);

		let command = 2u8;
		notification_buffer.push(command);
		notification_buffer.push_all(message_buffer_length.as_slice());
		notification_buffer.push_all(message_buffer.as_slice());

		let should_init_ssl_stream = self.ssl_stream.borrow().is_none();

		if should_init_ssl_stream {
			self.init_push_ssl_stream();
		}
		else {
			if let Some(ssl_stream) = self.ssl_stream.borrow_mut().as_mut() {
				while let Err(error) = ssl_stream.write_all(&notification_buffer) {
					println!("ssl_stream write error {:?}", error);
/*		            self.init_push_ssl_stream();*/
				}

				// Response error code
				/*let mut read_buffer = [0u8; 6];
				println!("SslStream read {:?}", ssl_stream.read(&mut read_buffer));

				for c in read_buffer.iter() {
					print!("{}", c);
				}
				println!("");*/
			}
		}
	}

	fn init_push_ssl_stream(&self) {
		let mut borrow_ssl_stream = self.ssl_stream.borrow_mut();

		let apns_url_production = "gateway.push.apple.com";
		let apns_url_development = "gateway.sandbox.push.apple.com";
		let apns_port = 2195;

		let apns_url = if self.sandbox { apns_url_development } else { apns_url_production };

		*borrow_ssl_stream = Some(get_ssl_stream(apns_url, apns_port, &self.certificate, &self.private_key, &self.ca_certificate).unwrap());
	}
}

fn get_ssl_stream(url: &str, port: u16, cert_file: &Path, private_key_file: &Path, ca_file: &Path) -> Result<SslStream<TcpStream>, SslError> {
	let mut context = try!(ssl::SslContext::new(ssl::SslMethod::Sslv23));

	if let Some(error) = context.set_CA_file(&ca_file) {
		println!("set_CA_file error {:?}", error);
	}
	if let Some(error) = context.set_certificate_file(&cert_file, openssl::x509::X509FileType::PEM) {
		println!("set_certificate_file error {:?}", error);
	}
	if let Some(error) = context.set_private_key_file(&private_key_file, openssl::x509::X509FileType::PEM) {
		println!("set_private_key_file error {:?}", error);
	}

	let apns_ip = match net::addrinfo::get_host_addresses(url) {
		Ok(results) => { results[0] },
		Err(error) => {
			return Result::Err(SslError::StreamError(error));
		}
	};

	let sock_addr = SocketAddr{ip: apns_ip, port: port};
    let tcp_conn = match TcpStream::connect(sock_addr) {
		Ok(conn) => { conn },
		Err(error) => {
			return Result::Err(SslError::StreamError(error));
		}
	};

	let ssl = try!(ssl::Ssl::new(&context));

	return SslStream::new_from(ssl, tcp_conn);
}

<|endoftext|>


<commit_before>use std::io::Read;
use std::fs;
use std::env;
use std::path::PathBuf;

#[cfg(unix)] use std::os::unix::fs::MetadataExt;

use flate2::read::GzDecoder;
use tar::Archive;
use curl::http;
use time;

use error::TldrError::{self, CacheError, UpdateError};
use types::OsType;

#[derive(Debug)]
pub struct Cache {
    url: String,
    os: OsType,
}

impl Cache {

    pub fn new<S>(url: S, os: OsType) -> Cache where S: Into<String> {
        Cache {
            url: url.into(),
            os: os,
        }
    }

    /// Return the path to the cache directory.
    fn get_cache_dir(&self) -> Result<PathBuf, TldrError> {
        let home_dir = try!(env::home_dir().ok_or(CacheError("Could not determine home directory".into())));
        Ok(home_dir.join(".cache").join("tldr-rs"))
    }

    /// Download the archive
    fn download(&self) -> Result<http::Response, TldrError> {
        let resp = try!(
            http::handle()
                 .follow_location(1)
                 .get(&self.url[..])
                 .exec()
        );
        Ok(resp)
    }

    /// Decompress and open the archive
    fn decompress<R: Read>(&self, reader: R) -> Result<Archive<GzDecoder<R>>, TldrError> {
        let decoder = try!(GzDecoder::new(reader).map_err(|_| UpdateError("Could not decode gzip data".into())));
        Ok(Archive::new(decoder))
    }

    /// Update the pages cache. Return the number of cached pages.
    pub fn update(&self) -> Result<(), TldrError> {
        // First, download the compressed data
        let response = try!(self.download());

        // Decompress the response body into an `Archive`
        let mut archive = try!(self.decompress(response.get_body()));

        // Determine paths
        let cache_dir = try!(self.get_cache_dir());

        // Extract archive
        try!(archive.unpack(&cache_dir).map_err(|e| {
            UpdateError(format!("Could not unpack compressed data: {}", e))
        }));

        // Make sure that cache directory exists
        debug!("Ensure cache directory {:?} exists", &cache_dir);
        try!(fs::create_dir_all(&cache_dir).map_err(|e| {
            UpdateError(format!("Could not create cache directory: {}", e))
        }));

        Ok(())
    }

    #[cfg(unix)]
    /// Return the number of seconds since the cache directory was last modified.
    pub fn last_update(&self) -> Option<i64> {
        if let Ok(cache_dir) = self.get_cache_dir() {
            if let Ok(metadata) = fs::metadata(cache_dir) {
                let mtime = metadata.mtime();
                let now = time::now_utc().to_timespec();
                return Some(now.sec - mtime)
            };
        };
        None
    }

    /// Return the platform directory.
    fn get_platform_dir(&self) -> Option<&'static str> {
        match self.os {
            OsType::Linux => Some("linux"),
            OsType::OsX => Some("osx"),
            OsType::SunOs => None, // TODO: Does Rust support SunOS?
            OsType::Other => None,
        }
    }

    /// Search for a page and return the path to it.
    pub fn find_page(&self, name: &str) -> Option<PathBuf> {
        // Build page file name
        let page_filename = format!("{}.md", name);

        // Get platform dir
        let cache_dir = match self.get_cache_dir() {
            Ok(dir) => dir,
            Err(_) => return None,
        };
        let platforms_dir = cache_dir.join("tldr-master").join("pages");

        // Determine platform
        let platform = self.get_platform_dir();

        // Search for the page in the platform specific directory
        if let Some(pf) = platform {
            let path = platforms_dir.join(&pf).join(&page_filename);
            if path.exists() && path.is_file() {
                return Some(path);
            }
        }

        // If platform is not supported or if platform specific page does not exist,
        // look up the page in the "common" directory.
        let path = platforms_dir.join("common").join(&page_filename);

        // Return it if it exists, otherwise give up and return `None`
        if path.exists() && path.is_file() {
            Some(path)
        } else {
            None
        }
    }

    /// Delete the cache directory.
    pub fn clear(&self) -> Result<(), TldrError> {
        let path = try!(self.get_cache_dir());
        if path.exists() && path.is_dir() {
            try!(fs::remove_dir_all(&path).map_err(|_| {
                CacheError(format!("Could not remove cache directory ({}).", path.display()))
            }));
        } else if path.exists() {
            return Err(CacheError(format!("Cache path ({}) is not a directory.", path.display())));
        } else {
            return Err(CacheError(format!("Cache path ({}) does not exist.", path.display())));
        };
        Ok(())
    }

}
<commit_msg>Simplify logic in Cache::find_page<commit_after>use std::io::Read;
use std::fs;
use std::env;
use std::path::PathBuf;

#[cfg(unix)] use std::os::unix::fs::MetadataExt;

use flate2::read::GzDecoder;
use tar::Archive;
use curl::http;
use time;

use error::TldrError::{self, CacheError, UpdateError};
use types::OsType;

#[derive(Debug)]
pub struct Cache {
    url: String,
    os: OsType,
}

impl Cache {

    pub fn new<S>(url: S, os: OsType) -> Cache where S: Into<String> {
        Cache {
            url: url.into(),
            os: os,
        }
    }

    /// Return the path to the cache directory.
    fn get_cache_dir(&self) -> Result<PathBuf, TldrError> {
        let home_dir = try!(env::home_dir().ok_or(CacheError("Could not determine home directory".into())));
        Ok(home_dir.join(".cache").join("tldr-rs"))
    }

    /// Download the archive
    fn download(&self) -> Result<http::Response, TldrError> {
        let resp = try!(
            http::handle()
                 .follow_location(1)
                 .get(&self.url[..])
                 .exec()
        );
        Ok(resp)
    }

    /// Decompress and open the archive
    fn decompress<R: Read>(&self, reader: R) -> Result<Archive<GzDecoder<R>>, TldrError> {
        let decoder = try!(GzDecoder::new(reader).map_err(|_| UpdateError("Could not decode gzip data".into())));
        Ok(Archive::new(decoder))
    }

    /// Update the pages cache. Return the number of cached pages.
    pub fn update(&self) -> Result<(), TldrError> {
        // First, download the compressed data
        let response = try!(self.download());

        // Decompress the response body into an `Archive`
        let mut archive = try!(self.decompress(response.get_body()));

        // Determine paths
        let cache_dir = try!(self.get_cache_dir());

        // Extract archive
        try!(archive.unpack(&cache_dir).map_err(|e| {
            UpdateError(format!("Could not unpack compressed data: {}", e))
        }));

        // Make sure that cache directory exists
        debug!("Ensure cache directory {:?} exists", &cache_dir);
        try!(fs::create_dir_all(&cache_dir).map_err(|e| {
            UpdateError(format!("Could not create cache directory: {}", e))
        }));

        Ok(())
    }

    #[cfg(unix)]
    /// Return the number of seconds since the cache directory was last modified.
    pub fn last_update(&self) -> Option<i64> {
        if let Ok(cache_dir) = self.get_cache_dir() {
            if let Ok(metadata) = fs::metadata(cache_dir) {
                let mtime = metadata.mtime();
                let now = time::now_utc().to_timespec();
                return Some(now.sec - mtime)
            };
        };
        None
    }

    /// Return the platform directory.
    fn get_platform_dir(&self) -> Option<&'static str> {
        match self.os {
            OsType::Linux => Some("linux"),
            OsType::OsX => Some("osx"),
            OsType::SunOs => None, // TODO: Does Rust support SunOS?
            OsType::Other => None,
        }
    }

    /// Search for a page and return the path to it.
    pub fn find_page(&self, name: &str) -> Option<PathBuf> {
        // Build page file name
        let page_filename = format!("{}.md", name);

        // Get platform dir
        let platforms_dir = match self.get_cache_dir() {
            Ok(cache_dir) => cache_dir.join("tldr-master").join("pages"),
            _ => return None,
        };

        // Determine platform
        let platform = self.get_platform_dir();

        // Search for the page in the platform specific directory
        if let Some(pf) = platform {
            let path = platforms_dir.join(&pf).join(&page_filename);
            if path.exists() && path.is_file() {
                return Some(path);
            }
        }

        // If platform is not supported or if platform specific page does not exist,
        // look up the page in the "common" directory.
        let path = platforms_dir.join("common").join(&page_filename);

        // Return it if it exists, otherwise give up and return `None`
        if path.exists() && path.is_file() {
            Some(path)
        } else {
            None
        }
    }

    /// Delete the cache directory.
    pub fn clear(&self) -> Result<(), TldrError> {
        let path = try!(self.get_cache_dir());
        if path.exists() && path.is_dir() {
            try!(fs::remove_dir_all(&path).map_err(|_| {
                CacheError(format!("Could not remove cache directory ({}).", path.display()))
            }));
        } else if path.exists() {
            return Err(CacheError(format!("Cache path ({}) is not a directory.", path.display())));
        } else {
            return Err(CacheError(format!("Cache path ({}) does not exist.", path.display())));
        };
        Ok(())
    }

}
<|endoftext|>


<commit_before>use termion::color;
use std::fmt;
use rand::{Rng, thread_rng};
use std::slice::Iter;
use atty;

#[derive(Debug, Clone, Copy)]
#[repr(usize)]
pub enum ColorMode {
    Plain = 0,
    RedBlack = 1,
    Unique = 2
}

static mut SUIT_COLOR_MODE: ColorMode = ColorMode::Unique;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Color {
    Black,
    Red
}

#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Suit {
    Clubs = 0,
    Diamonds = 1,
    Hearts = 2,
    Spades = 3
}

impl Suit {
    pub fn color(&self) -> Color {
        match *self {
            Suit::Diamonds | Suit::Hearts => Color::Red,
            _ => Color::Black
        }
    }

    pub fn ord(&self) -> u8 {
        *self as u8
    }
}

impl fmt::Display for Suit {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Suit::*;

        lazy_static! {
            static ref RED: String = format!("{}", color::Fg(color::Red));
            static ref GREEN: String = format!("{}", color::Fg(color::Green));
            static ref BLUE: String = format!("{}", color::Fg(color::Blue));
            static ref RESET: String = format!("{}", color::Fg(color::Reset));
        }

        let (begin, end) = unsafe {
            match SUIT_COLOR_MODE {
                ColorMode::Plain => ("", ""),
                ColorMode::RedBlack => match self.color() {
                    Color::Red => (RED.as_str(), RESET.as_str()),
                    _ => ("", "")
                },
                ColorMode::Unique => match *self {
                    Clubs => (GREEN.as_str(), RESET.as_str()),
                    Hearts => (RED.as_str(), RESET.as_str()),
                    Diamonds => (BLUE.as_str(), RESET.as_str()),
                    _ => ("", "")
                }
            }
        };

        write!(f, "{}{}{}", begin, match *self {
            Clubs => "♣",
            Diamonds => "♦",
            Hearts => "♥",
            Spades => "♠"
        }, end)
    }
}

#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Rank {
    Two = 2,
    Three = 3,
    Four = 4,
    Five = 5,
    Six = 6,
    Seven = 7,
    Eight = 8,
    Nine = 9,
    Ten = 10,
    Jack = 11,
    Queen = 12,
    King = 13,
    Ace = 14
}

impl Rank {
    pub fn iterator() -> Iter<'static, Rank> {
        use Rank::*;
        static RANKS: [Rank;  13] = [Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace];
        RANKS.into_iter()
    }
    /// Assign numerical values to each rank, with ace as high
    pub fn ord_ace_high(&self) -> u8 {
        *self as u8
    }

    /// Assign numerical values to each rank, with ace as low
    pub fn ord_ace_low(&self) -> u8 {
        use Rank::*;
        match *self {
            Ace => 1,
            x => x as u8
        }
    }
}

impl fmt::Display for Rank {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Rank::*;
        write!(f, "{}", match *self {
            Two => "2",
            Three => "3",
            Four => "4",
            Five => "5",
            Six => "6",
            Seven => "7",
            Eight => "8",
            Nine => "9",
            Ten => "T",
            Jack => "J",
            Queen => "Q",
            King => "K",
            Ace => "A"
        })
    }
}

/// Normal non-joker playing card
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BasicCard {
    pub rank: Rank,
    pub suit: Suit
}

impl BasicCard {
    /// Returns a Vec of all 52 possible `BasicCard`s, in
    /// some unspecified order.
    pub fn all() -> Vec<BasicCard> {
        use Rank::*;
        use Suit::*;

        let mut cards = Vec::with_capacity(52);
        for rank in &[Two, Three, Four, Five, Six, Seven, Eight,
                      Nine, Ten, Jack, Queen, King, Ace] {
            for suit in &[Clubs, Diamonds, Hearts, Spades] {
                cards.push(BasicCard { rank: *rank, suit: *suit })
            }
        }

        cards
    }
}

impl fmt::Display for BasicCard {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}{}", self.rank, self.suit)
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Card {
    Basic(BasicCard),
    BigJoker,
    SmallJoker
}

impl fmt::Display for Card {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Card::*;
        match self {
            &BigJoker => write!(f, "JJ"),
            &SmallJoker => write!(f, "jj"),
            &Card::Basic(ref basic) => write!(f, "{}", basic)
        }
    }
}

/// Deck of 52 basic (non-joker) cards
#[derive(Debug)]
pub struct BasicDeck {
    cards: Vec<BasicCard>
}

impl BasicDeck {
    pub fn new() -> BasicDeck {
        BasicDeck { cards: BasicCard::all() }
    }

    /// Shuffle the remaining cards in the deck
    pub fn shuffle(&mut self) {
        let mut rng = thread_rng();
        rng.shuffle(&mut self.cards)
    }

    pub fn num_cards_left(&self) -> usize {
        self.cards.len()
    }

    /// Return the top card from the deck, if there are any cards
    pub fn draw(&mut self) -> Option<BasicCard> {
        self.cards.pop()
    }

    /// Return the top n cards from the deck, if there are n
    /// cards. Otherwise, return None.
    ///
    /// # Remarks
    ///
    /// If this function returns `Some`, there will be
    /// exactly `n` cards.
    pub fn draw_n(&mut self, n: usize) -> Option<Vec<BasicCard>> {
        let m = self.cards.len();
        if m >= n {
            Some(self.cards.split_off(m - n))
        } else {
            None
        }
    }

}

pub fn auto_suit_colors() {
    unsafe {
        SUIT_COLOR_MODE = if atty::is(atty::Stream::Stdout) {
            ColorMode::Unique
        } else {
            ColorMode::Plain
        }
    }
}
<commit_msg>parse basic cards from strings<commit_after>use termion::color;
use std::str::FromStr;
use std::fmt;
use rand::{Rng, thread_rng};
use std::slice::Iter;
use atty;

#[derive(Debug, Clone, Copy)]
#[repr(usize)]
pub enum ColorMode {
    Plain = 0,
    RedBlack = 1,
    Unique = 2
}

static mut SUIT_COLOR_MODE: ColorMode = ColorMode::Unique;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Color {
    Black,
    Red
}

#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Suit {
    Clubs = 0,
    Diamonds = 1,
    Hearts = 2,
    Spades = 3
}

impl Suit {
    /// iterate through all elements of suit
    pub fn iterator() -> Iter<'static, Suit> {
        use Suit::*;
        static ALL_SUITS: [Suit; 4] = [Clubs, Diamonds, Hearts, Spades];
        ALL_SUITS.into_iter()
    }

    pub fn color(&self) -> Color {
        match *self {
            Suit::Diamonds | Suit::Hearts => Color::Red,
            _ => Color::Black
        }
    }

    pub fn ord(&self) -> u8 {
        *self as u8
    }
}

#[derive(Debug)]
pub enum CardParseError {
    BadSuit,
    BadRank
}

impl FromStr for Suit {
    type Err = CardParseError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Suit::*;
        use self::CardParseError::*;
        match s {
            "♣" => Ok(Clubs),
            "♦" => Ok(Hearts),
            "♥" => Ok(Diamonds),
            "♠" => Ok(Spades),
            _ => Err(BadSuit)
        }
    }
}

impl fmt::Display for Suit {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Suit::*;

        lazy_static! {
            static ref RED: String = format!("{}", color::Fg(color::Red));
            static ref GREEN: String = format!("{}", color::Fg(color::Green));
            static ref BLUE: String = format!("{}", color::Fg(color::Blue));
            static ref RESET: String = format!("{}", color::Fg(color::Reset));
        }

        let (begin, end) = unsafe {
            match SUIT_COLOR_MODE {
                ColorMode::Plain => ("", ""),
                ColorMode::RedBlack => match self.color() {
                    Color::Red => (RED.as_str(), RESET.as_str()),
                    _ => ("", "")
                },
                ColorMode::Unique => match *self {
                    Clubs => (GREEN.as_str(), RESET.as_str()),
                    Hearts => (RED.as_str(), RESET.as_str()),
                    Diamonds => (BLUE.as_str(), RESET.as_str()),
                    _ => ("", "")
                }
            }
        };

        write!(f, "{}{}{}", begin, match *self {
            Clubs => "♣",
            Diamonds => "♦",
            Hearts => "♥",
            Spades => "♠"
        }, end)
    }
}

#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Rank {
    Two = 2,
    Three = 3,
    Four = 4,
    Five = 5,
    Six = 6,
    Seven = 7,
    Eight = 8,
    Nine = 9,
    Ten = 10,
    Jack = 11,
    Queen = 12,
    King = 13,
    Ace = 14
}

impl Rank {
    pub fn iterator() -> Iter<'static, Rank> {
        use Rank::*;
        static RANKS: [Rank;  13] = [Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace];
        RANKS.into_iter()
    }
    /// Assign numerical values to each rank, with ace as high
    pub fn ord_ace_high(&self) -> u8 {
        *self as u8
    }

    /// Assign numerical values to each rank, with ace as low
    pub fn ord_ace_low(&self) -> u8 {
        use Rank::*;
        match *self {
            Ace => 1,
            x => x as u8
        }
    }
}

impl FromStr for Rank {
    type Err = CardParseError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Rank::*;
        use self::CardParseError::*;
        match s {
            "2" => Ok(Two),
            "3" => Ok(Three),
            "4" => Ok(Four),
            "5" => Ok(Five),
            "6" => Ok(Six),
            "7" => Ok(Seven),
            "8" => Ok(Eight),
            "9" => Ok(Nine),
            "T" => Ok(Ten),
            "J" => Ok(Jack),
            "Q" => Ok(Queen),
            "K" => Ok(King),
            "A" => Ok(Ace),
            _ => Err(BadRank)
        }
    }
}

impl fmt::Display for Rank {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Rank::*;
        write!(f, "{}", match *self {
            Two => "2",
            Three => "3",
            Four => "4",
            Five => "5",
            Six => "6",
            Seven => "7",
            Eight => "8",
            Nine => "9",
            Ten => "T",
            Jack => "J",
            Queen => "Q",
            King => "K",
            Ace => "A"
        })
    }
}

/// Normal non-joker playing card
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BasicCard {
    pub rank: Rank,
    pub suit: Suit
}

impl BasicCard {
    /// Returns a Vec of all 52 possible `BasicCard`s, in
    /// some unspecified order.
    pub fn all() -> Vec<BasicCard> {
        use Suit::*;

        let mut cards = Vec::with_capacity(52);
        for rank in Rank::iterator() {
            for suit in &[Clubs, Diamonds, Hearts, Spades] {
                cards.push(BasicCard { rank: *rank, suit: *suit })
            }
        }

        cards
    }
}

impl FromStr for BasicCard {
    type Err = CardParseError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let (rank_str, suit_str) = s.split_at(1);
        let rank = rank_str.parse()?;
        let suit = suit_str.parse()?;
        Ok(BasicCard { rank, suit })
    }
}

impl fmt::Display for BasicCard {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}{}", self.rank, self.suit)
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Card {
    Basic(BasicCard),
    BigJoker,
    SmallJoker
}

impl fmt::Display for Card {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Card::*;
        match self {
            &BigJoker => write!(f, "JJ"),
            &SmallJoker => write!(f, "jj"),
            &Card::Basic(ref basic) => write!(f, "{}", basic)
        }
    }
}

/// Deck of 52 basic (non-joker) cards
#[derive(Debug)]
pub struct BasicDeck {
    cards: Vec<BasicCard>
}

impl BasicDeck {
    pub fn new() -> BasicDeck {
        BasicDeck { cards: BasicCard::all() }
    }

    /// Shuffle the remaining cards in the deck
    pub fn shuffle(&mut self) {
        let mut rng = thread_rng();
        rng.shuffle(&mut self.cards)
    }

    pub fn num_cards_left(&self) -> usize {
        self.cards.len()
    }

    /// Return the top card from the deck, if there are any cards
    pub fn draw(&mut self) -> Option<BasicCard> {
        self.cards.pop()
    }

    /// Return the top n cards from the deck, if there are n
    /// cards. Otherwise, return None.
    ///
    /// # Remarks
    ///
    /// If this function returns `Some`, there will be
    /// exactly `n` cards.
    pub fn draw_n(&mut self, n: usize) -> Option<Vec<BasicCard>> {
        let m = self.cards.len();
        if m >= n {
            Some(self.cards.split_off(m - n))
        } else {
            None
        }
    }

}

pub fn auto_suit_colors() {
    unsafe {
        SUIT_COLOR_MODE = if atty::is(atty::Stream::Stdout) {
            ColorMode::Unique
        } else {
            ColorMode::Plain
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>fixup! feat: add inline_type_alias_uses assist<commit_after><|endoftext|>


<commit_before>//! A container for a series of audio devices.
//!
//! A chain can be used when a single series of audio devices passes its output
//! to the input of the next device. It is initialized from a single starting
//! device that will receive no input, and ends in a device who's output is
//! ignored.
//!
//!
//! # Example
//! The following will pass microphone input through a delay unit, then out to
//! the speaker:
//!
//! ```no_run
//! use oxcable::delay::Delay;
//! use oxcable::chain::{DeviceChain, Tick};
//! use oxcable::io::audio::AudioEngine;
//!
//! let engine = AudioEngine::with_buffer_size(256).unwrap();
//! let mut chain = DeviceChain::from(
//!     engine.default_input(1).unwrap()
//! ).into(
//!     Delay::new(1.0, 0.5, 0.5, 1)
//! ).into(
//!     engine.default_output(1).unwrap()
//! );
//! chain.tick_forever();
//! ```

use types::{AudioDevice, Sample, Time};
pub use tick::Tick;

/// A container for a series of audio devices.
pub struct DeviceChain {
    bus: Vec<Sample>,
    devices: Vec<AudioNode>,
    time: Time
}

impl DeviceChain {
    /// Creates a new chain that starts from the provided device. This device
    /// will receive no inputs unless they are manually supplied using
    /// DeviceChain::get_input.
    pub fn from<D>(device: D) -> Self where D: 'static+AudioDevice {
        let mut chain = DeviceChain {
            bus: Vec::new(),
            devices: Vec::new(),
            time: 0
        };
        chain.devices.push(AudioNode::new(device, &mut chain.bus));
        chain
    }

    /// Appends the provided device to the end of the chain. This device will be
    /// passed the output of the last device as input. This method returns the
    /// same chain it was passed.
    ///
    /// # Panics
    ///
    /// Panics if the provided device does not have as many inputs as the
    /// previous device has outputs.
    pub fn into<D>(mut self, device: D) -> Self where D: 'static+AudioDevice {
        if self.devices[self.devices.len()-1].device.num_outputs() !=
                device.num_inputs() {
            panic!("DeviceChain: number of outputs must match number of inputs");
        }
        self.devices.push(AudioNode::new(device, &mut self.bus));
        self
    }

    /// Return a mutable slice to the input of the first device in the chain.
    ///
    /// These inputs never get overwritten, so if you are supplying input you
    /// must manually zero the buffer again.
    pub fn get_input(&mut self) -> &mut[Sample] {
        &mut self.bus[..self.devices[0].device.num_inputs()]
    }

    /// Returns a slice to the output of the last device in the chain.
    pub fn get_output(&self) -> &[Sample] {
        let outputs = self.devices[self.devices.len()-1].device.num_outputs();
        &self.bus[self.bus.len()-outputs..]
    }
}

impl Tick for DeviceChain {
    fn tick(&mut self) {
        for device in self.devices.iter_mut() {
            device.tick(self.time, &mut self.bus);
        }
        self.time += 1;
    }
}

/// Wrap an audio device behind a pointer, and stores an index into the bus.
struct AudioNode {
    device: Box<AudioDevice>,
    bus_start: usize,
    bus_end: usize,
    split_point: usize
}

impl AudioNode {
    /// Wraps the provided audio device in a new node and allocate space for it
    /// in the bus.
    fn new<D>(device: D, bus: &mut Vec<Sample>) -> AudioNode
            where D: 'static+AudioDevice {
        let inputs = device.num_inputs();
        let outputs = device.num_outputs();
        let bus_start = bus.len() - inputs;
        for _ in 0..outputs {
            bus.push(0.0);
        }
        AudioNode {
            device: Box::new(device),
            bus_start: bus_start,
            bus_end: bus_start + inputs + outputs,
            split_point: inputs,
        }
    }

    /// Ticks the device one time step.
    fn tick(&mut self, t: Time, bus: &mut [Sample]) {
        let bus_slice = &mut bus[self.bus_start .. self.bus_end];
        let (inputs, outputs) = bus_slice.split_at_mut(self.split_point);
        self.device.tick(t, inputs, outputs);
    }
}
<commit_msg>Add chain tests.<commit_after>//! A container for a series of audio devices.
//!
//! A chain can be used when a single series of audio devices passes its output
//! to the input of the next device. It is initialized from a single starting
//! device that will receive no input, and ends in a device who's output is
//! ignored.
//!
//!
//! # Example
//! The following will pass microphone input through a delay unit, then out to
//! the speaker:
//!
//! ```no_run
//! use oxcable::delay::Delay;
//! use oxcable::chain::{DeviceChain, Tick};
//! use oxcable::io::audio::AudioEngine;
//!
//! let engine = AudioEngine::with_buffer_size(256).unwrap();
//! let mut chain = DeviceChain::from(
//!     engine.default_input(1).unwrap()
//! ).into(
//!     Delay::new(1.0, 0.5, 0.5, 1)
//! ).into(
//!     engine.default_output(1).unwrap()
//! );
//! chain.tick_forever();
//! ```

use types::{AudioDevice, Sample, Time};
pub use tick::Tick;

/// A container for a series of audio devices.
pub struct DeviceChain {
    bus: Vec<Sample>,
    devices: Vec<AudioNode>,
    time: Time
}

impl DeviceChain {
    /// Creates a new chain that starts from the provided device. This device
    /// will receive no inputs unless they are manually supplied using
    /// DeviceChain::get_input.
    pub fn from<D>(device: D) -> Self where D: 'static+AudioDevice {
        let mut chain = DeviceChain {
            bus: Vec::new(),
            devices: Vec::new(),
            time: 0
        };
        for _ in 0..device.num_inputs() {
            chain.bus.push(0.0);
        }
        chain.devices.push(AudioNode::new(device, &mut chain.bus));
        chain
    }

    /// Appends the provided device to the end of the chain. This device will be
    /// passed the output of the last device as input. This method returns the
    /// same chain it was passed.
    ///
    /// # Panics
    ///
    /// Panics if the provided device does not have as many inputs as the
    /// previous device has outputs.
    pub fn into<D>(mut self, device: D) -> Self where D: 'static+AudioDevice {
        if self.devices[self.devices.len()-1].device.num_outputs() !=
                device.num_inputs() {
            panic!("DeviceChain: number of outputs must match number of inputs");
        }
        self.devices.push(AudioNode::new(device, &mut self.bus));
        self
    }

    /// Return a mutable slice to the input of the first device in the chain.
    ///
    /// These inputs never get overwritten, so if you are supplying input you
    /// must manually zero the buffer again.
    pub fn get_input(&mut self) -> &mut[Sample] {
        &mut self.bus[..self.devices[0].device.num_inputs()]
    }

    /// Returns a slice to the output of the last device in the chain.
    pub fn get_output(&self) -> &[Sample] {
        let outputs = self.devices[self.devices.len()-1].device.num_outputs();
        &self.bus[self.bus.len()-outputs..]
    }
}

impl Tick for DeviceChain {
    fn tick(&mut self) {
        for device in self.devices.iter_mut() {
            device.tick(self.time, &mut self.bus);
        }
        self.time += 1;
    }
}

/// Wrap an audio device behind a pointer, and stores an index into the bus.
struct AudioNode {
    device: Box<AudioDevice>,
    bus_start: usize,
    bus_end: usize,
    split_point: usize
}

impl AudioNode {
    /// Wraps the provided audio device in a new node and allocate space for it
    /// in the bus.
    fn new<D>(device: D, bus: &mut Vec<Sample>) -> AudioNode
            where D: 'static+AudioDevice {
        let inputs = device.num_inputs();
        let outputs = device.num_outputs();
        let bus_start = bus.len() - inputs;
        for _ in 0..outputs {
            bus.push(0.0);
        }
        AudioNode {
            device: Box::new(device),
            bus_start: bus_start,
            bus_end: bus_start + inputs + outputs,
            split_point: inputs,
        }
    }

    /// Ticks the device one time step.
    fn tick(&mut self, t: Time, bus: &mut [Sample]) {
        let bus_slice = &mut bus[self.bus_start .. self.bus_end];
        let (inputs, outputs) = bus_slice.split_at_mut(self.split_point);
        self.device.tick(t, inputs, outputs);
    }
}

#[cfg(test)]
mod test {
    use testing::MockAudioDevice;
    use super::{DeviceChain, Tick};

    #[test]
    fn test_success() {
        let mut mock1 = MockAudioDevice::new("mock1", 0, 1);
        let mut mock2 = MockAudioDevice::new("mock2", 1, 2);
        let mut mock3 = MockAudioDevice::new("mock3", 2, 0);
        mock1.will_tick(&[], &[1.0]);
        mock2.will_tick(&[1.0], &[2.0, 3.0]);
        mock3.will_tick(&[2.0, 3.0], &[]);

        DeviceChain::from(mock1).into(mock2).into(mock3).tick();
    }

    #[test]
    fn test_input() {
        let mut mock = MockAudioDevice::new("mock1", 1, 0);
        mock.will_tick(&[1.0], &[]);

        let mut chain = DeviceChain::from(mock);
        chain.get_input()[0] = 1.0;
        chain.tick();
    }

    #[test]
    fn test_output() {
        let mut mock = MockAudioDevice::new("mock1", 0, 1);
        mock.will_tick(&[], &[1.0]);

        let mut chain = DeviceChain::from(mock);
        chain.tick();
        assert_eq!(chain.get_output(), [1.0]);
    }

    #[test]
    #[should_panic]
    fn test_wrong_number_inputs() {
        let mock1 = MockAudioDevice::new("mock1", 0, 1);
        let mock2 = MockAudioDevice::new("mock2", 2, 1);
        DeviceChain::from(mock1).into(mock2);
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate coreutils;
extern crate extra;

use std::env;
use std::io::{stdout, stderr, Write};
use std::process::exit;
use coreutils::ArgParser;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{echo} */ r#"
NAME
    echo - display a line of text

SYNOPSIS
    echo [ -h | --help ] [-e] [-n] [-s] [STRING]...

DESCRIPTION
    Print the STRING(s) to standard output.

OPTIONS
    -e
        enable the interpretation of backslash escapes
    -n
        do not output the trailing newline
    -s
        do not separate arguments with spaces

    Escape Sequences
        When the -e argument is used, the following sequences will be interpreted:

        \\  backslash

        \a  alert (BEL)

        \b  backspace (BS)

        \c  produce no further output

        \e  escape (ESC)

        \f  form feed (FF)

        \n  new line

        \r  carriage return

        \t  horizontal tab (HT)

        \v  vertical tab (VT)

"#; /* @MANEND */

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(4)
        .add_flag("e", "escape")
        .add_flag("n", "no-newline")
        .add_flag("s", "no-spaces")
        .add_flag("h", "help");
    parser.initialize(env::args());

    if parser.flagged(&'h') || parser.flagged("help") {
        stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    // Print to standard output
    for arg in parser.args.iter().map(|x| x.as_bytes()) {
        if parser.flagged(&'e') || parser.flagged("escape") {
            let mut check = false;
            for &byte in arg {
                match byte {
                    b'\\' if check => {
                        stdout.write(&[byte]).try(&mut stderr);
                        check = false;
                    },
                    b'\\' => check = true,
                    b'a' if check => {
                        stdout.write(&[7u8]).try(&mut stderr); // bell
                        check = false;
                    },
                    b'b' if check => {
                        stdout.write(&[8u8]).try(&mut stderr); // backspace
                        check = false;
                    },
                    b'c' if check => {
                        exit(0);
                    },
                    b'e' if check => {
                        stdout.write(&[27u8]).try(&mut stderr); // escape
                        check = false;
                    },
                    b'f' if check => {
                        stdout.write(&[12u8]).try(&mut stderr); // form feed
                        check = false;
                    },
                    b'n' if check => {
                        stdout.write(&[b'\n']).try(&mut stderr); // newline
                        check = false;
                    },
                    b'r' if check => {
                        stdout.write(&[b'\r']).try(&mut stderr);
                        check = false;
                    },
                    b't' if check => {
                        stdout.write(&[b'\t']).try(&mut stderr);
                        check = false;
                    },
                    b'v' if check => {
                        stdout.write(&[11u8]).try(&mut stderr); // vertical tab
                        check = false;
                    },
                    _ if check => {
                        stdout.write(&[b'\\', byte]).try(&mut stderr);
                        check = false;
                    },
                    _ => { stdout.write(&[byte]).try(&mut stderr); }
                }
            }
        } else {
            stdout.write(arg).try(&mut stderr);
        }
        if !(parser.flagged(&'s') || parser.flagged("no-spaces")) {
            stdout.write(&[b' ']).try(&mut stderr);
        }
    }

    if !(parser.flagged(&'n') || parser.flagged("no-newline")) {
        stdout.write(&[b'\n']).try(&mut stderr);
    }
}
<commit_msg>Fix echo<commit_after>#![deny(warnings)]

extern crate coreutils;
extern crate extra;

use std::env;
use std::io::{stdout, stderr, Write};
use std::process::exit;
use coreutils::ArgParser;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{echo} */ r#"
NAME
    echo - display a line of text

SYNOPSIS
    echo [ -h | --help ] [-e] [-n] [-s] [STRING]...

DESCRIPTION
    Print the STRING(s) to standard output.

OPTIONS
    -e
        enable the interpretation of backslash escapes
    -n
        do not output the trailing newline
    -s
        do not separate arguments with spaces

    Escape Sequences
        When the -e argument is used, the following sequences will be interpreted:

        \\  backslash
        \a  alert (BEL)
        \b  backspace (BS)
        \c  produce no further output
        \e  escape (ESC)
        \f  form feed (FF)
        \n  new line
        \r  carriage return
        \t  horizontal tab (HT)
        \v  vertical tab (VT)

"#; /* @MANEND */

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(4)
        .add_flag("e", "escape")
        .add_flag("n", "no-newline")
        .add_flag("s", "no-spaces")
        .add_flag("h", "help");
    parser.initialize(env::args());

    if parser.flagged(&'h') || parser.flagged("help") {
        stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    // Print to standard output
    let mut first = true;
    for arg in parser.args.iter().map(|x| x.as_bytes()) {
        if first {
            first = false;
        } else if !(parser.flagged(&'s') || parser.flagged("no-spaces")) {
            stdout.write(&[b' ']).try(&mut stderr);
        }
        if parser.flagged(&'e') || parser.flagged("escape") {
            let mut check = false;
            for &byte in arg {
                match byte {
                    b'\\' if check => {
                        stdout.write(&[byte]).try(&mut stderr);
                        check = false;
                    },
                    b'\\' => check = true,
                    b'a' if check => {
                        stdout.write(&[7u8]).try(&mut stderr); // bell
                        check = false;
                    },
                    b'b' if check => {
                        stdout.write(&[8u8]).try(&mut stderr); // backspace
                        check = false;
                    },
                    b'c' if check => {
                        exit(0);
                    },
                    b'e' if check => {
                        stdout.write(&[27u8]).try(&mut stderr); // escape
                        check = false;
                    },
                    b'f' if check => {
                        stdout.write(&[12u8]).try(&mut stderr); // form feed
                        check = false;
                    },
                    b'n' if check => {
                        stdout.write(&[b'\n']).try(&mut stderr); // newline
                        check = false;
                    },
                    b'r' if check => {
                        stdout.write(&[b'\r']).try(&mut stderr);
                        check = false;
                    },
                    b't' if check => {
                        stdout.write(&[b'\t']).try(&mut stderr);
                        check = false;
                    },
                    b'v' if check => {
                        stdout.write(&[11u8]).try(&mut stderr); // vertical tab
                        check = false;
                    },
                    _ if check => {
                        stdout.write(&[b'\\', byte]).try(&mut stderr);
                        check = false;
                    },
                    _ => { stdout.write(&[byte]).try(&mut stderr); }
                }
            }
        } else {
            stdout.write(arg).try(&mut stderr);
        }
    }

    if !(parser.flagged(&'n') || parser.flagged("no-newline")) {
        stdout.write(&[b'\n']).try(&mut stderr);
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

// TODO support reading from standard input

extern crate extra;
extern crate termion;

use std::env::args;
use std::fs::File;
use std::io::{self, Write, Read, StdoutLock, Stderr};
use std::path::Path;

use extra::option::OptionalExt;

use termion::{terminal_size, TermRead, TermWrite, IntoRawMode, Color, Key, RawTerminal};

static LONG_HELP: &'static str = /* @MANSTART{less} */ r#"
NAME
    less - view a text file.

SYNOPSIS
    less [-h | --help] [input]

DESCRIPTION
    This utility views text files. If no input file is specified as an argument, standard input is
    used.

OPTIONS
    --help, -h
        Print this manual page.

AUTHOR
    This program was written by MovingtoMars for Redox OS. Bugs, issues, or feature requests should
    be reported in the Github repository, 'redox-os/extrautils'.

COPYRIGHT
    Copyright (c) 2016 MovingtoMars

    Permission is hereby granted, free of charge, to any person obtaining a copy of this software
    and associated documentation files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use, copy, modify, merge, publish,
    distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all copies or
    substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
    BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"#; /* @MANEND */

fn main() {
    let mut args = args().skip(1);
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let stdin = io::stdin();
    let mut stdin = stdin.lock();
    let mut stderr = io::stderr();

    if let Some(x) = args.next() {
        match x.as_str() {
            "--help" | "-h" => {
                // Print help.
                stdout.write(LONG_HELP.as_bytes()).try(&mut stderr);
                return;
            },
            filename => {
                let mut file = File::open(Path::new(filename)).try(&mut stderr);
                run(&mut file, &mut stdin, &mut stdout, &mut stderr);
            }
        }

        if let Some(x) = args.next() {
            let mut file = File::open(Path::new(x.as_str())).try(&mut stderr);
            run(&mut file, &mut stdin, &mut stdout, &mut stderr);
        }
    } else {
        writeln!(stderr, "Readin from stdin is not yet supported").try(&mut stderr);
        //run(&mut stdin, &mut stdin, &mut stdout, &mut stderr);
    };
}

struct Buffer {
    lines: Vec<String>,
    y_off: u16,
}

impl Buffer {
    fn new() -> Buffer {
        Buffer{
            lines: Vec::new(),
            y_off: 0,
        }
    }

    fn read(&mut self, from: &mut Read) -> std::io::Result<usize> {
        let mut tmp = String::new();
        let res = from.read_to_string(&mut tmp);
        try!(res);

        self.lines.append(&mut tmp
            .as_str()
            .split("\n")
            .map(|x| {String::from(x)})
            .collect());

        return res;
    }

    fn draw(&self, to: &mut RawTerminal<&mut StdoutLock>, w: u16, h: u16) -> std::io::Result<usize> {
        try!(to.goto(0, 0));

        let mut y = 0;
        let mut bytes_written = 0;

        let lines = if self.lines.len() <= h as usize {
            &self.lines
        } else if self.y_off as usize >= self.lines.len() {
            &self.lines[0..0]
        } else {
            &self.lines[self.y_off as usize..]
        };

        for line in lines {
            if line.len() > w as usize {
                bytes_written += try!(to.write(line[..w as usize].as_bytes()));
            } else {
                bytes_written += try!(to.write(line.as_bytes()));
            }

            y += 1;
            try!(to.goto(0, y));
            if y >= h {
                break;
            }
        }

        Ok(bytes_written)
    }

    fn scroll_up(&mut self) {
        if self.y_off > 0 {
            self.y_off -= 1;
        }
    }

    fn scroll_down(&mut self, height: u16) {
        if ((self.y_off + height) as usize) <= self.lines.len() {
            self.y_off += 1;
        }
    }
}

fn run(file: &mut Read, controls: &mut Read, stdout: &mut StdoutLock, stderr: &mut Stderr) {
    let mut stdout = stdout.into_raw_mode().try(stderr);

    let (w, h) = {
        let (w, h) = terminal_size().try(stderr);
        (w as u16, h as u16)
    };

    stdout.clear().try(stderr);
    stdout.reset().try(stderr);

    let mut buffer = Buffer::new();
    buffer.read(file).try(stderr);

    buffer.draw(&mut stdout, w, h - 1).try(stderr);
    stdout.goto(0, h - 1).try(stderr);
    stdout.bg_color(Color::White).try(stderr);
    stdout.color(Color::Black).try(stderr);
    stdout.write(b"Press q to exit.").try(stderr);
    stdout.reset().try(stderr);
    stdout.flush().try(stderr);

    for c in controls.keys() {
        match c {
            Key::Char('q') => {
                stdout.clear().try(stderr);
                stdout.reset().try(stderr);
                stdout.goto(0, 0).try(stderr);
                return
            },
            Key::Up | Key::Char('k') => buffer.scroll_up(),
            Key::Down | Key::Char('j') => buffer.scroll_down(h),
            _ => {},
        }

        stdout.clear().try(stderr);
        stdout.reset().try(stderr);
        buffer.draw(&mut stdout, w, h - 1).try(stderr);
        stdout.goto(0, h - 1).try(stderr);
        stdout.bg_color(Color::White).try(stderr);
        stdout.color(Color::Black).try(stderr);
        stdout.write(b"Press q to exit.").try(stderr);
        stdout.reset().try(stderr);
        stdout.flush().try(stderr);
    }
}
<commit_msg>Add filename to less<commit_after>#![deny(warnings)]

// TODO support reading from standard input

extern crate extra;
extern crate termion;

use std::env::args;
use std::fs::File;
use std::io::{self, Write, Read, StdoutLock, Stderr};
use std::path::Path;

use extra::option::OptionalExt;

use termion::{terminal_size, TermRead, TermWrite, IntoRawMode, Color, Key, RawTerminal};

static LONG_HELP: &'static str = /* @MANSTART{less} */ r#"
NAME
    less - view a text file.

SYNOPSIS
    less [-h | --help] [input]

DESCRIPTION
    This utility views text files. If no input file is specified as an argument, standard input is
    used.

OPTIONS
    --help, -h
        Print this manual page.

AUTHOR
    This program was written by MovingtoMars for Redox OS. Bugs, issues, or feature requests should
    be reported in the Github repository, 'redox-os/extrautils'.

COPYRIGHT
    Copyright (c) 2016 MovingtoMars

    Permission is hereby granted, free of charge, to any person obtaining a copy of this software
    and associated documentation files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use, copy, modify, merge, publish,
    distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all copies or
    substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
    BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"#; /* @MANEND */

fn main() {
    let mut args = args().skip(1);
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    let stdin = io::stdin();
    let mut stdin = stdin.lock();
    let mut stderr = io::stderr();

    if let Some(x) = args.next() {
        match x.as_str() {
            "--help" | "-h" => {
                // Print help.
                stdout.write(LONG_HELP.as_bytes()).try(&mut stderr);
                return;
            },
            filename => {
                let mut file = File::open(Path::new(filename)).try(&mut stderr);
                run(filename, &mut file, &mut stdin, &mut stdout, &mut stderr);
            }
        }

        if let Some(x) = args.next() {
            let mut file = File::open(Path::new(x.as_str())).try(&mut stderr);
            run(x.as_str(), &mut file, &mut stdin, &mut stdout, &mut stderr);
        }
    } else {
        writeln!(stderr, "Readin from stdin is not yet supported").try(&mut stderr);
        //run(&mut stdin, &mut stdin, &mut stdout, &mut stderr);
    };
}

struct Buffer {
    lines: Vec<String>,
    y_off: u16,
}

impl Buffer {
    fn new() -> Buffer {
        Buffer{
            lines: Vec::new(),
            y_off: 0,
        }
    }

    fn read(&mut self, from: &mut Read) -> std::io::Result<usize> {
        let mut tmp = String::new();
        let res = from.read_to_string(&mut tmp);
        try!(res);

        self.lines.append(&mut tmp
            .as_str()
            .split("\n")
            .map(|x| {String::from(x)})
            .collect());

        return res;
    }

    fn draw(&self, to: &mut RawTerminal<&mut StdoutLock>, w: u16, h: u16) -> std::io::Result<usize> {
        try!(to.goto(0, 0));

        let mut y = 0;
        let mut bytes_written = 0;

        let lines = if self.lines.len() <= h as usize {
            &self.lines
        } else if self.y_off as usize >= self.lines.len() {
            &self.lines[0..0]
        } else {
            &self.lines[self.y_off as usize..]
        };

        for line in lines {
            if line.len() > w as usize {
                bytes_written += try!(to.write(line[..w as usize].as_bytes()));
            } else {
                bytes_written += try!(to.write(line.as_bytes()));
            }

            y += 1;
            try!(to.goto(0, y));
            if y >= h {
                break;
            }
        }

        Ok(bytes_written)
    }

    fn scroll_up(&mut self) {
        if self.y_off > 0 {
            self.y_off -= 1;
        }
    }

    fn scroll_down(&mut self, height: u16) {
        if ((self.y_off + height) as usize) <= self.lines.len() {
            self.y_off += 1;
        }
    }
}

fn run(path: &str, file: &mut Read, controls: &mut Read, stdout: &mut StdoutLock, stderr: &mut Stderr) {
    let mut stdout = stdout.into_raw_mode().try(stderr);

    let (w, h) = {
        let (w, h) = terminal_size().try(stderr);
        (w as u16, h as u16)
    };

    stdout.clear().try(stderr);
    stdout.reset().try(stderr);

    let mut buffer = Buffer::new();
    buffer.read(file).try(stderr);

    buffer.draw(&mut stdout, w, h - 1).try(stderr);
    stdout.goto(0, h - 1).try(stderr);
    stdout.bg_color(Color::White).try(stderr);
    stdout.color(Color::Black).try(stderr);
    stdout.write(path.as_bytes()).try(stderr);
    stdout.write(b" Press q to exit.").try(stderr);
    stdout.reset().try(stderr);
    stdout.flush().try(stderr);

    for c in controls.keys() {
        match c {
            Key::Char('q') => {
                stdout.clear().try(stderr);
                stdout.reset().try(stderr);
                stdout.goto(0, 0).try(stderr);
                return
            },
            Key::Up | Key::Char('k') => buffer.scroll_up(),
            Key::Down | Key::Char('j') => buffer.scroll_down(h),
            _ => {},
        }

        stdout.clear().try(stderr);
        stdout.reset().try(stderr);
        buffer.draw(&mut stdout, w, h - 1).try(stderr);
        stdout.goto(0, h - 1).try(stderr);
        stdout.bg_color(Color::White).try(stderr);
        stdout.color(Color::Black).try(stderr);
        stdout.write(path.as_bytes()).try(stderr);
        stdout.write(b" Press q to exit.").try(stderr);
        stdout.reset().try(stderr);
        stdout.flush().try(stderr);
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![feature(custom_derive)]
#![plugin(rocket_codegen)]

extern crate rocket;
extern crate failure;
extern crate rocket_contrib;
extern crate serde;
extern crate r2d2;
extern crate r2d2_diesel;
extern crate ring;
extern crate diesel;
extern crate config;
#[macro_use]
extern crate clap;

extern crate _aardwolf as aardwolf;

use ring::rand::SystemRandom;
use rocket::Rocket;
use rocket_contrib::Template;
use diesel::pg::PgConnection;
use r2d2_diesel::ConnectionManager;
use config::Config;
use clap::App;
use std::path::PathBuf;
use std::env;

type Pool = r2d2::Pool<ConnectionManager<PgConnection>>;

fn db_pool(rocket: &Rocket) -> Pool {
    let database_url = rocket.config().get_str("database_url").expect("Must set Database.url in config");
    let manager = ConnectionManager::<PgConnection>::new(database_url);
    r2d2::Pool::builder().build(manager).expect("Could not get DB connection pool")
}

fn app(config: config::Config) -> Rocket {
    let mut db_url = String::new();
    match config.get_str("Database.type").unwrap().to_lowercase().as_str() {
        "postgresql" | "postgres" => db_url.push_str("postgres://"),

        // If we reach this case, it's an error.
        // TODO: Handle it.
        _ => {}
    }

    db_url.push_str(config.get_str("Database.username").unwrap().as_str());
    db_url.push(':');
    db_url.push_str(config.get_str("Database.password").unwrap().as_str());
    db_url.push('@');
    db_url.push_str(config.get_str("Database.host").unwrap().as_str());
    db_url.push(':');
    db_url.push_str(config.get_str("Database.port").unwrap().as_str());
    db_url.push('/');
    db_url.push_str(config.get_str("Database.database").unwrap().as_str());

    let c = rocket::Config::build(rocket::config::Environment::Development)
        .address(config.get_str("Listen.address").unwrap())
        .port(config.get::<u16>("Listen.port").unwrap())
        .extra("database_url", db_url.as_str())
        .unwrap();

    let r = rocket::custom(c, true)
        .mount("/api/v1", routes![
            aardwolf::routes::applications::register_application
        ])
        .mount("/", routes![
            aardwolf::routes::auth::sign_up_form,
            aardwolf::routes::auth::sign_in_form,
            aardwolf::routes::auth::sign_up,
            aardwolf::routes::auth::sign_in,
            aardwolf::routes::auth::confirm,
            aardwolf::routes::auth::sign_out,

            aardwolf::routes::app::home,
            aardwolf::routes::app::home_redirect,
        ])
        .attach(Template::fairing())
        .manage(SystemRandom::new());

    // we need an instance of the app to access the config values in Rocket.toml,
    // so we pass it to the db_pool function, get the pool, and _then_ return the instance
    let pool = db_pool(&r);
    r.manage(pool)
}

fn configure() -> Config {
    // Set defaults
    let mut config = Config::default();
    config.set_default::<&str>("cfg_file", concat!(env!("CARGO_PKG_NAME"), ".toml")).unwrap();
    config.set_default::<&str>("log_file", concat!(env!("CARGO_PKG_NAME"), ".log")).unwrap();
    config.set_default::<&str>("Listen.address", "127.0.0.1").unwrap();
    config.set_default("Listen.port", 7878).unwrap();

    // Parse arguments
    let yaml = load_yaml!("cli.yml");
    let args = App::from_yaml(yaml)
        .name(env!("CARGO_PKG_NAME"))
        .version(env!("CARGO_PKG_VERSION"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .get_matches();

    // Determine config file
    match env::var("AARDWOLF_CONFIG") {
        Ok(c) => {config.set("cfg_file", c).unwrap();},
        Err(_) => {}
    }

    match args.value_of("config") {
        Some(c) => {config.set("cfg_file", c).unwrap();},
        None => {}
    }

    // Merge config file and apply over-rides
    let cfg_file: PathBuf = PathBuf::from(config.get_str("cfg_file").unwrap());
    config.merge(config::File::with_name(cfg_file.to_str().unwrap())).unwrap();

    config
}

fn main() {
    let config = configure();

    app(config).launch();
}
<commit_msg>Finish implementing argument parsing and config over-riding.<commit_after>#![feature(plugin)]
#![feature(custom_derive)]
#![plugin(rocket_codegen)]

extern crate rocket;
extern crate failure;
extern crate rocket_contrib;
extern crate serde;
extern crate r2d2;
extern crate r2d2_diesel;
extern crate ring;
extern crate diesel;
extern crate config;
#[macro_use]
extern crate clap;

extern crate _aardwolf as aardwolf;

use ring::rand::SystemRandom;
use rocket::Rocket;
use rocket_contrib::Template;
use diesel::pg::PgConnection;
use r2d2_diesel::ConnectionManager;
use config::Config;
use clap::App;
use std::path::PathBuf;
use std::env;

type Pool = r2d2::Pool<ConnectionManager<PgConnection>>;

fn db_pool(rocket: &Rocket) -> Pool {
    let database_url = rocket.config().get_str("database_url").expect("Must set Database.url in config");
    let manager = ConnectionManager::<PgConnection>::new(database_url);
    r2d2::Pool::builder().build(manager).expect("Could not get DB connection pool")
}

fn app(config: config::Config) -> Rocket {
    let mut db_url = String::new();
    match config.get_str("Database.type").unwrap().to_lowercase().as_str() {
        "postgresql" | "postgres" => db_url.push_str("postgres://"),

        // If we reach this case, it's an error.
        // TODO: Handle it.
        _ => {}
    }

    db_url.push_str(config.get_str("Database.username").unwrap().as_str());
    db_url.push(':');
    db_url.push_str(config.get_str("Database.password").unwrap().as_str());
    db_url.push('@');
    db_url.push_str(config.get_str("Database.host").unwrap().as_str());
    db_url.push(':');
    db_url.push_str(config.get_str("Database.port").unwrap().as_str());
    db_url.push('/');
    db_url.push_str(config.get_str("Database.database").unwrap().as_str());

    let c = rocket::Config::build(rocket::config::Environment::Development)
        .address(config.get_str("Listen.address").unwrap())
        .port(config.get::<u16>("Listen.port").unwrap())
        .extra("database_url", db_url.as_str())
        .unwrap();

    let r = rocket::custom(c, true)
        .mount("/api/v1", routes![
            aardwolf::routes::applications::register_application
        ])
        .mount("/", routes![
            aardwolf::routes::auth::sign_up_form,
            aardwolf::routes::auth::sign_in_form,
            aardwolf::routes::auth::sign_up,
            aardwolf::routes::auth::sign_in,
            aardwolf::routes::auth::confirm,
            aardwolf::routes::auth::sign_out,

            aardwolf::routes::app::home,
            aardwolf::routes::app::home_redirect,
        ])
        .attach(Template::fairing())
        .manage(SystemRandom::new());

    // we need an instance of the app to access the config values in Rocket.toml,
    // so we pass it to the db_pool function, get the pool, and _then_ return the instance
    let pool = db_pool(&r);
    r.manage(pool)
}

fn configure() -> Config {
    // Set defaults
    let mut config = Config::default();
    config.set_default::<&str>("cfg_file", concat!(env!("CARGO_PKG_NAME"), ".toml")).unwrap();
    config.set_default::<&str>("log_file", concat!(env!("CARGO_PKG_NAME"), ".log")).unwrap();
    config.set_default::<&str>("Listen.address", "127.0.0.1").unwrap();
    config.set_default("Listen.port", 7878).unwrap();

    // Parse arguments
    let yaml = load_yaml!("cli.yml");
    let args = App::from_yaml(yaml)
        .name(env!("CARGO_PKG_NAME"))
        .version(env!("CARGO_PKG_VERSION"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .get_matches();

    // Determine config file
    // TODO: Is there a better way to handle this?
    match env::var("AARDWOLF_CONFIG") {
        Ok(c) => {config.set("cfg_file", c).unwrap();},
        Err(_) => {}
    }

    match args.value_of("config") {
        Some(c) => {config.set("cfg_file", c).unwrap();},
        None => {}
    }

    // Merge config file and apply over-rides
    let cfg_file: PathBuf = PathBuf::from(config.get_str("cfg_file").unwrap());
    config.merge(config::File::with_name(cfg_file.to_str().unwrap())).unwrap();

    //  TODO: Is there a better way to handle this?
    match env::var("AARDWOLF_LOG") {
        Ok(l) => {config.set("log_file", l).unwrap();},
        Err(_) => {}
    }

    match args.value_of("log") {
        Some(l) => {config.set("log_file", l).unwrap();},
        None => {}
    }

    config
}

fn main() {
    let config = configure();

    app(config).launch();
}
<|endoftext|>


<commit_before>#![feature(rustc_private)]

extern crate getopts;
extern crate miri;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_codegen_utils;
extern crate env_logger;
extern crate log_settings;
extern crate syntax;
extern crate log;

use rustc::session::Session;
use rustc::middle::cstore::CrateStore;
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};
use rustc_driver::driver::{CompileState, CompileController};
use rustc::session::config::{self, Input, ErrorOutputType};
use rustc::hir::{self, itemlikevisit};
use rustc::ty::TyCtxt;
use rustc_codegen_utils::codegen_backend::CodegenBackend;
use syntax::ast;
use std::path::PathBuf;

struct MiriCompilerCalls {
    default: RustcDefaultCalls,
    /// Whether to begin interpretation at the start_fn lang item or not
    ///
    /// If false, the interpretation begins at the `main` function
    start_fn: bool,
}

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType,
    ) -> Compilation {
        self.default.early_callback(
            matches,
            sopts,
            cfg,
            descriptions,
            output,
        )
    }
    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry,
    ) -> Option<(Input, Option<PathBuf>)> {
        self.default.no_input(
            matches,
            sopts,
            cfg,
            odir,
            ofile,
            descriptions,
        )
    }
    fn late_callback(
        &mut self,
        trans: &CodegenBackend,
        matches: &getopts::Matches,
        sess: &Session,
        cstore: &CrateStore,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
    ) -> Compilation {
        self.default.late_callback(trans, matches, sess, cstore, input, odir, ofile)
    }
    fn build_controller(
        &mut self,
        sess: &Session,
        matches: &getopts::Matches,
    ) -> CompileController<'a> {
        let mut control = self.default.build_controller(sess, matches);
        control.after_hir_lowering.callback = Box::new(after_hir_lowering);
        let start_fn = self.start_fn;
        control.after_analysis.callback = Box::new(move |state| after_analysis(state, start_fn));
        if sess.target.target != sess.host {
            // only fully compile targets on the host. linking will fail for cross-compilation.
            control.after_analysis.stop = Compilation::Stop;
        }
        control
    }
}

fn after_hir_lowering(state: &mut CompileState) {
    let attr = (
        String::from("miri"),
        syntax::feature_gate::AttributeType::Whitelisted,
    );
    state.session.plugin_attributes.borrow_mut().push(attr);
}

fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bool) {
    state.session.abort_if_errors();

    let tcx = state.tcx.unwrap();

    if std::env::args().any(|arg| arg == "--test") {
        struct Visitor<'a, 'tcx: 'a>(
            TyCtxt<'a, 'tcx, 'tcx>,
            &'a CompileState<'a, 'tcx>
        );
        impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> {
            fn visit_item(&mut self, i: &'hir hir::Item) {
                if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node {
                    if i.attrs.iter().any(|attr| {
                        attr.name() == "test"
                    })
                    {
                        let did = self.0.hir.body_owner_def_id(body_id);
                        println!(
                            "running test: {}",
                            self.0.def_path_debug_str(did),
                        );
                        miri::eval_main(self.0, did, None);
                        self.1.session.abort_if_errors();
                    }
                }
            }
            fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
            fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
        }
        state.hir_crate.unwrap().visit_all_item_likes(
            &mut Visitor(tcx, state),
        );
    } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() {
        let entry_def_id = tcx.hir.local_def_id(entry_node_id);
        let start_wrapper = tcx.lang_items().start_fn().and_then(|start_fn| {
            if use_start_fn {
                Some(start_fn)
            } else {
                None
            }
        });
        miri::eval_main(tcx, entry_def_id, start_wrapper);

        state.session.abort_if_errors();
    } else {
        println!("no main function found, assuming auxiliary build");
    }
}

fn init_logger() {
    let format = |formatter: &mut env_logger::fmt::Formatter, record: &log::Record| {
        use std::io::Write;
        if record.level() == log::Level::Trace {
            // prepend frame number
            let indentation = log_settings::settings().indentation;
            writeln!(
                formatter,
                "{indentation}:{lvl}:{module}: {text}",
                lvl = record.level(),
                module = record.module_path().unwrap_or("<unknown module>"),
                indentation = indentation,
                text = record.args(),
            )
        } else {
            writeln!(
                formatter,
                "{lvl}:{module}: {text}",
                lvl = record.level(),
                module = record.module_path().unwrap_or("<unknown_module>"),
                text = record.args(),
            )
        }
    };

    let mut builder = env_logger::Builder::new();
    builder.format(format).filter(
        None,
        log::LevelFilter::Info,
    );

    if std::env::var("MIRI_LOG").is_ok() {
        builder.parse(&std::env::var("MIRI_LOG").unwrap());
    }

    builder.init();
}

fn find_sysroot() -> String {
    if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
        return sysroot;
    }

    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => {
            option_env!("RUST_SYSROOT")
                .expect(
                    "need to specify RUST_SYSROOT env var or use rustup or multirust",
                )
                .to_owned()
        }
    }
}

fn main() {
    rustc_driver::init_rustc_env_logger();
    init_logger();
    let mut args: Vec<String> = std::env::args().collect();

    let sysroot_flag = String::from("--sysroot");
    if !args.contains(&sysroot_flag) {
        args.push(sysroot_flag);
        args.push(find_sysroot());
    }

    let mut start_fn = false;
    args.retain(|arg| {
        if arg == "-Zmiri-start-fn" {
            start_fn = true;
            false
        } else {
            true
        }
    });

    // Make sure we always have all the MIR (e.g. for auxilary builds in unit tests).
    args.push("-Zalways-encode-mir".to_owned());

    rustc_driver::run_compiler(&args, &mut MiriCompilerCalls {
        default: RustcDefaultCalls,
        start_fn,
    }, None, None);
}
<commit_msg>trans -> codegen_backend<commit_after>#![feature(rustc_private)]

extern crate getopts;
extern crate miri;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_codegen_utils;
extern crate env_logger;
extern crate log_settings;
extern crate syntax;
extern crate log;

use rustc::session::Session;
use rustc::middle::cstore::CrateStore;
use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls};
use rustc_driver::driver::{CompileState, CompileController};
use rustc::session::config::{self, Input, ErrorOutputType};
use rustc::hir::{self, itemlikevisit};
use rustc::ty::TyCtxt;
use rustc_codegen_utils::codegen_backend::CodegenBackend;
use syntax::ast;
use std::path::PathBuf;

struct MiriCompilerCalls {
    default: RustcDefaultCalls,
    /// Whether to begin interpretation at the start_fn lang item or not
    ///
    /// If false, the interpretation begins at the `main` function
    start_fn: bool,
}

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType,
    ) -> Compilation {
        self.default.early_callback(
            matches,
            sopts,
            cfg,
            descriptions,
            output,
        )
    }
    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry,
    ) -> Option<(Input, Option<PathBuf>)> {
        self.default.no_input(
            matches,
            sopts,
            cfg,
            odir,
            ofile,
            descriptions,
        )
    }
    fn late_callback(
        &mut self,
        codegen_backend: &CodegenBackend,
        matches: &getopts::Matches,
        sess: &Session,
        cstore: &CrateStore,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
    ) -> Compilation {
        self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile)
    }
    fn build_controller(
        &mut self,
        sess: &Session,
        matches: &getopts::Matches,
    ) -> CompileController<'a> {
        let mut control = self.default.build_controller(sess, matches);
        control.after_hir_lowering.callback = Box::new(after_hir_lowering);
        let start_fn = self.start_fn;
        control.after_analysis.callback = Box::new(move |state| after_analysis(state, start_fn));
        if sess.target.target != sess.host {
            // only fully compile targets on the host. linking will fail for cross-compilation.
            control.after_analysis.stop = Compilation::Stop;
        }
        control
    }
}

fn after_hir_lowering(state: &mut CompileState) {
    let attr = (
        String::from("miri"),
        syntax::feature_gate::AttributeType::Whitelisted,
    );
    state.session.plugin_attributes.borrow_mut().push(attr);
}

fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bool) {
    state.session.abort_if_errors();

    let tcx = state.tcx.unwrap();

    if std::env::args().any(|arg| arg == "--test") {
        struct Visitor<'a, 'tcx: 'a>(
            TyCtxt<'a, 'tcx, 'tcx>,
            &'a CompileState<'a, 'tcx>
        );
        impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> {
            fn visit_item(&mut self, i: &'hir hir::Item) {
                if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node {
                    if i.attrs.iter().any(|attr| {
                        attr.name() == "test"
                    })
                    {
                        let did = self.0.hir.body_owner_def_id(body_id);
                        println!(
                            "running test: {}",
                            self.0.def_path_debug_str(did),
                        );
                        miri::eval_main(self.0, did, None);
                        self.1.session.abort_if_errors();
                    }
                }
            }
            fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {}
            fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {}
        }
        state.hir_crate.unwrap().visit_all_item_likes(
            &mut Visitor(tcx, state),
        );
    } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() {
        let entry_def_id = tcx.hir.local_def_id(entry_node_id);
        let start_wrapper = tcx.lang_items().start_fn().and_then(|start_fn| {
            if use_start_fn {
                Some(start_fn)
            } else {
                None
            }
        });
        miri::eval_main(tcx, entry_def_id, start_wrapper);

        state.session.abort_if_errors();
    } else {
        println!("no main function found, assuming auxiliary build");
    }
}

fn init_logger() {
    let format = |formatter: &mut env_logger::fmt::Formatter, record: &log::Record| {
        use std::io::Write;
        if record.level() == log::Level::Trace {
            // prepend frame number
            let indentation = log_settings::settings().indentation;
            writeln!(
                formatter,
                "{indentation}:{lvl}:{module}: {text}",
                lvl = record.level(),
                module = record.module_path().unwrap_or("<unknown module>"),
                indentation = indentation,
                text = record.args(),
            )
        } else {
            writeln!(
                formatter,
                "{lvl}:{module}: {text}",
                lvl = record.level(),
                module = record.module_path().unwrap_or("<unknown_module>"),
                text = record.args(),
            )
        }
    };

    let mut builder = env_logger::Builder::new();
    builder.format(format).filter(
        None,
        log::LevelFilter::Info,
    );

    if std::env::var("MIRI_LOG").is_ok() {
        builder.parse(&std::env::var("MIRI_LOG").unwrap());
    }

    builder.init();
}

fn find_sysroot() -> String {
    if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") {
        return sysroot;
    }

    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => {
            option_env!("RUST_SYSROOT")
                .expect(
                    "need to specify RUST_SYSROOT env var or use rustup or multirust",
                )
                .to_owned()
        }
    }
}

fn main() {
    rustc_driver::init_rustc_env_logger();
    init_logger();
    let mut args: Vec<String> = std::env::args().collect();

    let sysroot_flag = String::from("--sysroot");
    if !args.contains(&sysroot_flag) {
        args.push(sysroot_flag);
        args.push(find_sysroot());
    }

    let mut start_fn = false;
    args.retain(|arg| {
        if arg == "-Zmiri-start-fn" {
            start_fn = true;
            false
        } else {
            true
        }
    });

    // Make sure we always have all the MIR (e.g. for auxilary builds in unit tests).
    args.push("-Zalways-encode-mir".to_owned());

    rustc_driver::run_compiler(&args, &mut MiriCompilerCalls {
        default: RustcDefaultCalls,
        start_fn,
    }, None, None);
}
<|endoftext|>