<commit_before>extern crate iron;
#[macro_use]
extern crate router;
extern crate staticfile;
extern crate mount;
extern crate urlencoded;
extern crate rustc_serialize;
extern crate html5ever;
extern crate regex;
extern crate uuid;

use std::net::SocketAddrV4;
use std::net::Ipv4Addr;
use std::path::Path;
use iron::prelude::*;
use iron::status;
use iron::headers::{ContentType};
use iron::modifiers::Header;
use iron::mime::Mime;
use staticfile::Static;
use mount::Mount;
use router::{Router};
use urlencoded::UrlEncodedQuery;
use urlencoded::UrlEncodedBody;
use std::str::FromStr;

#[macro_use]
extern crate string_cache;

extern crate pink_spider;

use pink_spider::error::Error;
use pink_spider::scraper::extract;
use pink_spider::model::{Track, Entry, Provider};
use rustc_serialize::json::{ToJson, Json};

pub fn playlistify(req: &mut Request) -> IronResult<Response> {
    let json_type = Header(ContentType(Mime::from_str("application/json").ok().unwrap()));
    match req.get_ref::<UrlEncodedQuery>() {
        Ok(ref params) => {
            match params.get("url") {
                Some(url) => {
                    let defaults = &vec!("false".to_string());
                    let force    = params.get("force").unwrap_or(defaults);
                    match find_or_playlistify_entry(&url[0], force.len() > 0 && &force[0] == "true") {
                        Ok(entry) => {
                            let json_obj: Json   = entry.to_json();
                            let json_str: String = json_obj.to_string();
                            Ok(Response::with((status::Ok, json_type, json_str)))
                        },
                        Err(e) => Ok(e.as_response())
                    }
                },
                None => Ok(Error::BadRequest.as_response())
            }
        }
        Err(_) => Ok(Error::BadRequest.as_response())
    }
}

pub fn find_or_playlistify_entry(url: &str, force: bool) -> Result<Entry, Error> {
    match Entry::find_by_url(url) {
        Ok(entry) => {
            println!("Get entry from database cache: {}", url);
            if force {
                println!("Update entry: {}", url);
                let entry = try!(playlistify_entry(entry));
                Ok(entry)
            } else {
                Ok(entry)
            }
        },
        Err(_) => {
            let entry = try!(Entry::create_by_url(url.to_string()));
            let entry = try!(playlistify_entry(entry));
            println!("Create new entry to database cache: {}", url);
            Ok(entry)
        },
    }
}

pub fn playlistify_entry(entry: Entry) -> Result<Entry, Error> {
    let mut e = entry.clone();
    let product = try!(extract(&entry.url));
    match product.og_obj {
        Some(og_obj) => {
            e.title       = Some(og_obj.title);
            e.description = og_obj.description;
            e.locale      = og_obj.locale;
            e.visual_url  = og_obj.images.first().map(|i| i.url.clone());
        },
        None => (),
    }
    for t in product.tracks {
        let track = try!(Track::find_or_create(t.provider,
                                               t.title,
                                               t.url,
                                               t.identifier));
        match entry.tracks.iter().find(|&t| t.id == track.id) {
            Some(_) => (),
            None    => e.add_track(track.clone())
        }
    }
    try!(e.save());
    Ok(e)
}

pub fn show_track(req: &mut Request) -> IronResult<Response> {
    let ref track_id = req.extensions.get::<Router>().unwrap()
                          .find("track_id").unwrap();
    let json_type = Header(ContentType(Mime::from_str("application/json").ok().unwrap()));
    match Track::find_by_id(track_id) {
        Ok(track) => {
            Ok(Response::with((status::Ok,
                               json_type,
                               track.to_json().to_string())))
        },
        Err(e) => Ok(e.as_response())
    }
}

pub fn show_track_by_provider_id(req: &mut Request) -> IronResult<Response> {
    let provider   = req.extensions.get::<Router>().unwrap().find("provider").unwrap();
    let identifier = req.extensions.get::<Router>().unwrap().find("id").unwrap();
    let json_type  = Header(ContentType(Mime::from_str("application/json").ok().unwrap()));
    let p = &Provider::new(provider.to_string());
    match Track::find_by(p, identifier) {
        Ok(track) => {
            Ok(Response::with((status::Ok,
                               json_type,
                               track.to_json().to_string())))
        },
        Err(e) => Ok(e.as_response())
    }
}

pub fn update_track(req: &mut Request) -> IronResult<Response> {
    let json_type = Header(ContentType(Mime::from_str("application/json").ok().unwrap()));
    fn param_as_string(req: &mut Request, key: &str) -> Option<String> {
        match req.get_ref::<UrlEncodedBody>() {
            Ok(ref params) => match params.get(key) {
                Some(val) => Some(val[0].clone()),
                None      => None
            },
            Err(_) => None
        }
    }

    fn query_as_string(req: &mut Request, key: &str) -> String {
        return req.extensions.get::<Router>().unwrap()
                  .find(key).unwrap().to_string();
    }

    match Track::find_by_id(&query_as_string(req, "track_id")) {
        Ok(mut track) => {
            match param_as_string(req, "title") {
                Some(title) => track.title = title,
                None        => println!("no title")
            }
            match param_as_string(req, "url") {
                Some(url) => track.url = url,
                None      => println!("no url")
            }
            match track.save() {
                Ok(_) => Ok(Response::with((status::Ok,
                                         json_type,
                                         track.to_json().to_string()))),
                Err(e) =>  Ok(e.as_response())
            }
        },
        Err(e) =>  {
            Ok(e.as_response())
        }
    }
}

pub fn main() {
    let path = Path::new("public");
    let mut mount = Mount::new();
    mount.mount("/web/", Static::new(Path::new(path)));
    let router = router!(
                         playlistify: get  "/playlistify"          => playlistify,
                          show_track: get  "/tracks/:track_id"     => show_track,
                        update_track: post "/tracks/:track_id"     => update_track,
           show_track_by_provider_id: get  "/tracks/:provider/:id" => show_track_by_provider_id,
                                 web: get  "/*"                    => mount,
    );
    let port_str = match std::env::var("PORT") {
        Ok(n)    => n,
        Err(_) => "8080".to_string()
    };
    let port: u16 = match port_str.trim().parse() {
        Ok(n) => n,
        Err(_) => {
            println!("Faild to parse port");
            return;
        }
    };
    println!("PORT {}", port_str);
    let ip = Ipv4Addr::new(0, 0, 0, 0);
    Iron::new(router).http(SocketAddrV4::new(ip, port)).unwrap();
}
<commit_msg>Implement GET `/entries` api that returns entries<commit_after>extern crate iron;
#[macro_use]
extern crate router;
extern crate staticfile;
extern crate mount;
extern crate urlencoded;
extern crate rustc_serialize;
extern crate html5ever;
extern crate regex;
extern crate uuid;

use std::net::SocketAddrV4;
use std::net::Ipv4Addr;
use std::path::Path;
use iron::prelude::*;
use iron::status;
use iron::headers::{ContentType};
use iron::modifiers::Header;
use iron::mime::Mime;
use staticfile::Static;
use mount::Mount;
use router::{Router};
use urlencoded::UrlEncodedQuery;
use urlencoded::UrlEncodedBody;
use std::str::FromStr;

#[macro_use]
extern crate string_cache;

extern crate pink_spider;

use pink_spider::error::Error;
use pink_spider::scraper::extract;
use pink_spider::model::{Track, Entry, Provider};
use rustc_serialize::json::{ToJson, Json};

static JSON: &'static str = "application/json";

pub fn index_entries(req: &mut Request) -> IronResult<Response> {
    let json_type = Header(ContentType(Mime::from_str(JSON).ok().unwrap()));
    let entries = Entry::find();
    let json_obj: Json   = entries.to_json();
    let json_str: String = json_obj.to_string();
    Ok(Response::with((status::Ok, json_type, json_str)))
}

pub fn playlistify(req: &mut Request) -> IronResult<Response> {
    let json_type = Header(ContentType(Mime::from_str("application/json").ok().unwrap()));
    match req.get_ref::<UrlEncodedQuery>() {
        Ok(ref params) => {
            match params.get("url") {
                Some(url) => {
                    let defaults = &vec!("false".to_string());
                    let force    = params.get("force").unwrap_or(defaults);
                    match find_or_playlistify_entry(&url[0], force.len() > 0 && &force[0] == "true") {
                        Ok(entry) => {
                            let json_obj: Json   = entry.to_json();
                            let json_str: String = json_obj.to_string();
                            Ok(Response::with((status::Ok, json_type, json_str)))
                        },
                        Err(e) => Ok(e.as_response())
                    }
                },
                None => Ok(Error::BadRequest.as_response())
            }
        }
        Err(_) => Ok(Error::BadRequest.as_response())
    }
}

pub fn find_or_playlistify_entry(url: &str, force: bool) -> Result<Entry, Error> {
    match Entry::find_by_url(url) {
        Ok(entry) => {
            println!("Get entry from database cache: {}", url);
            if force {
                println!("Update entry: {}", url);
                let entry = try!(playlistify_entry(entry));
                Ok(entry)
            } else {
                Ok(entry)
            }
        },
        Err(_) => {
            let entry = try!(Entry::create_by_url(url.to_string()));
            let entry = try!(playlistify_entry(entry));
            println!("Create new entry to database cache: {}", url);
            Ok(entry)
        },
    }
}

pub fn playlistify_entry(entry: Entry) -> Result<Entry, Error> {
    let mut e = entry.clone();
    let product = try!(extract(&entry.url));
    match product.og_obj {
        Some(og_obj) => {
            e.title       = Some(og_obj.title);
            e.description = og_obj.description;
            e.locale      = og_obj.locale;
            e.visual_url  = og_obj.images.first().map(|i| i.url.clone());
        },
        None => (),
    }
    for t in product.tracks {
        let track = try!(Track::find_or_create(t.provider,
                                               t.title,
                                               t.url,
                                               t.identifier));
        match entry.tracks.iter().find(|&t| t.id == track.id) {
            Some(_) => (),
            None    => e.add_track(track.clone())
        }
    }
    try!(e.save());
    Ok(e)
}

pub fn show_track(req: &mut Request) -> IronResult<Response> {
    let ref track_id = req.extensions.get::<Router>().unwrap()
                          .find("track_id").unwrap();
    let json_type = Header(ContentType(Mime::from_str("application/json").ok().unwrap()));
    match Track::find_by_id(track_id) {
        Ok(track) => {
            Ok(Response::with((status::Ok,
                               json_type,
                               track.to_json().to_string())))
        },
        Err(e) => Ok(e.as_response())
    }
}

pub fn show_track_by_provider_id(req: &mut Request) -> IronResult<Response> {
    let provider   = req.extensions.get::<Router>().unwrap().find("provider").unwrap();
    let identifier = req.extensions.get::<Router>().unwrap().find("id").unwrap();
    let json_type  = Header(ContentType(Mime::from_str("application/json").ok().unwrap()));
    let p = &Provider::new(provider.to_string());
    match Track::find_by(p, identifier) {
        Ok(track) => {
            Ok(Response::with((status::Ok,
                               json_type,
                               track.to_json().to_string())))
        },
        Err(e) => Ok(e.as_response())
    }
}

pub fn update_track(req: &mut Request) -> IronResult<Response> {
    let json_type = Header(ContentType(Mime::from_str("application/json").ok().unwrap()));
    fn param_as_string(req: &mut Request, key: &str) -> Option<String> {
        match req.get_ref::<UrlEncodedBody>() {
            Ok(ref params) => match params.get(key) {
                Some(val) => Some(val[0].clone()),
                None      => None
            },
            Err(_) => None
        }
    }

    fn query_as_string(req: &mut Request, key: &str) -> String {
        return req.extensions.get::<Router>().unwrap()
                  .find(key).unwrap().to_string();
    }

    match Track::find_by_id(&query_as_string(req, "track_id")) {
        Ok(mut track) => {
            match param_as_string(req, "title") {
                Some(title) => track.title = title,
                None        => println!("no title")
            }
            match param_as_string(req, "url") {
                Some(url) => track.url = url,
                None      => println!("no url")
            }
            match track.save() {
                Ok(_) => Ok(Response::with((status::Ok,
                                         json_type,
                                         track.to_json().to_string()))),
                Err(e) =>  Ok(e.as_response())
            }
        },
        Err(e) =>  {
            Ok(e.as_response())
        }
    }
}

pub fn main() {
    let path = Path::new("public");
    let mut mount = Mount::new();
    mount.mount("/web/", Static::new(Path::new(path)));
    let router = router!(
                         playlistify: get  "/playlistify"          => playlistify,
                          show_track: get  "/tracks/:track_id"     => show_track,
                        update_track: post "/tracks/:track_id"     => update_track,
           show_track_by_provider_id: get  "/tracks/:provider/:id" => show_track_by_provider_id,
                       index_entries: get  "/entries"              => index_entries,
                                 web: get  "/*"                    => mount,
    );
    let port_str = match std::env::var("PORT") {
        Ok(n)    => n,
        Err(_) => "8080".to_string()
    };
    let port: u16 = match port_str.trim().parse() {
        Ok(n) => n,
        Err(_) => {
            println!("Faild to parse port");
            return;
        }
    };
    println!("PORT {}", port_str);
    let ip = Ipv4Addr::new(0, 0, 0, 0);
    Iron::new(router).http(SocketAddrV4::new(ip, port)).unwrap();
}
<|endoftext|>


<commit_before>use ast::{TIdent, TNumber, TString, TSemicolon, TComment, TColon, TDot, TEqual, TOpenParen, TCloseParen, TComma, TOpenBlock, TCloseBlock, TOpenArray, TCloseArray, TQuestion, TBinOp, TAssignOp, TUnaryOp, TArrow};
use ast::{OpAdd, OpSub, OpMul, OpDiv, OpMod};
use ast::{BitAnd, BitOr, BitXor, BitShl, BitShr};
use ast::{CompEqual, CompStrictEqual, CompNotEqual, CompStrictNotEqual, CompLessThan, CompGreaterThan, CompLessThanOrEqual, CompGreaterThanOrEqual};
use ast::{LogAnd, LogOr};
use ast::{UnaryNot};
use ast::{BinNum, BinBit, BinComp, BinLog};
use ast::{Token, TokenData};
use std::io::{BufReader, BufferedReader, Buffer, IoResult, EndOfFile};
use std::strbuf::StrBuf;
use std::char::from_u32;
use std::num::from_str_radix;
#[deriving(Clone, Eq)]
/// The type of string used
pub enum StringType {
	/// `"` - Double-quoted
	DoubleQuote,
	/// `'` - Single-quoted
	SingleQuote
}
#[deriving(Clone, Eq)]
/// The type of comment used
pub enum CommentType {
	/// `/*...*/` - A multi-line comment
	MultiLineComment,
	/// `//...` - A single-line comment
	SingleLineComment
}
#[deriving(Clone, Eq)]
/// The type of number used
pub enum NumberType {
	/// A decimal number, such as `3.1415`
	DecimalNumber,
	/// A hexadecimal number, such as `0xFF00FF`
	HexadecimalNumber,
	/// An octal number, such as `011`
	OctalNumber
}
/// A Javascript lexer
pub struct Lexer<B> {
	/// The list of tokens generated so far
	pub tokens : Vec<Token>,
	/// The current line number in the script
	line_number : uint,
	/// The current column number in the script
	column_number : uint,
	/// The reader
	buffer: B,
	/// The peeked character buffer
	peek_buffer: StrBuf
}
impl<B:Buffer> Lexer<B> {
	/// Creates a new lexer with empty buffers
	pub fn new(buffer: B) -> Lexer<B> {
		return Lexer {
			tokens: Vec::new(),
			line_number: 1,
			column_number: 0,
			buffer: buffer,
			peek_buffer: StrBuf::new()
		};
	}
	fn push_token(&mut self, tk:TokenData) {
		self.tokens.push(Token::new(tk, self.line_number, self.column_number))
	}
	/// Processes an input stream from a string into an array of tokens
	pub fn lex_str(script:&str) -> Vec<Token> {
		let script_bytes:&[u8] = script.as_bytes();
		let reader = BufReader::new(script_bytes);
		let buf_reader = BufferedReader::new(reader);
		let mut lexer = Lexer::new(buf_reader);
		lexer.lex().unwrap();
		lexer.tokens
	}
	fn next(&mut self) -> IoResult<char> {
		if self.peek_buffer.len() == 0 {
			self.buffer.read_char()
		} else {
			Ok(match self.peek_buffer.pop_char() {
				Some(v) => v,
				None => unreachable!()
			})
		}
	}
	fn peek_for(&mut self, peek:char) -> bool {
		if self.peek_buffer.len() > 0 {
			self.peek_buffer.as_slice().char_at(self.peek_buffer.len() - 1) == peek
		} else {
			match self.buffer.read_char() {
				Ok(ch) if ch == peek => {
					self.column_number += 1;
					true
				},
				Ok(ch) if ch != peek => {
					self.peek_buffer.push_char(ch);
					false
				},
				_ => false
			}
		}
	}
	/// Processes an input stream from the `buffer` into a vector of tokens
	pub fn lex(&mut self) -> IoResult<()> {
		loop {
			let ch = match self.next() {
				Ok(ch) => ch,
				Err(ref err) if err.kind == EndOfFile => break,
				Err(err) => return Err(err)
			};
			self.column_number += 1;
			match ch {
				'"' | '\'' => {
					let mut buf = StrBuf::new();
					loop {
						match try!(self.next()) {
							'\'' if ch == '\'' => {
								break;
							},
							'"' if ch == '"' => {
								break;
							},
							'\\' => {
								let escape = try!(self.next());
								if escape != '\n' {
									let escaped_ch = match escape {
										'n' => '\n',
										'r' => '\r',
										't' => '\t',
										'b' => '\x08',
										'f' => '\x0c',
										'0' => '\0',
										'x' => {
											let mut nums = StrBuf::with_capacity(2);
											for _ in range(0, 2) {
												nums.push_char(try!(self.next()));
											}
											self.column_number += 2;
											let as_num = match from_str_radix(nums.as_slice(), 16) {
												Some(v) => v,
												None => 0
											};
											match from_u32(as_num) {
												Some(v) => v,
												None => fail!("{}:{}: {} is not a valid unicode scalar value", self.line_number, self.column_number, as_num)
											}
										},
										'u' => {
											let mut nums = StrBuf::new();
											for _ in range(0, 4) {
												nums.push_char(try!(self.next()));
											}
											self.column_number += 4;
											let as_num = match from_str_radix(nums.as_slice(), 16) {
												Some(v) => v,
												None => 0
											};
											match from_u32(as_num) {
												Some(v) => v,
												None => fail!("{}:{}: {} is not a valid unicode scalar value", self.line_number, self.column_number, as_num)
											}
										},
										'\'' | '"' => escape,
										_ => fail!("{}:{}: Invalid escape `{}`", self.line_number, self.column_number, ch)
									};
									buf.push_char(escaped_ch);
								}
							},
							ch => buf.push_char(ch)
						}
					}
					self.push_token(TString(buf))
				},
				'0' if self.peek_for('x') => {
					let mut buf = StrBuf::new();
					loop {
						match try!(self.next()) {
							ch if ch.is_digit_radix(16) => buf.push_char(ch),
							ch => {
								self.peek_buffer.push_char(ch);
								break;
							}
						}
					}
					self.push_token(TNumber(from_str_radix(buf.as_slice(), 16).unwrap()));
				},
				'0' => {
					let mut buf = StrBuf::new();
					let mut gone_decimal = false;
					loop {
						let ch = try!(self.next());
						match ch {
							_ if ch.is_digit_radix(8) => buf.push_char(ch),
							'8' | '9' | '.' => {
								gone_decimal = true;
								buf.push_char(ch);
							},
							ch => {
								self.peek_buffer.push_char(ch);
								break;
							}
						}
					}
					self.push_token(TNumber(if gone_decimal {
						from_str(buf.as_slice())
					} else {
						from_str_radix(buf.as_slice(), 8)
					}.unwrap()));
				},
				_ if ch.is_digit() => {
					let mut buf = StrBuf::new();
					buf.push_char(ch);
					loop {
						let ch = try!(self.next());
						match ch {
							'.' => buf.push_char(ch),
							_ if ch.is_digit() => buf.push_char(ch),
							_ => {
								self.peek_buffer.push_char(ch);
								break;
							}
						}
					}
					self.push_token(TNumber(from_str(buf.as_slice()).unwrap()));
				},
				_ if ch.is_alphabetic() || ch == '$' || ch == '_' => {
					let mut buf = StrBuf::new();
					buf.push_char(ch);
					loop {
						let ch = try!(self.next());
						match ch {
							_ if ch.is_alphabetic() || ch.is_digit() => buf.push_char(ch),
							_ => {
								self.peek_buffer.push_char(ch);
								break;
							}
						}
					}
					self.push_token(TIdent(buf));
				},
				';' => {
					self.push_token(TSemicolon);
				},
				':' => {
					self.push_token(TColon);
				},
				'.' => {
					self.push_token(TDot);
				},
				'(' => {
					self.push_token(TOpenParen);
				},
				')' => {
					self.push_token(TCloseParen);
				},
				',' => {
					self.push_token(TComma);
				},
				'{' => {
					self.push_token(TOpenBlock);
				},
				'}' => {
					self.push_token(TCloseBlock);
				},
				'[' => {
					self.push_token(TOpenArray);
				},
				']' => {
					self.push_token(TCloseArray);
				},
				'?' => {
					self.push_token(TQuestion);
				},
				'/' if self.peek_for('/') => {
					let mut buf = StrBuf::new();
					loop {
						match try!(self.next()) {
							'\n' => break,
							ch => buf.push_char(ch)
						}
					}
					self.push_token(TComment(buf));
				},
				'/' if self.peek_for('*') => {
					let mut buf = StrBuf::new();
					loop {
						match try!(self.next()) {
							'\n' => break,
							'*' if self.peek_for('/') => break,
							ch => buf.push_char(ch)
						}
					}
					self.push_token(TComment(buf));
				},
				'/' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinNum(OpDiv)));
				},
				'/' => {
					self.push_token(TBinOp(BinNum(OpDiv)));
				},
				'*' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinNum(OpMul)));
				},
				'*' => {
					self.push_token(TBinOp(BinNum(OpMul)));
				},
				'+' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinNum(OpAdd)));
				},
				'+' => {
					self.push_token(TBinOp(BinNum(OpAdd)));
				},
				'-' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinNum(OpSub)));
				},
				'-' => {
					self.push_token(TBinOp(BinNum(OpSub)));
				},
				'%' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinNum(OpMod)));
				},
				'%' => {
					self.push_token(TBinOp(BinNum(OpMod)));
				},
				'|' if self.peek_for('|') => {
					if self.peek_for('=') {
						self.push_token(TAssignOp(BinLog(LogOr)));
					} else {
						self.push_token(TBinOp(BinLog(LogOr)));
					}
				},
				'|' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinBit(BitOr)));
				},
				'|' => {
					self.push_token(TBinOp(BinBit(BitOr)));
				},
				'&' if self.peek_for('&') => {
					if self.peek_for('=') {
						self.push_token(TAssignOp(BinLog(LogAnd)));
					} else {
						self.push_token(TBinOp(BinLog(LogAnd)));
					}
				},
				'&' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinBit(BitAnd)));
				},
				'&' => {
					self.push_token(TBinOp(BinBit(BitAnd)));
				},
				'^' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinBit(BitXor)));
				},
				'^' => {
					self.push_token(TBinOp(BinBit(BitXor)));
				},
				'=' if self.peek_for('>') => {
					self.push_token(TArrow);
				},
				'=' if self.peek_for('=') => {
					if self.peek_for('=') {
						self.push_token(TBinOp(BinComp(CompStrictEqual)));
					} else {
						self.push_token(TBinOp(BinComp(CompEqual)));
					}
				},
				'=' => {
					self.push_token(TEqual);
				},
				'<' if self.peek_for('=') => {
					self.push_token(TBinOp(BinComp(CompLessThanOrEqual)));
				},
				'<' if self.peek_for('<') => {
					if self.peek_for('=') {
						self.push_token(TAssignOp(BinBit(BitShl)));
					} else {
						self.push_token(TBinOp(BinBit(BitShl)));
					}
				},
				'<' => {
					self.push_token(TBinOp(BinComp(CompLessThan)));
				},
				'>' if self.peek_for('=') => {
					self.push_token(TBinOp(BinComp(CompGreaterThanOrEqual)));
				},
				'>' if self.peek_for('>') => {
					if self.peek_for('=') {
						self.push_token(TAssignOp(BinBit(BitShr)));
					} else {
						self.push_token(TBinOp(BinBit(BitShr)));
					}
				},
				'>' => {
					self.push_token(TBinOp(BinComp(CompGreaterThan)));
				},
				'!' if self.peek_for('=') => {
					if self.peek_for('=') {
						self.push_token(TBinOp(BinComp(CompStrictNotEqual)));
					} else {
						self.push_token(TBinOp(BinComp(CompNotEqual)));
					}
				},
				'!' => {
					self.push_token(TUnaryOp(UnaryNot));
				},
				'\n' => {
					self.line_number += 1;
					self.column_number = 0;
				},
				'\r' => {
					self.column_number = 0;
				},
				' ' => (),
				ch => fail!("{}:{}: Unexpected '{}'", self.line_number, self.column_number, ch)
			};
		}
		Ok(())
	}
}<commit_msg>Fix `peek_for` function to pop the peeked character if it matched the request when it is looking through the peek buffer<commit_after>use ast::{TIdent, TNumber, TString, TSemicolon, TComment, TColon, TDot, TEqual, TOpenParen, TCloseParen, TComma, TOpenBlock, TCloseBlock, TOpenArray, TCloseArray, TQuestion, TBinOp, TAssignOp, TUnaryOp, TArrow};
use ast::{OpAdd, OpSub, OpMul, OpDiv, OpMod};
use ast::{BitAnd, BitOr, BitXor, BitShl, BitShr};
use ast::{CompEqual, CompStrictEqual, CompNotEqual, CompStrictNotEqual, CompLessThan, CompGreaterThan, CompLessThanOrEqual, CompGreaterThanOrEqual};
use ast::{LogAnd, LogOr};
use ast::{UnaryNot};
use ast::{BinNum, BinBit, BinComp, BinLog};
use ast::{Token, TokenData};
use std::io::{BufReader, BufferedReader, Buffer, IoResult, EndOfFile};
use std::strbuf::StrBuf;
use std::char::from_u32;
use std::num::from_str_radix;
#[deriving(Clone, Eq)]
/// The type of string used
pub enum StringType {
	/// `"` - Double-quoted
	DoubleQuote,
	/// `'` - Single-quoted
	SingleQuote
}
#[deriving(Clone, Eq)]
/// The type of comment used
pub enum CommentType {
	/// `/*...*/` - A multi-line comment
	MultiLineComment,
	/// `//...` - A single-line comment
	SingleLineComment
}
#[deriving(Clone, Eq)]
/// The type of number used
pub enum NumberType {
	/// A decimal number, such as `3.1415`
	DecimalNumber,
	/// A hexadecimal number, such as `0xFF00FF`
	HexadecimalNumber,
	/// An octal number, such as `011`
	OctalNumber
}
/// A Javascript lexer
pub struct Lexer<B> {
	/// The list of tokens generated so far
	pub tokens : Vec<Token>,
	/// The current line number in the script
	line_number : uint,
	/// The current column number in the script
	column_number : uint,
	/// The reader
	buffer: B,
	/// The peeked character buffer
	peek_buffer: StrBuf
}
impl<B:Buffer> Lexer<B> {
	/// Creates a new lexer with empty buffers
	pub fn new(buffer: B) -> Lexer<B> {
		return Lexer {
			tokens: Vec::new(),
			line_number: 1,
			column_number: 0,
			buffer: buffer,
			peek_buffer: StrBuf::new()
		};
	}
	fn push_token(&mut self, tk:TokenData) {
		self.tokens.push(Token::new(tk, self.line_number, self.column_number))
	}
	/// Processes an input stream from a string into an array of tokens
	pub fn lex_str(script:&str) -> Vec<Token> {
		let script_bytes:&[u8] = script.as_bytes();
		let reader = BufReader::new(script_bytes);
		let buf_reader = BufferedReader::new(reader);
		let mut lexer = Lexer::new(buf_reader);
		lexer.lex().unwrap();
		lexer.tokens
	}
	fn next(&mut self) -> IoResult<char> {
		if self.peek_buffer.len() == 0 {
			self.buffer.read_char()
		} else {
			Ok(match self.peek_buffer.pop_char() {
				Some(v) => v,
				None => unreachable!()
			})
		}
	}
	fn peek_for(&mut self, peek:char) -> bool {
		if self.peek_buffer.len() > 0 {
			let matched = self.peek_buffer.as_slice().char_at(self.peek_buffer.len() - 1) == peek;
			if matched {
				self.peek_buffer.pop_char();
			}
			matched
		} else {
			match self.buffer.read_char() {
				Ok(ch) if ch == peek => {
					self.column_number += 1;
					true
				},
				Ok(ch) if ch != peek => {
					self.peek_buffer.push_char(ch);
					false
				},
				_ => false
			}
		}
	}
	/// Processes an input stream from the `buffer` into a vector of tokens
	pub fn lex(&mut self) -> IoResult<()> {
		loop {
			let ch = match self.next() {
				Ok(ch) => ch,
				Err(ref err) if err.kind == EndOfFile => break,
				Err(err) => return Err(err)
			};
			self.column_number += 1;
			match ch {
				'"' | '\'' => {
					let mut buf = StrBuf::new();
					loop {
						match try!(self.next()) {
							'\'' if ch == '\'' => {
								break;
							},
							'"' if ch == '"' => {
								break;
							},
							'\\' => {
								let escape = try!(self.next());
								if escape != '\n' {
									let escaped_ch = match escape {
										'n' => '\n',
										'r' => '\r',
										't' => '\t',
										'b' => '\x08',
										'f' => '\x0c',
										'0' => '\0',
										'x' => {
											let mut nums = StrBuf::with_capacity(2);
											for _ in range(0, 2) {
												nums.push_char(try!(self.next()));
											}
											self.column_number += 2;
											let as_num = match from_str_radix(nums.as_slice(), 16) {
												Some(v) => v,
												None => 0
											};
											match from_u32(as_num) {
												Some(v) => v,
												None => fail!("{}:{}: {} is not a valid unicode scalar value", self.line_number, self.column_number, as_num)
											}
										},
										'u' => {
											let mut nums = StrBuf::new();
											for _ in range(0, 4) {
												nums.push_char(try!(self.next()));
											}
											self.column_number += 4;
											let as_num = match from_str_radix(nums.as_slice(), 16) {
												Some(v) => v,
												None => 0
											};
											match from_u32(as_num) {
												Some(v) => v,
												None => fail!("{}:{}: {} is not a valid unicode scalar value", self.line_number, self.column_number, as_num)
											}
										},
										'\'' | '"' => escape,
										_ => fail!("{}:{}: Invalid escape `{}`", self.line_number, self.column_number, ch)
									};
									buf.push_char(escaped_ch);
								}
							},
							ch => buf.push_char(ch)
						}
					}
					self.push_token(TString(buf))
				},
				'0' if self.peek_for('x') => {
					let mut buf = StrBuf::new();
					loop {
						match try!(self.next()) {
							ch if ch.is_digit_radix(16) => buf.push_char(ch),
							ch => {
								self.peek_buffer.push_char(ch);
								break;
							}
						}
					}
					self.push_token(TNumber(from_str_radix(buf.as_slice(), 16).unwrap()));
				},
				'0' => {
					let mut buf = StrBuf::new();
					let mut gone_decimal = false;
					loop {
						let ch = try!(self.next());
						match ch {
							_ if ch.is_digit_radix(8) => buf.push_char(ch),
							'8' | '9' | '.' => {
								gone_decimal = true;
								buf.push_char(ch);
							},
							ch => {
								self.peek_buffer.push_char(ch);
								break;
							}
						}
					}
					self.push_token(TNumber(if gone_decimal {
						from_str(buf.as_slice())
					} else {
						from_str_radix(buf.as_slice(), 8)
					}.unwrap()));
				},
				_ if ch.is_digit() => {
					let mut buf = StrBuf::new();
					buf.push_char(ch);
					loop {
						let ch = try!(self.next());
						match ch {
							'.' => buf.push_char(ch),
							_ if ch.is_digit() => buf.push_char(ch),
							_ => {
								self.peek_buffer.push_char(ch);
								break;
							}
						}
					}
					self.push_token(TNumber(from_str(buf.as_slice()).unwrap()));
				},
				_ if ch.is_alphabetic() || ch == '$' || ch == '_' => {
					let mut buf = StrBuf::new();
					buf.push_char(ch);
					loop {
						let ch = try!(self.next());
						match ch {
							_ if ch.is_alphabetic() || ch.is_digit() => buf.push_char(ch),
							_ => {
								self.peek_buffer.push_char(ch);
								break;
							}
						}
					}
					self.push_token(TIdent(buf));
				},
				';' => {
					self.push_token(TSemicolon);
				},
				':' => {
					self.push_token(TColon);
				},
				'.' => {
					self.push_token(TDot);
				},
				'(' => {
					self.push_token(TOpenParen);
				},
				')' => {
					self.push_token(TCloseParen);
				},
				',' => {
					self.push_token(TComma);
				},
				'{' => {
					self.push_token(TOpenBlock);
				},
				'}' => {
					self.push_token(TCloseBlock);
				},
				'[' => {
					self.push_token(TOpenArray);
				},
				']' => {
					self.push_token(TCloseArray);
				},
				'?' => {
					self.push_token(TQuestion);
				},
				'/' if self.peek_for('/') => {
					let mut buf = StrBuf::new();
					loop {
						match try!(self.next()) {
							'\n' => break,
							ch => buf.push_char(ch)
						}
					}
					self.push_token(TComment(buf));
				},
				'/' if self.peek_for('*') => {
					let mut buf = StrBuf::new();
					loop {
						match try!(self.next()) {
							'\n' => break,
							'*' if self.peek_for('/') => break,
							ch => buf.push_char(ch)
						}
					}
					self.push_token(TComment(buf));
				},
				'/' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinNum(OpDiv)));
				},
				'/' => {
					self.push_token(TBinOp(BinNum(OpDiv)));
				},
				'*' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinNum(OpMul)));
				},
				'*' => {
					self.push_token(TBinOp(BinNum(OpMul)));
				},
				'+' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinNum(OpAdd)));
				},
				'+' => {
					self.push_token(TBinOp(BinNum(OpAdd)));
				},
				'-' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinNum(OpSub)));
				},
				'-' => {
					self.push_token(TBinOp(BinNum(OpSub)));
				},
				'%' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinNum(OpMod)));
				},
				'%' => {
					self.push_token(TBinOp(BinNum(OpMod)));
				},
				'|' if self.peek_for('|') => {
					if self.peek_for('=') {
						self.push_token(TAssignOp(BinLog(LogOr)));
					} else {
						self.push_token(TBinOp(BinLog(LogOr)));
					}
				},
				'|' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinBit(BitOr)));
				},
				'|' => {
					self.push_token(TBinOp(BinBit(BitOr)));
				},
				'&' if self.peek_for('&') => {
					if self.peek_for('=') {
						self.push_token(TAssignOp(BinLog(LogAnd)));
					} else {
						self.push_token(TBinOp(BinLog(LogAnd)));
					}
				},
				'&' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinBit(BitAnd)));
				},
				'&' => {
					self.push_token(TBinOp(BinBit(BitAnd)));
				},
				'^' if self.peek_for('=') => {
					self.push_token(TAssignOp(BinBit(BitXor)));
				},
				'^' => {
					self.push_token(TBinOp(BinBit(BitXor)));
				},
				'=' if self.peek_for('>') => {
					self.push_token(TArrow);
				},
				'=' if self.peek_for('=') => {
					if self.peek_for('=') {
						self.push_token(TBinOp(BinComp(CompStrictEqual)));
					} else {
						self.push_token(TBinOp(BinComp(CompEqual)));
					}
				},
				'=' => {
					self.push_token(TEqual);
				},
				'<' if self.peek_for('=') => {
					self.push_token(TBinOp(BinComp(CompLessThanOrEqual)));
				},
				'<' if self.peek_for('<') => {
					if self.peek_for('=') {
						self.push_token(TAssignOp(BinBit(BitShl)));
					} else {
						self.push_token(TBinOp(BinBit(BitShl)));
					}
				},
				'<' => {
					self.push_token(TBinOp(BinComp(CompLessThan)));
				},
				'>' if self.peek_for('=') => {
					self.push_token(TBinOp(BinComp(CompGreaterThanOrEqual)));
				},
				'>' if self.peek_for('>') => {
					if self.peek_for('=') {
						self.push_token(TAssignOp(BinBit(BitShr)));
					} else {
						self.push_token(TBinOp(BinBit(BitShr)));
					}
				},
				'>' => {
					self.push_token(TBinOp(BinComp(CompGreaterThan)));
				},
				'!' if self.peek_for('=') => {
					if self.peek_for('=') {
						self.push_token(TBinOp(BinComp(CompStrictNotEqual)));
					} else {
						self.push_token(TBinOp(BinComp(CompNotEqual)));
					}
				},
				'!' => {
					self.push_token(TUnaryOp(UnaryNot));
				},
				'\n' => {
					self.line_number += 1;
					self.column_number = 0;
				},
				'\r' => {
					self.column_number = 0;
				},
				' ' => (),
				ch => fail!("{}:{}: Unexpected '{}'", self.line_number, self.column_number, ch)
			};
		}
		Ok(())
	}
}<|endoftext|>


<commit_before>#![feature(custom_attribute, custom_derive, proc_macro)]
#[macro_use] extern crate diesel_codegen;
#[macro_use] extern crate diesel;
extern crate dotenv;
extern crate iron;
extern crate staticfile;
extern crate router;
extern crate mount;
extern crate params;
extern crate rustc_serialize;
extern crate time;

use iron::prelude::*;
use staticfile::Static;
use router::Router;
use mount::Mount;
use std::path::Path;

mod api;
mod database;
mod schema;
mod logger;
mod models;

fn main() {
    let mut router = Router::new();
    router.get("/", api::v1::index, "api");
    router.get("/translations", api::v1::translations_index, "translations_index");
    router.post("/translations", api::v1::translations_create, "translations_create");

    let mut mount = Mount::new();
    mount.mount("/", Static::new(Path::new("src/frontend/public/")));
    mount.mount("/api/v1", router);

    let mut chain = Chain::new(mount);
    chain.link_before(logger::RequestLogger);
    chain.link_after(logger::RequestLogger);

    Iron::new(chain).http("localhost:3000").unwrap();
}
<commit_msg>Bind server from environment variable<commit_after>#![feature(custom_attribute, custom_derive, proc_macro)]
#[macro_use] extern crate diesel_codegen;
#[macro_use] extern crate diesel;
extern crate dotenv;
extern crate iron;
extern crate staticfile;
extern crate router;
extern crate mount;
extern crate params;
extern crate rustc_serialize;
extern crate time;

use dotenv::dotenv;
use iron::prelude::*;
use staticfile::Static;
use router::Router;
use mount::Mount;
use std::env;
use std::path::Path;

mod api;
mod database;
mod schema;
mod logger;
mod models;

fn main() {
    dotenv().ok();

    let mut router = Router::new();
    router.get("/", api::v1::index, "api");
    router.get("/translations", api::v1::translations_index, "translations_index");
    router.post("/translations", api::v1::translations_create, "translations_create");

    let mut mount = Mount::new();
    mount.mount("/", Static::new(Path::new("src/frontend/public/")));
    mount.mount("/api/v1", router);

    let mut chain = Chain::new(mount);
    chain.link_before(logger::RequestLogger);
    chain.link_after(logger::RequestLogger);

    let bind = env::var("LUGH_BIND").unwrap_or("localhost:3000".to_string());
    println!("Start application on {}", bind);

    Iron::new(chain).http(bind.as_str())
        .expect("Can’t start application");
}
<|endoftext|>


<commit_before>use color::RGB;
use linear::{Direction, Position};
use std::default::Default;

pub struct LightProp {
  pub diff: RGB,
  pub spec: RGB,
  pub gloss: f32
}

pub struct Light<L> {
  pub prop: LightProp,
  pub feature: L
}

pub type Dir = Light<Direction>;
pub type Omni = Light<Position>;

impl LightProp {
  pub fn new(diff: RGB, spec: RGB, gloss: f32) -> Self {
    LightProp {
      diff: diff,
      spec: spec,
      gloss: gloss
    }
  }
}

impl Default for LightProp {
  fn default() -> Self {
    LightProp {
      diff: RGB::new(0.6, 0.6, 0.7),
      spec: RGB::new(0.6, 0.6, 0.7),
      gloss: 10.
    }
  }
}

impl<L> Light<L> {
  pub fn new(prop: LightProp, feature: L) -> Self {
    Light {
      prop: prop,
      feature: feature
    }
  }
}
<commit_msg>Comment on light types.<commit_after>use color::RGB;
use linear::{Direction, Position};
use std::default::Default;

pub struct LightProp {
  pub diff: RGB,
  pub spec: RGB,
  pub gloss: f32
}

pub struct Light<L> {
  pub prop: LightProp,
  pub feature: L
}

// TODO: use wrappers here, because those resolve to the actual same type
pub type Dir = Light<Direction>;
pub type Omni = Light<Position>;

impl LightProp {
  pub fn new(diff: RGB, spec: RGB, gloss: f32) -> Self {
    LightProp {
      diff: diff,
      spec: spec,
      gloss: gloss
    }
  }
}

impl Default for LightProp {
  fn default() -> Self {
    LightProp {
      diff: RGB::new(0.6, 0.6, 0.7),
      spec: RGB::new(0.6, 0.6, 0.7),
      gloss: 10.
    }
  }
}

impl<L> Light<L> {
  pub fn new(prop: LightProp, feature: L) -> Self {
    Light {
      prop: prop,
      feature: feature
    }
  }
}
<|endoftext|>


<commit_before>#![feature(io)]

extern crate argparse;
extern crate bit_set;
extern crate compress;
extern crate libc;

use std::fs;
use std::io;
use std::mem;
use std::path;
use std::slice;

use argparse::{Store, StoreTrue};

use bit_set::BitSet;

use libc::c_void;

//magic:
use std::io::Read;
use std::os::unix::io::AsRawFd;

type CharResult = Result<char, io::CharsError>;

static TRI_MAX: usize = 64 * 64 * 64;

fn simplify(wut: char) -> u8 {
    let c = match wut {
        'a' ... 'z' => (wut as u8 - 'a' as u8 + 'A' as u8) as char,
        _ => wut,
    };

    if c > 128 as char {
        if c.is_whitespace() {
            return 2;
        }
        if c.is_control() {
            return 0;
        }
        return 63;
    }

    let sym_end = 33u8;
    let letters = 21u8;

    match c {
        '\r' | '\n' => 1,
        '\t' | '\x0c' | '\x0b' | ' ' => 2,
        '!' => 3,
        '"' | '\'' | '`' => 4,
        '$' => 5,
        '%' => 6,
        '&' => 7,
        '(' ... '@' => 8 + (c as u8 - '(' as u8),
        'A' ... 'I' => sym_end + (c as u8 - 'A' as u8),
        'J' | 'K' => sym_end + letters,
        'L' ... 'P' => sym_end + (c as u8 - 'A' as u8) - 2,
        'Q' => sym_end + letters,
        'R' ... 'W' => sym_end + (c as u8 - 'A' as u8) - 3,
        'X' | 'Z' => sym_end + letters,
        'Y' => sym_end + letters - 1,
        '[' => 55,
        '\\' => 56,
        ']'=> 57,
        '^' | '~' | '#' => 58,
        '_' => 59,
        '{' ... '}' => 60 + (c as u8 - '{' as u8),
        _ => 0,
    }
}

fn explain(wut: u8) -> char {
    match wut {
        0 => 'X',
        1 => 'N',
        2 => ' ',
        3 => '!',
        4 => '"',
        5 => '$',
        6 => '%',
        7 => '&',
        8 ... 32 => (wut - 8 + '(' as u8) as char,
        33 ... 41 => (wut - 33 + 'a' as u8) as char,
        42 ... 46 => (wut - 42 + 'l' as u8) as char,
        47 ... 52 => (wut - 47 + 'r' as u8) as char,
        53 => 'y',
        54 => 'X',
        55 => '[',
        56 => '\\',
        57 => ']',
        58 => '#',
        59 => '_',
        60 ... 62 => (wut - 60 + '{' as u8) as char,
        63 => 'U',
        _ => 'D',
    }
}

fn unpack(wut: usize) -> String {
    let mut ret = String::with_capacity(3);
    ret.push(explain((wut / 64 / 64 % 64) as u8));
    ret.push(explain((wut / 64 % 64) as u8));
    ret.push(explain((wut % 64) as u8));
    return ret;
}

fn trigrams_for<T: Iterator<Item=CharResult>>(input: T) -> Result<BitSet, String> {
    let mut line: u64 = 1;
    let mut prev: [u8; 3] = [0; 3];
    let mut ret: BitSet = BitSet::with_capacity(64 * 64 * 64);

    for (off, maybe_char) in input.enumerate() {
        let c = try!(maybe_char.map_err(|e| {
            format!("line {}: file char {}: failed: {}", line, off, e)
        }));
        if '\n' == c {
            line += 1;
        }
        if '\0' == c {
            return Err(format!("line {}: null found: not a text file", line));
        }
        prev[0] = prev[1];
        prev[1] = prev[2];
        prev[2] = simplify(c);
        let tri: usize = 64 * 64 * prev[0] as usize + 64 * prev[1] as usize + prev[2] as usize;
        ret.insert(tri);
    }
    return Ok(ret);
}

struct Mapped<'a, T: 'a> {
    file: fs::File,
    map: *mut c_void,
    data: &'a mut [T],
}

impl <'a, T: 'a> Mapped<'a, T> {
    fn fixed_len<P>(path: P, len: usize) -> io::Result<Mapped<'a, T>>
        where P: AsRef<path::Path> {
        let file = fs::OpenOptions::new().read(true).write(true).create(true).open(path)?;
        file.set_len(mem::size_of::<T>() as u64 * len as u64)?;
        let map: *mut c_void = unsafe {
            libc::mmap(0 as *mut c_void,
                       len,
                       libc::PROT_READ | libc::PROT_WRITE,
                       libc::MAP_SHARED,
                       file.as_raw_fd(),
                       0)
        };

        assert_ne!(0 as *mut c_void, map);

        let data = unsafe { slice::from_raw_parts_mut(map as *mut T, len / mem::size_of::<T>()) };
        Ok(Mapped { file, map, data })
    }
}

impl <'a, T: 'a> Drop for Mapped<'a, T> {
    fn drop(&mut self) {
        unsafe {
            assert_eq!(0, libc::munmap(self.map, self.data.len() * mem::size_of::<T>()));
        }
        println!("mapping dropped");
    }
}

fn main() {
    let mut from: String = "".to_string();
    let mut simple = false;
    {
        let mut ap = argparse::ArgumentParser::new();
        ap.set_description("totally not a load of tools glued together");
        ap.refer(&mut from)
                .required()
                .add_option(&["-f", "--input-file"], Store,
                            "pack file to read");
        ap.refer(&mut simple)
                .add_option(&["--simple"], StoreTrue,
                            "not a pack, just a normal decompressed file");
        ap.parse_args_or_exit();
    }

    if simple {
        let fh = fs::File::open(from).expect("input file must exist and be readable");
        let trigrams = trigrams_for(fh.chars()).expect("trigramming must work");
        for found in trigrams.iter() {
            println!("{}: {}", found, unpack(found));
        }
        return;
    }

    let mut idx: Mapped<u32> = Mapped::fixed_len("idx", TRI_MAX).unwrap();
    idx.data[0] = 5;

    let page_size: usize = 1024;

    let pages_len: usize = (match fs::metadata("pages") {
        Ok(m) => m.len(),
        Err(e) => if e.kind() == io::ErrorKind::NotFound {
            0
        } else {
            panic!("couldn't get info on pages file: {}", e)
        }
    } / (mem::size_of::<u64>() as u64)) as usize;

    let mut pages: Mapped<u64> = Mapped::fixed_len("pages", pages_len + (page_size * 100)).unwrap();
    let mut free_page = pages.data.len() / page_size - 99;
    loop {
        if 0 != pages.data[(free_page - 1) * page_size] {
            break;
        }
        free_page -= 1;
        if 0 == free_page {
            break;
        }
    }

    unimplemented!();
}
<commit_msg>allocate new pages for new index items, and write to them<commit_after>#![feature(io)]

extern crate argparse;
extern crate bit_set;
extern crate compress;
extern crate libc;

use std::fs;
use std::io;
use std::mem;
use std::path;
use std::slice;

use argparse::{Store, StoreTrue};

use bit_set::BitSet;

use libc::c_void;

//magic:
use std::io::Read;
use std::os::unix::io::AsRawFd;

type CharResult = Result<char, io::CharsError>;

static TRI_MAX: usize = 64 * 64 * 64;

fn simplify(wut: char) -> u8 {
    let c = match wut {
        'a' ... 'z' => (wut as u8 - 'a' as u8 + 'A' as u8) as char,
        _ => wut,
    };

    if c > 128 as char {
        if c.is_whitespace() {
            return 2;
        }
        if c.is_control() {
            return 0;
        }
        return 63;
    }

    let sym_end = 33u8;
    let letters = 21u8;

    match c {
        '\r' | '\n' => 1,
        '\t' | '\x0c' | '\x0b' | ' ' => 2,
        '!' => 3,
        '"' | '\'' | '`' => 4,
        '$' => 5,
        '%' => 6,
        '&' => 7,
        '(' ... '@' => 8 + (c as u8 - '(' as u8),
        'A' ... 'I' => sym_end + (c as u8 - 'A' as u8),
        'J' | 'K' => sym_end + letters,
        'L' ... 'P' => sym_end + (c as u8 - 'A' as u8) - 2,
        'Q' => sym_end + letters,
        'R' ... 'W' => sym_end + (c as u8 - 'A' as u8) - 3,
        'X' | 'Z' => sym_end + letters,
        'Y' => sym_end + letters - 1,
        '[' => 55,
        '\\' => 56,
        ']'=> 57,
        '^' | '~' | '#' => 58,
        '_' => 59,
        '{' ... '}' => 60 + (c as u8 - '{' as u8),
        _ => 0,
    }
}

fn explain(wut: u8) -> char {
    match wut {
        0 => 'X',
        1 => 'N',
        2 => ' ',
        3 => '!',
        4 => '"',
        5 => '$',
        6 => '%',
        7 => '&',
        8 ... 32 => (wut - 8 + '(' as u8) as char,
        33 ... 41 => (wut - 33 + 'a' as u8) as char,
        42 ... 46 => (wut - 42 + 'l' as u8) as char,
        47 ... 52 => (wut - 47 + 'r' as u8) as char,
        53 => 'y',
        54 => 'X',
        55 => '[',
        56 => '\\',
        57 => ']',
        58 => '#',
        59 => '_',
        60 ... 62 => (wut - 60 + '{' as u8) as char,
        63 => 'U',
        _ => 'D',
    }
}

fn unpack(wut: usize) -> String {
    let mut ret = String::with_capacity(3);
    ret.push(explain((wut / 64 / 64 % 64) as u8));
    ret.push(explain((wut / 64 % 64) as u8));
    ret.push(explain((wut % 64) as u8));
    return ret;
}

fn trigrams_for<T: Iterator<Item=CharResult>>(input: T) -> Result<BitSet, String> {
    let mut line: u64 = 1;
    let mut prev: [u8; 3] = [0; 3];
    let mut ret: BitSet = BitSet::with_capacity(64 * 64 * 64);

    for (off, maybe_char) in input.enumerate() {
        let c = try!(maybe_char.map_err(|e| {
            format!("line {}: file char {}: failed: {}", line, off, e)
        }));
        if '\n' == c {
            line += 1;
        }
        if '\0' == c {
            return Err(format!("line {}: null found: not a text file", line));
        }
        prev[0] = prev[1];
        prev[1] = prev[2];
        prev[2] = simplify(c);
        let tri: usize = 64 * 64 * prev[0] as usize + 64 * prev[1] as usize + prev[2] as usize;
        ret.insert(tri);
    }
    return Ok(ret);
}

struct Mapped<'a, T: 'a> {
    file: fs::File,
    map: *mut c_void,
    data: &'a mut [T],
}

impl <'a, T: 'a> Mapped<'a, T> {
    fn fixed_len<P>(path: P, len: usize) -> io::Result<Mapped<'a, T>>
        where P: AsRef<path::Path> {
        let file = fs::OpenOptions::new().read(true).write(true).create(true).open(path)?;
        file.set_len(mem::size_of::<T>() as u64 * len as u64)?;
        let map: *mut c_void = unsafe {
            libc::mmap(0 as *mut c_void,
                       len * mem::size_of::<T>(),
                       libc::PROT_READ | libc::PROT_WRITE,
                       libc::MAP_SHARED,
                       file.as_raw_fd(),
                       0)
        };

        assert_ne!(0 as *mut c_void, map);

        let data = unsafe { slice::from_raw_parts_mut(map as *mut T, len) };
        Ok(Mapped { file, map, data })
    }
}

impl <'a, T: 'a> Drop for Mapped<'a, T> {
    fn drop(&mut self) {
        unsafe {
            assert_eq!(0, libc::munmap(self.map, self.data.len() * mem::size_of::<T>()));
        }
    }
}

fn main() {
    let mut from: String = "".to_string();
    let mut simple: u64 = 0;
    {
        let mut ap = argparse::ArgumentParser::new();
        ap.set_description("totally not a load of tools glued together");
        ap.refer(&mut from)
                .required()
                .add_option(&["-f", "--input-file"], Store,
                            "pack file to read");
        ap.refer(&mut simple)
                .add_option(&["--simple"], Store,
                            "not a pack, just a normal decompressed file");
        ap.parse_args_or_exit();
    }

    let mut idx: Mapped<u32> = Mapped::fixed_len("idx", TRI_MAX).unwrap();

    let page_size: usize = 1024;

    let pages_len: usize = (match fs::metadata("pages") {
        Ok(m) => m.len(),
        Err(e) => if e.kind() == io::ErrorKind::NotFound {
            0
        } else {
            panic!("couldn't get info on pages file: {}", e)
        }
    } / (mem::size_of::<u64>() as u64)) as usize;

    let mut pages: Mapped<u64> = Mapped::fixed_len("pages", pages_len + (page_size * 100)).unwrap();
    let mut free_page: usize = pages.data.len() / page_size - 98;
    loop {
        if 0 != pages.data[(free_page - 1) * page_size] {
            break;
        }
        free_page -= 1;
        if 1 == free_page {
            break;
        }
    }

    if 0 != simple {
        let fh = fs::File::open(from).expect("input file must exist and be readable");
        let trigrams = trigrams_for(fh.chars()).expect("trigramming must work");
        for found in trigrams.iter() {
            let mut page = idx.data[found] as usize;
            if 0 == page {
                page = free_page;
                idx.data[found] = page as u32;
                free_page += 1;
            }

            let header_loc = page * page_size;
            let header = pages.data[header_loc];
            assert!(header < page_size as u64);
            pages.data[header_loc] += 1;
            pages.data[page * page_size + 1 + header as usize] = simple;
        }
        return;
    }

    unimplemented!();
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
extern crate pbr;
extern crate crypto;
extern crate reqwest;

use clap::{App, Arg};
use crypto::digest::Digest;
use crypto::sha1::Sha1;
use crypto::sha2::Sha256;
use pbr::{ProgressBar, Units};
use reqwest::header::UserAgent;
use reqwest::header::ContentLength;
use std::fs::File;
use std::io;
use std::io::BufWriter;
use std::io::prelude::*;
use std::path::Path;
use std::process;

static DEFAULT_USER_AGENT: &'static str =
    concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));
const EXIT_URL_FAILURE: i32 = 1;
const EXIT_OUTPUT_FAILURE: i32 = 2;

struct CopyResult {
    bytes_written: u64,
    sha1: String,
    sha256: String,
}

fn get_filename(url: &str) -> Option<&str> {
    url.rsplit('/').next()
}

fn write_status(writer: &mut Write, resp: &reqwest::Response) {
    // TODO: get version back in reqwest 0.7... maybe can be cast to hyper type
    let _ = writeln!(writer, "{}", resp.status());
}

fn write_headers(writer: &mut Write, resp: &reqwest::Response) {
    let _ = writeln!(writer, "{}", resp.headers());
}

fn http_download(url: &str, user_agent: &str, max_redirects: usize) -> reqwest::Result<reqwest::Response> {
    let client = reqwest::Client::builder()
        .gzip(true)
        .redirect(reqwest::RedirectPolicy::limited(max_redirects))
        .build()?;

    let resp = client
        .get(url)
        .header(UserAgent::new(user_agent.to_owned()))
        .send()?;

    Ok(resp)
}

fn copy_with_progress<R: ?Sized, W: ?Sized>(
    reader: &mut R,
    writer: &mut W,
    progress: &mut ProgressBar<io::Stdout>,
) -> io::Result<CopyResult>
where
    R: Read,
    W: Write,
{
    let mut buf = [0; 8192];
    let mut written = 0;
    let mut sha1 = Sha1::new();
    let mut sha256 = Sha256::new();
    loop {
        let len = match reader.read(&mut buf) {
            Ok(0) => {
                return Ok(CopyResult {
                    bytes_written: written,
                    sha1: sha1.result_str(),
                    sha256: sha256.result_str(),
                })
            }
            Ok(len) => len,
            Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
            Err(e) => return Err(e),
        };
        // write buf to writer
        writer.write_all(&buf[..len])?;

        // add buf to hash digests
        sha1.input(&buf[..len]);
        sha256.input(&buf[..len]);

        // increment progress and bytes written
        progress.add(len as u64);
        written += len as u64;
    }
}

fn main() {
    let args = App::new("download")
        .version(crate_version!())
        .about("remote file downloader command-line interface")
        .arg(
            Arg::with_name("output")
                .short("o")
                .long("output")
                .value_name("OUTPUT")
                .help("output filename")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("remote-name")
                .short("O")
                .long("remote-name")
                .help("output to a file using the same name as the remote"),
        )
        .arg(
            Arg::with_name("user-agent")
                .short("A")
                .long("user-agent")
                .takes_value(true)
                .help("use value as user-agent header"),
        )
        .arg(
            Arg::with_name("max-redirects")
                .long("max-redirects")
                .takes_value(true)
                .default_value("0")
                .help("maximum number of redirects to follow"),
        )
        .arg(
            Arg::with_name("verbose")
                .short("v")
                .long("verbose")
                .help("enable verbose logging (useful for debugging)"),
        )
        .arg(Arg::with_name("url").required(true))
        .get_matches();

    let url = args.value_of("url").unwrap();
    let user_agent = args.value_of("user-agent")
        .unwrap_or(DEFAULT_USER_AGENT);
    let max_redirects = args.value_of("max-redirects")
        .unwrap_or_default()
        .parse::<usize>()
        .unwrap();
    let verbose = args.is_present("verbose");

    // determine an output filename; if none are set then send to stdout
    let output_path = {
        if args.is_present("remote-name") {
            get_filename(url).and_then(|filename| Some(Path::new(filename)))
        } else {
            args.value_of("output")
                .and_then(|path| Some(Path::new(path)))
        }
    };

    // setup client for downloading and send request
    let mut resp = http_download(url, user_agent, max_redirects).unwrap_or_else(|e| {
        let _ = writeln!(&mut io::stderr(), "{}", e);
        process::exit(EXIT_URL_FAILURE);
    });

    // process response
    if let Some(file_path) = output_path {
        let _ = File::create(file_path)
            .and_then(|output_file| {
                let mut writer = BufWriter::new(output_file);

                if verbose {
                    write_status(&mut io::stdout(), &resp);
                    write_headers(&mut io::stdout(), &resp);
                }

                // setup progress bar based on content-length
                let mut n_bytes: u64 = 0;
                match resp.headers().get::<ContentLength>() {
                    Some(length) => {
                        n_bytes = length.0 as u64;
                    }
                    None => println!("Content-Length header missing"),
                }
                let mut pb = ProgressBar::new(n_bytes);
                pb.set_units(Units::Bytes);

                // copy file with progress updates
                let copy_result = copy_with_progress(&mut resp, &mut writer, &mut pb)?;
                writer.flush()?;

                // print hash signatures
                println!("sha1({}) = {}", file_path.display(), copy_result.sha1);
                println!("sha256({}) = {}", file_path.display(), copy_result.sha256);

                pb.finish_print("Done.");

                Ok(())
            })
            .map_err(|e| {
                let _ = writeln!(&mut io::stderr(), "{}", e);
                process::exit(EXIT_OUTPUT_FAILURE);
            });
    } else {
        let stdout = io::stdout();
        let lock = stdout.lock();
        let mut writer = BufWriter::new(lock);

        if verbose {
            write_status(&mut writer, &resp);
            write_headers(&mut writer, &resp);
        }

        io::copy(&mut resp, &mut writer).unwrap_or_else(|e| {
            let _ = writeln!(&mut io::stderr(), "{}", e);
            process::exit(EXIT_OUTPUT_FAILURE);
        });
    }

    ()
}
<commit_msg>Updating dependencies<commit_after>#[macro_use]
extern crate clap;
extern crate pbr;
extern crate crypto;
extern crate reqwest;

use clap::{App, Arg};
use crypto::digest::Digest;
use crypto::sha1::Sha1;
use crypto::sha2::Sha256;
use pbr::{ProgressBar, Units};
use reqwest::header::UserAgent;
use reqwest::header::ContentLength;
use std::fs::File;
use std::io;
use std::io::BufWriter;
use std::io::prelude::*;
use std::path::Path;
use std::process;

static DEFAULT_USER_AGENT: &'static str =
    concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));
const EXIT_URL_FAILURE: i32 = 1;
const EXIT_OUTPUT_FAILURE: i32 = 2;

struct DownloadResult {
    bytes_written: u64,
    sha1: String,
    sha256: String,
}

fn get_filename(url: &str) -> Option<&str> {
    url.rsplit('/').next()
}

fn write_status(writer: &mut Write, resp: &reqwest::Response) {
    // TODO: get version back in reqwest 0.7... maybe can be cast to hyper type
    let _ = writeln!(writer, "{}", resp.status());
}

fn write_headers(writer: &mut Write, resp: &reqwest::Response) {
    let _ = writeln!(writer, "{}", resp.headers());
}

fn http_download(url: &str, user_agent: &str, max_redirects: usize) -> reqwest::Result<reqwest::Response> {
    let client = reqwest::Client::builder()
        .gzip(true)
        .redirect(reqwest::RedirectPolicy::limited(max_redirects))
        .build()?;

    let resp = client
        .get(url)
        .header(UserAgent::new(user_agent.to_owned()))
        .send()?;

    Ok(resp)
}

fn download_with_progress<R: ?Sized, W: ?Sized>(
    reader: &mut R,
    writer: &mut W,
    progress: &mut ProgressBar<io::Stdout>,
) -> io::Result<DownloadResult>
where
    R: Read,
    W: Write,
{
    let mut buf = [0; 8192];
    let mut written = 0;
    let mut sha1 = Sha1::new();
    let mut sha256 = Sha256::new();
    loop {
        let len = match reader.read(&mut buf) {
            Ok(0) => {
                return Ok(DownloadResult {
                    bytes_written: written,
                    sha1: sha1.result_str(),
                    sha256: sha256.result_str(),
                })
            }
            Ok(len) => len,
            Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
            Err(e) => return Err(e),
        };
        // write buf to writer
        writer.write_all(&buf[..len])?;

        // add buf to hash digests
        sha1.input(&buf[..len]);
        sha256.input(&buf[..len]);

        // increment progress and bytes written
        progress.add(len as u64);
        written += len as u64;
    }
}

fn main() {
    let args = App::new("download")
        .version(crate_version!())
        .about("remote file downloader command-line interface")
        .arg(
            Arg::with_name("output")
                .short("o")
                .long("output")
                .value_name("OUTPUT")
                .help("output filename")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("remote-name")
                .short("O")
                .long("remote-name")
                .help("output to a file using the same name as the remote"),
        )
        .arg(
            Arg::with_name("user-agent")
                .short("A")
                .long("user-agent")
                .takes_value(true)
                .help("use value as user-agent header"),
        )
        .arg(
            Arg::with_name("max-redirects")
                .long("max-redirects")
                .takes_value(true)
                .default_value("0")
                .help("maximum number of redirects to follow"),
        )
        .arg(
            Arg::with_name("verbose")
                .short("v")
                .long("verbose")
                .help("enable verbose logging (useful for debugging)"),
        )
        .arg(Arg::with_name("url").required(true))
        .get_matches();

    let url = args.value_of("url").unwrap();
    let user_agent = args.value_of("user-agent")
        .unwrap_or(DEFAULT_USER_AGENT);
    let max_redirects = args.value_of("max-redirects")
        .unwrap_or_default()
        .parse::<usize>()
        .unwrap();
    let verbose = args.is_present("verbose");

    // determine an output filename; if none are set then send to stdout
    let output_path = {
        if args.is_present("remote-name") {
            get_filename(url).and_then(|filename| Some(Path::new(filename)))
        } else {
            args.value_of("output")
                .and_then(|path| Some(Path::new(path)))
        }
    };

    // setup client for downloading and send request
    let mut resp = http_download(url, user_agent, max_redirects).unwrap_or_else(|e| {
        let _ = writeln!(&mut io::stderr(), "{}", e);
        process::exit(EXIT_URL_FAILURE);
    });

    // process response
    if let Some(file_path) = output_path {
        let _ = File::create(file_path)
            .and_then(|output_file| {
                let mut writer = BufWriter::new(output_file);

                if verbose {
                    write_status(&mut io::stdout(), &resp);
                    write_headers(&mut io::stdout(), &resp);
                }

                // setup progress bar based on content-length
                let mut n_bytes: u64 = 0;
                match resp.headers().get::<ContentLength>() {
                    Some(length) => {
                        n_bytes = length.0 as u64;
                    }
                    None => println!("Content-Length header missing"),
                }
                let mut pb = ProgressBar::new(n_bytes);
                pb.set_units(Units::Bytes);

                // copy file with progress updates
                let result = download_with_progress(&mut resp, &mut writer, &mut pb)?;
                writer.flush()?;

                // print hash signatures
                println!("sha1({}) = {}", file_path.display(), result.sha1);
                println!("sha256({}) = {}", file_path.display(), result.sha256);

                pb.finish_print("Done.");

                Ok(())
            })
            .map_err(|e| {
                let _ = writeln!(&mut io::stderr(), "{}", e);
                process::exit(EXIT_OUTPUT_FAILURE);
            });
    } else {
        let stdout = io::stdout();
        let lock = stdout.lock();
        let mut writer = BufWriter::new(lock);

        if verbose {
            write_status(&mut writer, &resp);
            write_headers(&mut writer, &resp);
        }

        io::copy(&mut resp, &mut writer).unwrap_or_else(|e| {
            let _ = writeln!(&mut io::stderr(), "{}", e);
            process::exit(EXIT_OUTPUT_FAILURE);
        });
    }

    ()
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
// Copyright (c) font-loader Developers
//
// 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.

/// Font loading utilities for installed system fonts
pub mod system_fonts {
    use core_text::font_descriptor::*;
    use core_text::font_descriptor;
    use core_text;
    use std::fs::File;
    use std::mem;
    use std::ptr;
    use core_foundation::string::{CFString, CFStringRef};
    use core_foundation::number::CFNumber;
    use core_foundation::array::CFArray;
    use core_foundation::dictionary::CFDictionary;
    use core_foundation::base::{CFType, TCFType};
    use core_foundation::url::{CFURL, CFURLRef, CFURLCopyFileSystemPath, kCFURLPOSIXPathStyle};
    use libc::c_int;
    use std::io::Read;
    /// The platform specific font properties
    pub type FontProperty = CTFontDescriptor;

    /// Builder for FontProperty
    pub struct FontPropertyBuilder {
        symbolic_traits: CTFontSymbolicTraits,
        family: String
    }

    impl FontPropertyBuilder {
        pub fn new() -> FontPropertyBuilder {
            FontPropertyBuilder{ symbolic_traits: 0, family: String::new()}
        }

        pub fn italic(mut self) -> FontPropertyBuilder {
            self.symbolic_traits |= kCTFontItalicTrait;
            self
        }

        pub fn oblique(self) -> FontPropertyBuilder {
            self.italic()
        }

        pub fn monospace(mut self) -> FontPropertyBuilder {
            self.symbolic_traits |= kCTFontMonoSpaceTrait;
            self
        }

        pub fn bold(mut self) -> FontPropertyBuilder {
            self.symbolic_traits |= kCTFontBoldTrait;
            self
        }

        pub fn family(mut self, name: &str) -> FontPropertyBuilder {
            self.family = name.to_string();
            self
        }

        pub fn build(self) -> FontProperty {
            let family_attr: CFString = unsafe { TCFType::wrap_under_get_rule(kCTFontFamilyNameAttribute) };
            let family_name: CFString = self.family.parse().unwrap();
            let traits_attr: CFString = unsafe { TCFType::wrap_under_get_rule(kCTFontTraitsAttribute) };
            let symbolic_traits_attr: CFString = unsafe { TCFType::wrap_under_get_rule(kCTFontSymbolicTrait) };
            let traits = CFDictionary::from_CFType_pairs(&[(symbolic_traits_attr.as_CFType(), CFNumber::from_i32(self.symbolic_traits as i32).as_CFType())]);
            let mut attributes = Vec::new();
            attributes.push((traits_attr.as_CFType(), traits.as_CFType()));
            if self.family.len() != 0 {
                attributes.push((family_attr.as_CFType(), family_name.as_CFType()));
            }
            let attributes = CFDictionary::from_CFType_pairs(&attributes);
            font_descriptor::new_from_attributes(&attributes)
        }
    }

    /// Get the binary data and index of a specific font
    pub fn get(config: &FontProperty) -> Option<(Vec<u8>, c_int)> {
        let mut buffer = Vec::new();
        let path;
        unsafe {
            let value = CTFontDescriptorCopyAttribute(config.as_concrete_TypeRef(), kCTFontURLAttribute);
            assert!(!value.is_null());

            let value: CFType = TCFType::wrap_under_get_rule(value);
            assert!(value.instance_of::<CFURLRef,CFURL>());
            let url: CFURL = TCFType::wrap_under_get_rule(mem::transmute(value.as_CFTypeRef()));
            path = CFString::wrap_under_create_rule(CFURLCopyFileSystemPath(url.as_concrete_TypeRef(), kCFURLPOSIXPathStyle));
        }
        match File::open(path.to_string()).and_then(|mut f| f.read_to_end(&mut buffer)) {
            Ok(_) => { Some((buffer, 0)) }
            Err(_) => { None }
        }
    }

    /// Query the names of all fonts installed in the system
    pub fn query_all() -> Vec<String> {
        let family_names = core_text::font_collection::get_family_names();
        family_names.iter().map(|strref| {
            let family_name_ref: CFStringRef = unsafe { mem::transmute(strref) };
            let family_name_cf: CFString = unsafe { TCFType::wrap_under_get_rule(family_name_ref) };
            family_name_cf.to_string()}).collect()
    }

    /// Query the names of specifc fonts installed in the system
    pub fn query_specific(property: &mut FontProperty) -> Vec<String> {
        let descs: CFArray =
        unsafe {
            let descs = CTFontDescriptorCreateMatchingFontDescriptors(property.as_concrete_TypeRef(),
                                                                      ptr::null());
            TCFType::wrap_under_create_rule(descs)
        };
        descs.iter().map(|desc| {
                         let desc : CTFontDescriptor = unsafe { TCFType::wrap_under_get_rule(mem::transmute(desc))};
                         desc.family_name()
                         }).collect::<Vec<_>>()
    }
}
<commit_msg>Upgrade code to core-foundation 0.5.0 compatible<commit_after>// The MIT License (MIT)
// Copyright (c) font-loader Developers
//
// 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.

/// Font loading utilities for installed system fonts
pub mod system_fonts {
    use core_text::font_descriptor::*;
    use core_text::font_descriptor;
    use core_text;
    use std::fs::File;
    use std::mem;
    use std::ptr;
    use core_foundation::string::CFString;
    use core_foundation::number::CFNumber;
    use core_foundation::array::CFArray;
    use core_foundation::dictionary::CFDictionary;
    use core_foundation::base::{CFType, TCFType};
    use core_foundation::url::{CFURL, CFURLCopyFileSystemPath, kCFURLPOSIXPathStyle};
    use libc::c_int;
    use std::io::Read;
    /// The platform specific font properties
    pub type FontProperty = CTFontDescriptor;

    /// Builder for FontProperty
    pub struct FontPropertyBuilder {
        symbolic_traits: CTFontSymbolicTraits,
        family: String
    }

    impl FontPropertyBuilder {
        pub fn new() -> FontPropertyBuilder {
            FontPropertyBuilder{ symbolic_traits: 0, family: String::new()}
        }

        pub fn italic(mut self) -> FontPropertyBuilder {
            self.symbolic_traits |= kCTFontItalicTrait;
            self
        }

        pub fn oblique(self) -> FontPropertyBuilder {
            self.italic()
        }

        pub fn monospace(mut self) -> FontPropertyBuilder {
            self.symbolic_traits |= kCTFontMonoSpaceTrait;
            self
        }

        pub fn bold(mut self) -> FontPropertyBuilder {
            self.symbolic_traits |= kCTFontBoldTrait;
            self
        }

        pub fn family(mut self, name: &str) -> FontPropertyBuilder {
            self.family = name.to_string();
            self
        }

        pub fn build(self) -> FontProperty {
            let family_attr: CFString = unsafe { TCFType::wrap_under_get_rule(kCTFontFamilyNameAttribute) };
            let family_name: CFString = self.family.parse().unwrap();
            let traits_attr: CFString = unsafe { TCFType::wrap_under_get_rule(kCTFontTraitsAttribute) };
            let symbolic_traits_attr: CFString = unsafe { TCFType::wrap_under_get_rule(kCTFontSymbolicTrait) };
            let traits = CFDictionary::from_CFType_pairs(&[(symbolic_traits_attr.as_CFType(), CFNumber::from(self.symbolic_traits as i32).as_CFType())]);
            let mut attributes = Vec::new();
            attributes.push((traits_attr.as_CFType(), traits.as_CFType()));
            if self.family.len() != 0 {
                attributes.push((family_attr.as_CFType(), family_name.as_CFType()));
            }
            let attributes = CFDictionary::from_CFType_pairs(&attributes);
            font_descriptor::new_from_attributes(&attributes)
        }
    }

    /// Get the binary data and index of a specific font
    pub fn get(config: &FontProperty) -> Option<(Vec<u8>, c_int)> {
        let mut buffer = Vec::new();
        let path;
        unsafe {
            let value =
                CTFontDescriptorCopyAttribute(config.as_concrete_TypeRef(), kCTFontURLAttribute);
            assert!(!value.is_null());

            let value: CFType = TCFType::wrap_under_get_rule(value);
            assert!(value.instance_of::<CFURL>());
            let url: CFURL = TCFType::wrap_under_get_rule(mem::transmute(value.as_CFTypeRef()));
            path = CFString::wrap_under_create_rule(CFURLCopyFileSystemPath(
                url.as_concrete_TypeRef(),
                kCFURLPOSIXPathStyle,
            ));
        }
        match File::open(path.to_string()).and_then(|mut f| f.read_to_end(&mut buffer)) {
            Ok(_) => Some((buffer, 0)),
            Err(_) => None,
        }
    }

    /// Query the names of all fonts installed in the system
    pub fn query_all() -> Vec<String> {
        core_text::font_collection::get_family_names()
            .iter()
            .map(|family_name| family_name.to_string())
            .collect()
    }

    /// Query the names of specifc fonts installed in the system
    pub fn query_specific(property: &mut FontProperty) -> Vec<String> {
        let descs: CFArray<CTFontDescriptor> = unsafe {
            let descs = CTFontDescriptorCreateMatchingFontDescriptors(
                property.as_concrete_TypeRef(),
                ptr::null(),
            );
            TCFType::wrap_under_create_rule(descs)
        };
        descs
            .iter()
            .map(|desc| desc.family_name())
            .collect::<Vec<_>>()
    }
}
<|endoftext|>


<commit_before>use range::Range;
use std::rc::Rc;
use std::cell::RefCell;

use {
    update,
    MetaData,
    MetaReader,
    ParseError,
    Rule,
};

/// Stores information about a parameter.
pub struct Node {
    /// The name of the parameter.
    pub name: Rc<String>,
    /// The property name of parent to set the value.
    pub value: Option<Rc<String>>,
    /// The body of the parameter.
    pub body: Vec<Rule>,
}

impl Node {
    /// Parses parameter.
    pub fn parse<M>(
        &self,
        meta_reader: &mut M,
        state: &M::State,
        mut chars: &[char],
        start_offset: usize
    ) -> Result<(Range, M::State), (Range, ParseError)>
        where M: MetaReader
    {
        let mut offset = start_offset;
        let name = self.value.clone().unwrap_or(self.name.clone());
        let mut state = match meta_reader.data(
            MetaData::StartNode(name.clone()),
            state,
            Range::empty(offset)
        ) {
            Err(err) => { return Err((Range::new(offset, 0), err)); }
            Ok(state) => state,
        };
        for rule in &self.body {
            state = match rule.parse(meta_reader, &state, chars, offset) {
                Err(err) => { return Err(err); }
                Ok((range, state)) => {
                    update(range, &mut chars, &mut offset);
                    state
                }
            }
        }
        let range = Range::new(start_offset, offset - start_offset);
        match meta_reader.data(MetaData::EndNode(name), &state, range) {
            Err(err) => { return Err((range, err)); }
            Ok(state) => Ok((range, state)),
        }
    }
}

/// A parameter reference.
pub enum NodeRef {
    /// Points to a parameter by name.
    Name(Rc<String>),
    /// Reference to parameter.
    /// The `bool` flag is used to prevent multiple visits when updating.
    Ref(Rc<RefCell<Node>>, NodeVisit),
}

/// Tells whether a parameter is visited when updated.
pub enum NodeVisit {
    /// The parameter is not being visited.
    Unvisited,
    /// The parameter is being visited.
    Visited
}

#[cfg(test)]
mod tests {
    use super::super::*;
    use range::Range;
    use std::rc::Rc;
    use std::cell::RefCell;

    #[test]
    fn parameter_ref() {
        // Create a parameter rule the refers to itself.
        let foo: Rc<String> = Rc::new("foo".into());
        let num: Rc<String> = Rc::new("num".into());
        let node = Rc::new(RefCell::new(Node {
            name: foo.clone(),
            value: None,
            body: vec![
                Rule::Number(Number { property: Some(num.clone()) }),
                Rule::Optional(Optional {
                    args: vec![
                        Rule::Whitespace(Whitespace { optional: false }),
                        Rule::Node(NodeRef::Name(foo.clone())),
                    ]
                })
            ]
        }));

        // Replace self referencing names with direct references.
        let refs = vec![(foo.clone(), node.clone())];
        for sub_rule in &mut node.borrow_mut().body {
            sub_rule.update_refs(&refs);
        }

        let text = "1 2 3";
        let chars: Vec<char> = text.chars().collect();
        let mut tokenizer = Tokenizer::new();
        let s = TokenizerState::new();
        let res = node.borrow().parse(&mut tokenizer, &s, &chars, 0);
        assert_eq!(res, Ok((Range::new(0, 5), TokenizerState(9))));
        assert_eq!(tokenizer.tokens.len(), 9);
        assert_eq!(&tokenizer.tokens[0].0, &MetaData::StartNode(foo.clone()));
        assert_eq!(&tokenizer.tokens[1].0, &MetaData::F64(num.clone(), 1.0));
        assert_eq!(&tokenizer.tokens[2].0, &MetaData::StartNode(foo.clone()));
        assert_eq!(&tokenizer.tokens[3].0, &MetaData::F64(num.clone(), 2.0));
        assert_eq!(&tokenizer.tokens[4].0, &MetaData::StartNode(foo.clone()));
        assert_eq!(&tokenizer.tokens[5].0, &MetaData::F64(num.clone(), 3.0));
        assert_eq!(&tokenizer.tokens[6].0, &MetaData::EndNode(foo.clone()));
        assert_eq!(&tokenizer.tokens[7].0, &MetaData::EndNode(foo.clone()));
        assert_eq!(&tokenizer.tokens[8].0, &MetaData::EndNode(foo.clone()));
    }
}
<commit_msg>Replaced `parameter` with `node`<commit_after>use range::Range;
use std::rc::Rc;
use std::cell::RefCell;

use {
    update,
    MetaData,
    MetaReader,
    ParseError,
    Rule,
};

/// Stores information about a node.
pub struct Node {
    /// The name of the node.
    pub name: Rc<String>,
    /// The property name of parent to set the value.
    pub value: Option<Rc<String>>,
    /// The body of the node.
    pub body: Vec<Rule>,
}

impl Node {
    /// Parses node.
    pub fn parse<M>(
        &self,
        meta_reader: &mut M,
        state: &M::State,
        mut chars: &[char],
        start_offset: usize
    ) -> Result<(Range, M::State), (Range, ParseError)>
        where M: MetaReader
    {
        let mut offset = start_offset;
        let name = self.value.clone().unwrap_or(self.name.clone());
        let mut state = match meta_reader.data(
            MetaData::StartNode(name.clone()),
            state,
            Range::empty(offset)
        ) {
            Err(err) => { return Err((Range::new(offset, 0), err)); }
            Ok(state) => state,
        };
        for rule in &self.body {
            state = match rule.parse(meta_reader, &state, chars, offset) {
                Err(err) => { return Err(err); }
                Ok((range, state)) => {
                    update(range, &mut chars, &mut offset);
                    state
                }
            }
        }
        let range = Range::new(start_offset, offset - start_offset);
        match meta_reader.data(MetaData::EndNode(name), &state, range) {
            Err(err) => { return Err((range, err)); }
            Ok(state) => Ok((range, state)),
        }
    }
}

/// A node reference.
pub enum NodeRef {
    /// Points to a node by name.
    Name(Rc<String>),
    /// Reference to node.
    /// The `bool` flag is used to prevent multiple visits when updating.
    Ref(Rc<RefCell<Node>>, NodeVisit),
}

/// Tells whether a node is visited when updated.
pub enum NodeVisit {
    /// The node is not being visited.
    Unvisited,
    /// The node is being visited.
    Visited
}

#[cfg(test)]
mod tests {
    use super::super::*;
    use range::Range;
    use std::rc::Rc;
    use std::cell::RefCell;

    #[test]
    fn node_ref() {
        // Create a node rule the refers to itself.
        let foo: Rc<String> = Rc::new("foo".into());
        let num: Rc<String> = Rc::new("num".into());
        let node = Rc::new(RefCell::new(Node {
            name: foo.clone(),
            value: None,
            body: vec![
                Rule::Number(Number { property: Some(num.clone()) }),
                Rule::Optional(Optional {
                    args: vec![
                        Rule::Whitespace(Whitespace { optional: false }),
                        Rule::Node(NodeRef::Name(foo.clone())),
                    ]
                })
            ]
        }));

        // Replace self referencing names with direct references.
        let refs = vec![(foo.clone(), node.clone())];
        for sub_rule in &mut node.borrow_mut().body {
            sub_rule.update_refs(&refs);
        }

        let text = "1 2 3";
        let chars: Vec<char> = text.chars().collect();
        let mut tokenizer = Tokenizer::new();
        let s = TokenizerState::new();
        let res = node.borrow().parse(&mut tokenizer, &s, &chars, 0);
        assert_eq!(res, Ok((Range::new(0, 5), TokenizerState(9))));
        assert_eq!(tokenizer.tokens.len(), 9);
        assert_eq!(&tokenizer.tokens[0].0, &MetaData::StartNode(foo.clone()));
        assert_eq!(&tokenizer.tokens[1].0, &MetaData::F64(num.clone(), 1.0));
        assert_eq!(&tokenizer.tokens[2].0, &MetaData::StartNode(foo.clone()));
        assert_eq!(&tokenizer.tokens[3].0, &MetaData::F64(num.clone(), 2.0));
        assert_eq!(&tokenizer.tokens[4].0, &MetaData::StartNode(foo.clone()));
        assert_eq!(&tokenizer.tokens[5].0, &MetaData::F64(num.clone(), 3.0));
        assert_eq!(&tokenizer.tokens[6].0, &MetaData::EndNode(foo.clone()));
        assert_eq!(&tokenizer.tokens[7].0, &MetaData::EndNode(foo.clone()));
        assert_eq!(&tokenizer.tokens[8].0, &MetaData::EndNode(foo.clone()));
    }
}
<|endoftext|>