<commit_before>//!
//! FUSE native interface declarations (as of libosxfuse-2.5.5).
//!

#![allow(non_camel_case_types, missing_doc)]

use std::libc::{c_int, c_char};

// Link with libosxfuse on OS X
#[cfg(target_os = "macos")]
#[link(name = "osxfuse")]
extern "system" { }

// Link with libfuse on Linux
#[cfg(target_os = "linux")]
#[link(name = "fuse")]
extern "system" { }

//
// FUSE arguments (see fuse_opt.h for details)
//

pub struct fuse_args {
	argc: c_int,
	argv: **c_char,
	allocated: c_int,
}

//
// FUSE common (see fuse_common_compat.h for details)
//

extern "system" {
	pub fn fuse_mount_compat25 (mountpoint: *c_char, args: *fuse_args) -> c_int;
	#[cfg(not(target_os = "macos"))]
	pub fn fuse_unmount_compat22 (mountpoint: *c_char);
}

//
// FUSE kernel (see fuse_kernel.h for details)
//

pub static FUSE_KERNEL_VERSION: u32 = 7;
pub static FUSE_KERNEL_MINOR_VERSION: u32 = 8;
pub static FUSE_ROOT_ID: u64 = 1;

#[cfg(target_os = "macos")]
#[deriving(Default)]
pub struct fuse_attr {
	ino: u64,
	size: u64,
	blocks: u64,
	atime: i64,
	mtime: i64,
	ctime: i64,
	crtime: i64,			// OS X only
	atimensec: i32,
	mtimensec: i32,
	ctimensec: i32,
	crtimensec: i32,		// OS X only
	mode: u32,
	nlink: u32,
	uid: u32,
	gid: u32,
	rdev: u32,
	flags: u32,				// OS X only, see chflags(2)
}

#[cfg(target_os = "linux")]
#[deriving(Default)]
pub struct fuse_attr {
	ino: u64,
	size: u64,
	blocks: u64,
	atime: i64,
	mtime: i64,
	ctime: i64,
	atimensec: i32,
	mtimensec: i32,
	ctimensec: i32,
	mode: u32,
	nlink: u32,
	uid: u32,
	gid: u32,
	rdev: u32,
}

pub struct fuse_kstatfs {
	blocks: u64,			// Total blocks (in units of frsize)
	bfree: u64,				// Free blocks
	bavail: u64,			// Free blocks for unprivileged users
	files: u64,				// Total inodes
	ffree: u64,				// Free inodes
	bsize: u32,				// Filesystem block size
	namelen: u32,			// Maximum filename length
	frsize: u32,			// Fundamental file system block size
	padding: u32,
	spare: [u32, ..6],
}

pub struct fuse_file_lock {
	start: u64,
	end: u64,
	typ: u32,
	pid: u32,
}

pub mod consts {
	// Bitmasks for fuse_setattr_in.valid
	pub static FATTR_MODE: u32				= 1 << 0;
	pub static FATTR_UID: u32				= 1 << 1;
	pub static FATTR_GID: u32				= 1 << 2;
	pub static FATTR_SIZE: u32				= 1 << 3;
	pub static FATTR_ATIME: u32				= 1 << 4;
	pub static FATTR_MTIME: u32				= 1 << 5;
	pub static FATTR_FH: u32				= 1 << 6;
	#[cfg(target_os = "macos")]
	pub static FATTR_CRTIME: u32			= 1 << 28;	// OS X only
	#[cfg(target_os = "macos")]
	pub static FATTR_CHGTIME: u32			= 1 << 29;	// OS X only
	#[cfg(target_os = "macos")]
	pub static FATTR_BKUPTIME: u32			= 1 << 30;	// OS X only
	#[cfg(target_os = "macos")]
	pub static FATTR_FLAGS: u32				= 1 << 31;	// OS X only

	// Flags returned by the open request
	pub static FOPEN_DIRECT_IO: u32			= 1 << 0;	// bypass page cache for this open file
	pub static FOPEN_KEEP_CACHE: u32		= 1 << 1;	// don't invalidate the data cache on open
	#[cfg(target_os = "macos")]
	pub static FOPEN_PURGE_ATTR: u32		= 1 << 30;	// OS X only
	#[cfg(target_os = "macos")]
	pub static FOPEN_PURGE_UBC: u32			= 1 << 31;	// OS X only

	// Init request/reply flags
	pub static FUSE_ASYNC_READ: u32			= 1 << 0;
	pub static FUSE_POSIX_LOCKS: u32		= 1 << 1;
	pub static FUSE_FILE_OPS: u32			= 1 << 2;
	pub static FUSE_ATOMIC_O_TRUNC: u32		= 1 << 3;
	pub static FUSE_EXPORT_SUPPORT: u32		= 1 << 4;
	pub static FUSE_BIG_WRITES: u32			= 1 << 5;
	pub static FUSE_DONT_MASK: u32			= 1 << 6;
	#[cfg(target_os = "macos")]
	pub static FUSE_CASE_INSENSITIVE: u32	= 1 << 29;	// OS X only
	#[cfg(target_os = "macos")]
	pub static FUSE_VOL_RENAME: u32			= 1 << 30;	// OS X only
	#[cfg(target_os = "macos")]
	pub static FUSE_XTIMES: u32				= 1 << 31;	// OS X only

	// Release flags
	pub static FUSE_RELEASE_FLUSH: u32		= 1 << 0;
}

#[deriving(FromPrimitive)]
pub enum fuse_opcode {
	FUSE_LOOKUP = 1,
	FUSE_FORGET = 2,			// no reply
	FUSE_GETATTR = 3,
	FUSE_SETATTR = 4,
	FUSE_READLINK = 5,
	FUSE_SYMLINK = 6,
	FUSE_MKNOD = 8,
	FUSE_MKDIR = 9,
	FUSE_UNLINK = 10,
	FUSE_RMDIR = 11,
	FUSE_RENAME = 12,
	FUSE_LINK = 13,
	FUSE_OPEN = 14,
	FUSE_READ = 15,
	FUSE_WRITE = 16,
	FUSE_STATFS = 17,
	FUSE_RELEASE = 18,
	FUSE_FSYNC = 20,
	FUSE_SETXATTR = 21,
	FUSE_GETXATTR = 22,
	FUSE_LISTXATTR = 23,
	FUSE_REMOVEXATTR = 24,
	FUSE_FLUSH = 25,
	FUSE_INIT = 26,
	FUSE_OPENDIR = 27,
	FUSE_READDIR = 28,
	FUSE_RELEASEDIR = 29,
	FUSE_FSYNCDIR = 30,
	FUSE_GETLK = 31,
	FUSE_SETLK = 32,
	FUSE_SETLKW = 33,
	FUSE_ACCESS = 34,
	FUSE_CREATE = 35,
	FUSE_INTERRUPT = 36,
	FUSE_BMAP = 37,
	FUSE_DESTROY = 38,
	FUSE_SETVOLNAME = 61,		// OS X only
	FUSE_GETXTIMES = 62,		// OS X only
	FUSE_EXCHANGE = 63,			// OS X only
}

pub struct fuse_entry_out {
	nodeid: u64,
	generation: u64,
	entry_valid: i64,
	attr_valid: i64,
	entry_valid_nsec: i32,
	attr_valid_nsec: i32,
	attr: fuse_attr,
}

pub struct fuse_forget_in {
	nlookup: u64,
}

pub struct fuse_attr_out {
	attr_valid: i64,
	attr_valid_nsec: i32,
	dummy: u32,
	attr: fuse_attr,
}

#[cfg(target_os = "macos")]
pub struct fuse_getxtimes_out {	// OS X only
	bkuptime: i64,
	crtime: i64,
	bkuptimensec: i32,
	crtimensec: i32,
}

pub struct fuse_mknod_in {
	mode: u32,
	rdev: u32,
}

pub struct fuse_mkdir_in {
	mode: u32,
	padding: u32,
}

pub struct fuse_rename_in {
	newdir: u64,
}

#[cfg(target_os = "macos")]
pub struct fuse_exchange_in {	// OS X only
	olddir: u64,
	newdir: u64,
	options: u64,
}

pub struct fuse_link_in {
	oldnodeid: u64,
}

#[cfg(target_os = "macos")]
pub struct fuse_setattr_in {
	valid: u32,
	padding: u32,
	fh: u64,
	size: u64,
	unused1: u64,
	atime: i64,
	mtime: i64,
	unused2: u64,
	atimensec: i32,
	mtimensec: i32,
	unused3: u32,
	mode: u32,
	unused4: u32,
	uid: u32,
	gid: u32,
	unused5: u32,
	bkuptime: i64,			// OS X only
	chgtime: i64,			// OS X only
	crtime: i64,			// OS X only
	bkuptimensec: i32,		// OS X only
	chgtimensec: i32,		// OS X only
	crtimensec: i32,		// OS X only
	flags: u32,				// OS X only
}

#[cfg(target_os = "linux")]
pub struct fuse_setattr_in {
	valid: u32,
	padding: u32,
	fh: u64,
	size: u64,
	unused1: u64,
	atime: i64,
	mtime: i64,
	unused2: u64,
	atimensec: i32,
	mtimensec: i32,
	unused3: u32,
	mode: u32,
	unused4: u32,
	uid: u32,
	gid: u32,
	unused5: u32,
}

pub struct fuse_open_in {
	flags: u32,
	mode: u32,
}

pub struct fuse_open_out {
	fh: u64,
	open_flags: u32,
	padding: u32,
}

pub struct fuse_release_in {
	fh: u64,
	flags: u32,
	release_flags: u32,
	lock_owner: u64,
}

pub struct fuse_flush_in {
	fh: u64,
	unused: u32,
	padding: u32,
	lock_owner: u64,
}

pub struct fuse_read_in {
	fh: u64,
	offset: u64,
	size: u32,
	padding: u32,
}

pub struct fuse_write_in {
	fh: u64,
	offset: u64,
	size: u32,
	write_flags: u32,
}

pub struct fuse_write_out {
	size: u32,
	padding: u32,
}

pub struct fuse_statfs_out {
	st: fuse_kstatfs,
}

pub struct fuse_fsync_in {
	fh: u64,
	fsync_flags: u32,
	padding: u32,
}

#[cfg(target_os = "macos")]
pub struct fuse_setxattr_in {
	size: u32,
	flags: u32,
	position: u32,			// OS X only
	padding: u32,			// OS X only
}

#[cfg(target_os = "linux")]
pub struct fuse_setxattr_in {
	size: u32,
	flags: u32,
}

#[cfg(target_os = "macos")]
pub struct fuse_getxattr_in {
	size: u32,
	padding: u32,
	position: u32,			// OS X only
	padding2: u32,			// OS X only
}

#[cfg(target_os = "linux")]
pub struct fuse_getxattr_in {
	size: u32,
	padding: u32,
}

pub struct fuse_getxattr_out {
	size: u32,
	padding: u32,
}

pub struct fuse_lk_in {
	fh: u64,
	owner: u64,
	lk: fuse_file_lock,
}

pub struct fuse_lk_out {
	lk: fuse_file_lock,
}

pub struct fuse_access_in {
	mask: u32,
	padding: u32,
}

pub struct fuse_init_in {
	major: u32,
	minor: u32,
	max_readahead: u32,
	flags: u32,
}

pub struct fuse_init_out {
	major: u32,
	minor: u32,
	max_readahead: u32,
	flags: u32,
	unused: u32,
	max_write: u32,
}

pub struct fuse_interrupt_in {
	unique: u64,
}

pub struct fuse_bmap_in {
	block: u64,
	blocksize: u32,
	padding: u32,
}

pub struct fuse_bmap_out {
	block: u64,
}

pub struct fuse_in_header {
	len: u32,
	opcode: u32,
	unique: u64,
	nodeid: u64,
	uid: u32,
	gid: u32,
	pid: u32,
	padding: u32,
}

pub struct fuse_out_header {
	len: u32,
	error: i32,
	unique: u64,
}

pub struct fuse_dirent {
	ino: u64,
	off: u64,
	namelen: u32,
	typ: u32,
	// followed by name of namelen bytes
}
<commit_msg>Place target_os attributes on struct fields<commit_after>//!
//! FUSE native interface declarations (as of libosxfuse-2.5.5).
//!

#![allow(non_camel_case_types, missing_doc)]

use std::libc::{c_int, c_char};

// Link with libosxfuse on OS X
#[cfg(target_os = "macos")]
#[link(name = "osxfuse")]
extern "system" { }

// Link with libfuse on Linux
#[cfg(target_os = "linux")]
#[link(name = "fuse")]
extern "system" { }

//
// FUSE arguments (see fuse_opt.h for details)
//

pub struct fuse_args {
	argc: c_int,
	argv: **c_char,
	allocated: c_int,
}

//
// FUSE common (see fuse_common_compat.h for details)
//

extern "system" {
	pub fn fuse_mount_compat25 (mountpoint: *c_char, args: *fuse_args) -> c_int;
	#[cfg(not(target_os = "macos"))]
	pub fn fuse_unmount_compat22 (mountpoint: *c_char);
}

//
// FUSE kernel (see fuse_kernel.h for details)
//

pub static FUSE_KERNEL_VERSION: u32 = 7;
pub static FUSE_KERNEL_MINOR_VERSION: u32 = 8;
pub static FUSE_ROOT_ID: u64 = 1;

#[deriving(Default)]
pub struct fuse_attr {
	ino: u64,
	size: u64,
	blocks: u64,
	atime: i64,
	mtime: i64,
	ctime: i64,
	#[cfg(target_os = "macos")]
	crtime: i64,			// OS X only
	atimensec: i32,
	mtimensec: i32,
	ctimensec: i32,
	#[cfg(target_os = "macos")]
	crtimensec: i32,		// OS X only
	mode: u32,
	nlink: u32,
	uid: u32,
	gid: u32,
	rdev: u32,
	#[cfg(target_os = "macos")]
	flags: u32,				// OS X only, see chflags(2)
}

pub struct fuse_kstatfs {
	blocks: u64,			// Total blocks (in units of frsize)
	bfree: u64,				// Free blocks
	bavail: u64,			// Free blocks for unprivileged users
	files: u64,				// Total inodes
	ffree: u64,				// Free inodes
	bsize: u32,				// Filesystem block size
	namelen: u32,			// Maximum filename length
	frsize: u32,			// Fundamental file system block size
	padding: u32,
	spare: [u32, ..6],
}

pub struct fuse_file_lock {
	start: u64,
	end: u64,
	typ: u32,
	pid: u32,
}

pub mod consts {
	// Bitmasks for fuse_setattr_in.valid
	pub static FATTR_MODE: u32				= 1 << 0;
	pub static FATTR_UID: u32				= 1 << 1;
	pub static FATTR_GID: u32				= 1 << 2;
	pub static FATTR_SIZE: u32				= 1 << 3;
	pub static FATTR_ATIME: u32				= 1 << 4;
	pub static FATTR_MTIME: u32				= 1 << 5;
	pub static FATTR_FH: u32				= 1 << 6;
	#[cfg(target_os = "macos")]
	pub static FATTR_CRTIME: u32			= 1 << 28;	// OS X only
	#[cfg(target_os = "macos")]
	pub static FATTR_CHGTIME: u32			= 1 << 29;	// OS X only
	#[cfg(target_os = "macos")]
	pub static FATTR_BKUPTIME: u32			= 1 << 30;	// OS X only
	#[cfg(target_os = "macos")]
	pub static FATTR_FLAGS: u32				= 1 << 31;	// OS X only

	// Flags returned by the open request
	pub static FOPEN_DIRECT_IO: u32			= 1 << 0;	// bypass page cache for this open file
	pub static FOPEN_KEEP_CACHE: u32		= 1 << 1;	// don't invalidate the data cache on open
	#[cfg(target_os = "macos")]
	pub static FOPEN_PURGE_ATTR: u32		= 1 << 30;	// OS X only
	#[cfg(target_os = "macos")]
	pub static FOPEN_PURGE_UBC: u32			= 1 << 31;	// OS X only

	// Init request/reply flags
	pub static FUSE_ASYNC_READ: u32			= 1 << 0;
	pub static FUSE_POSIX_LOCKS: u32		= 1 << 1;
	pub static FUSE_FILE_OPS: u32			= 1 << 2;
	pub static FUSE_ATOMIC_O_TRUNC: u32		= 1 << 3;
	pub static FUSE_EXPORT_SUPPORT: u32		= 1 << 4;
	pub static FUSE_BIG_WRITES: u32			= 1 << 5;
	pub static FUSE_DONT_MASK: u32			= 1 << 6;
	#[cfg(target_os = "macos")]
	pub static FUSE_CASE_INSENSITIVE: u32	= 1 << 29;	// OS X only
	#[cfg(target_os = "macos")]
	pub static FUSE_VOL_RENAME: u32			= 1 << 30;	// OS X only
	#[cfg(target_os = "macos")]
	pub static FUSE_XTIMES: u32				= 1 << 31;	// OS X only

	// Release flags
	pub static FUSE_RELEASE_FLUSH: u32		= 1 << 0;
}

#[deriving(FromPrimitive)]
pub enum fuse_opcode {
	FUSE_LOOKUP = 1,
	FUSE_FORGET = 2,			// no reply
	FUSE_GETATTR = 3,
	FUSE_SETATTR = 4,
	FUSE_READLINK = 5,
	FUSE_SYMLINK = 6,
	FUSE_MKNOD = 8,
	FUSE_MKDIR = 9,
	FUSE_UNLINK = 10,
	FUSE_RMDIR = 11,
	FUSE_RENAME = 12,
	FUSE_LINK = 13,
	FUSE_OPEN = 14,
	FUSE_READ = 15,
	FUSE_WRITE = 16,
	FUSE_STATFS = 17,
	FUSE_RELEASE = 18,
	FUSE_FSYNC = 20,
	FUSE_SETXATTR = 21,
	FUSE_GETXATTR = 22,
	FUSE_LISTXATTR = 23,
	FUSE_REMOVEXATTR = 24,
	FUSE_FLUSH = 25,
	FUSE_INIT = 26,
	FUSE_OPENDIR = 27,
	FUSE_READDIR = 28,
	FUSE_RELEASEDIR = 29,
	FUSE_FSYNCDIR = 30,
	FUSE_GETLK = 31,
	FUSE_SETLK = 32,
	FUSE_SETLKW = 33,
	FUSE_ACCESS = 34,
	FUSE_CREATE = 35,
	FUSE_INTERRUPT = 36,
	FUSE_BMAP = 37,
	FUSE_DESTROY = 38,
	FUSE_SETVOLNAME = 61,		// OS X only
	FUSE_GETXTIMES = 62,		// OS X only
	FUSE_EXCHANGE = 63,			// OS X only
}

pub struct fuse_entry_out {
	nodeid: u64,
	generation: u64,
	entry_valid: i64,
	attr_valid: i64,
	entry_valid_nsec: i32,
	attr_valid_nsec: i32,
	attr: fuse_attr,
}

pub struct fuse_forget_in {
	nlookup: u64,
}

pub struct fuse_attr_out {
	attr_valid: i64,
	attr_valid_nsec: i32,
	dummy: u32,
	attr: fuse_attr,
}

#[cfg(target_os = "macos")]
pub struct fuse_getxtimes_out {	// OS X only
	bkuptime: i64,
	crtime: i64,
	bkuptimensec: i32,
	crtimensec: i32,
}

pub struct fuse_mknod_in {
	mode: u32,
	rdev: u32,
}

pub struct fuse_mkdir_in {
	mode: u32,
	padding: u32,
}

pub struct fuse_rename_in {
	newdir: u64,
}

#[cfg(target_os = "macos")]
pub struct fuse_exchange_in {	// OS X only
	olddir: u64,
	newdir: u64,
	options: u64,
}

pub struct fuse_link_in {
	oldnodeid: u64,
}

pub struct fuse_setattr_in {
	valid: u32,
	padding: u32,
	fh: u64,
	size: u64,
	unused1: u64,
	atime: i64,
	mtime: i64,
	unused2: u64,
	atimensec: i32,
	mtimensec: i32,
	unused3: u32,
	mode: u32,
	unused4: u32,
	uid: u32,
	gid: u32,
	unused5: u32,
	#[cfg(target_os = "macos")]
	bkuptime: i64,			// OS X only
	#[cfg(target_os = "macos")]
	chgtime: i64,			// OS X only
	#[cfg(target_os = "macos")]
	crtime: i64,			// OS X only
	#[cfg(target_os = "macos")]
	bkuptimensec: i32,		// OS X only
	#[cfg(target_os = "macos")]
	chgtimensec: i32,		// OS X only
	#[cfg(target_os = "macos")]
	crtimensec: i32,		// OS X only
	#[cfg(target_os = "macos")]
	flags: u32,				// OS X only
}

pub struct fuse_open_in {
	flags: u32,
	mode: u32,
}

pub struct fuse_open_out {
	fh: u64,
	open_flags: u32,
	padding: u32,
}

pub struct fuse_release_in {
	fh: u64,
	flags: u32,
	release_flags: u32,
	lock_owner: u64,
}

pub struct fuse_flush_in {
	fh: u64,
	unused: u32,
	padding: u32,
	lock_owner: u64,
}

pub struct fuse_read_in {
	fh: u64,
	offset: u64,
	size: u32,
	padding: u32,
}

pub struct fuse_write_in {
	fh: u64,
	offset: u64,
	size: u32,
	write_flags: u32,
}

pub struct fuse_write_out {
	size: u32,
	padding: u32,
}

pub struct fuse_statfs_out {
	st: fuse_kstatfs,
}

pub struct fuse_fsync_in {
	fh: u64,
	fsync_flags: u32,
	padding: u32,
}

pub struct fuse_setxattr_in {
	size: u32,
	flags: u32,
	#[cfg(target_os = "macos")]
	position: u32,			// OS X only
	#[cfg(target_os = "macos")]
	padding: u32,			// OS X only
}

pub struct fuse_getxattr_in {
	size: u32,
	padding: u32,
	#[cfg(target_os = "macos")]
	position: u32,			// OS X only
	#[cfg(target_os = "macos")]
	padding2: u32,			// OS X only
}

pub struct fuse_getxattr_out {
	size: u32,
	padding: u32,
}

pub struct fuse_lk_in {
	fh: u64,
	owner: u64,
	lk: fuse_file_lock,
}

pub struct fuse_lk_out {
	lk: fuse_file_lock,
}

pub struct fuse_access_in {
	mask: u32,
	padding: u32,
}

pub struct fuse_init_in {
	major: u32,
	minor: u32,
	max_readahead: u32,
	flags: u32,
}

pub struct fuse_init_out {
	major: u32,
	minor: u32,
	max_readahead: u32,
	flags: u32,
	unused: u32,
	max_write: u32,
}

pub struct fuse_interrupt_in {
	unique: u64,
}

pub struct fuse_bmap_in {
	block: u64,
	blocksize: u32,
	padding: u32,
}

pub struct fuse_bmap_out {
	block: u64,
}

pub struct fuse_in_header {
	len: u32,
	opcode: u32,
	unique: u64,
	nodeid: u64,
	uid: u32,
	gid: u32,
	pid: u32,
	padding: u32,
}

pub struct fuse_out_header {
	len: u32,
	error: i32,
	unique: u64,
}

pub struct fuse_dirent {
	ino: u64,
	off: u64,
	namelen: u32,
	typ: u32,
	// followed by name of namelen bytes
}
<|endoftext|>


<commit_before>extern crate html5ever;
// extern crate reqwest;

use std::default::Default;
use std::io;
use http::{retrieve_asset, resolve_url};

use self::html5ever::parse_document;
use self::html5ever::rcdom::{Handle, NodeData, RcDom};
use self::html5ever::tendril::TendrilSink;
use self::html5ever::serialize::{SerializeOpts, serialize};

enum NodeMatch {
    Icon,
    Image,
    StyleSheet,
    Anchor,
    Script,
    Other,
}

static JS_DOM_EVENT_ATTRS: [&str; 21] = [
    // Input
    "onfocus", "onblur", "onselect", "onchange", "onsubmit", "onreset", "onkeydown", "onkeypress", "onkeyup",
    // Mouse
    "onmouseover", "onmouseout", "onmousedown", "onmouseup", "onmousemove",
    // Click
    "onclick", "ondblclick",
    // Load
    "onload", "onunload", "onabort", "onerror", "onresize",
];

pub fn walk_and_embed_assets(url: &str, node: &Handle, opt_no_js: bool) {
    match node.data {
        NodeData::Document => {
            // Dig deeper
            for child in node.children.borrow().iter() {
                walk_and_embed_assets(&url, child, opt_no_js);
            }
        },

        NodeData::Doctype {
            name: _,
            public_id: _,
            system_id: _,
        } => {},

        NodeData::Text { contents: _, } => {},

        NodeData::Comment { contents: _, } => {
            // Note: in case of opt_no_js being set to true, there's no need to worry about
            //       getting rid of comments that may contain scripts, e.g. <!--[if IE]><script>...
            //       since that's not part of W3C standard and gets ignored by browsers other than IE [5, 9]
        },

        NodeData::Element {
            ref name,
            ref attrs,
            ..
        } => {
            let ref mut attrs_mut = attrs.borrow_mut();
            let mut found = NodeMatch::Other;

            if &name.local == "link" {
                for attr in attrs_mut.iter_mut() {
                    if &attr.name.local == "rel" {
                        if is_icon(&attr.value.to_string()) {
                            found = NodeMatch::Icon;
                            break;
                        } else if attr.value.to_string() == "stylesheet" {
                            found = NodeMatch::StyleSheet;
                            break;
                        }
                    }
                }
            } else if &name.local == "img" {
                found = NodeMatch::Image;
            } else if &name.local == "a" {
                found = NodeMatch::Anchor;
            } else if &name.local == "script" {
                found = NodeMatch::Script;
            }

            match found {
                NodeMatch::Icon => {
                    for attr in attrs_mut.iter_mut() {
                        if &attr.name.local == "href" {
                            let href_full_url = resolve_url(&url, &attr.value.to_string());
                            let favicon_datauri = retrieve_asset(&href_full_url.unwrap(), true, "");
                            attr.value.clear();
                            attr.value.push_slice(favicon_datauri.unwrap().as_str());
                        }
                    }
                },
                NodeMatch::Image => {
                    for attr in attrs_mut.iter_mut() {
                        if &attr.name.local == "src" {
                            let href_full_url = resolve_url(&url, &attr.value.to_string());
                            let favicon_datauri = retrieve_asset(&href_full_url.unwrap(), true, "");
                            attr.value.clear();
                            attr.value.push_slice(favicon_datauri.unwrap().as_str());
                        }
                    }
                },
                NodeMatch::Anchor => {
                    for attr in attrs_mut.iter_mut() {
                        if &attr.name.local == "href" {
                            // Do not touch hrefs which begin with a hash sign
                            if attr.value.to_string().chars().nth(0) == Some('#') {
                                continue;
                            }

                            let href_full_url = resolve_url(&url, &attr.value.to_string());
                            attr.value.clear();
                            attr.value.push_slice(href_full_url.unwrap().as_str());
                        }
                    }
                },
                NodeMatch::StyleSheet => {
                    for attr in attrs_mut.iter_mut() {
                        if &attr.name.local == "href" {
                            let href_full_url = resolve_url(&url, &attr.value.to_string());
                            let favicon_datauri = retrieve_asset(&href_full_url.unwrap(), true, "text/css");
                            attr.value.clear();
                            attr.value.push_slice(favicon_datauri.unwrap().as_str());
                        }
                    }
                },
                NodeMatch::Script => {
                    if opt_no_js {
                        // Get rid of src and inner content of SCRIPT tags
                        for attr in attrs_mut.iter_mut() {
                            if &attr.name.local == "src" {
                                attr.value.clear();
                            }
                        }
                        node.children.borrow_mut().clear();
                    } else {
                        for attr in attrs_mut.iter_mut() {
                            if &attr.name.local == "src" {
                                let href_full_url = resolve_url(&url, &attr.value.to_string());
                                let favicon_datauri = retrieve_asset(&href_full_url.unwrap(), true, "application/javascript");
                                attr.value.clear();
                                attr.value.push_slice(favicon_datauri.unwrap().as_str());
                            }
                        }
                    }
                },
                NodeMatch::Other => {},
            }

            if opt_no_js {
                // Get rid of JS event attributes
                for attr in attrs_mut.iter_mut() {
                    if JS_DOM_EVENT_ATTRS.contains(&attr.name.local.to_lowercase().as_str()) {
                        attr.value.clear();
                    }
                }
            }

            // Dig deeper
            for child in node.children.borrow().iter() {
                walk_and_embed_assets(&url, child, opt_no_js);
            }
        },

        NodeData::ProcessingInstruction { .. } => unreachable!(),
    }
}

pub fn html_to_dom(data: &str) -> html5ever::rcdom::RcDom {
    parse_document(RcDom::default(), Default::default())
        .from_utf8()
        .read_from(&mut data.as_bytes())
        .unwrap()
}

pub fn print_dom(handle: &Handle) {
    serialize(&mut io::stdout(), handle, SerializeOpts::default()).unwrap();
}

fn is_icon(attr_value: &str) -> bool {
    attr_value == "icon"
        || attr_value == "shortcut icon"
        || attr_value == "mask-icon"
        || attr_value == "apple-touch-icon"
}

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

    #[test]
    fn test_is_icon() {
        assert_eq!(is_icon("icon"), true);
        assert_eq!(is_icon("stylesheet"), false);
    }
}
<commit_msg>Remove leftover line<commit_after>extern crate html5ever;

use std::default::Default;
use std::io;
use http::{retrieve_asset, resolve_url};

use self::html5ever::parse_document;
use self::html5ever::rcdom::{Handle, NodeData, RcDom};
use self::html5ever::tendril::TendrilSink;
use self::html5ever::serialize::{SerializeOpts, serialize};

enum NodeMatch {
    Icon,
    Image,
    StyleSheet,
    Anchor,
    Script,
    Other,
}

static JS_DOM_EVENT_ATTRS: [&str; 21] = [
    // Input
    "onfocus", "onblur", "onselect", "onchange", "onsubmit", "onreset", "onkeydown", "onkeypress", "onkeyup",
    // Mouse
    "onmouseover", "onmouseout", "onmousedown", "onmouseup", "onmousemove",
    // Click
    "onclick", "ondblclick",
    // Load
    "onload", "onunload", "onabort", "onerror", "onresize",
];

pub fn walk_and_embed_assets(url: &str, node: &Handle, opt_no_js: bool) {
    match node.data {
        NodeData::Document => {
            // Dig deeper
            for child in node.children.borrow().iter() {
                walk_and_embed_assets(&url, child, opt_no_js);
            }
        },

        NodeData::Doctype {
            name: _,
            public_id: _,
            system_id: _,
        } => {},

        NodeData::Text { contents: _, } => {},

        NodeData::Comment { contents: _, } => {
            // Note: in case of opt_no_js being set to true, there's no need to worry about
            //       getting rid of comments that may contain scripts, e.g. <!--[if IE]><script>...
            //       since that's not part of W3C standard and gets ignored by browsers other than IE [5, 9]
        },

        NodeData::Element {
            ref name,
            ref attrs,
            ..
        } => {
            let ref mut attrs_mut = attrs.borrow_mut();
            let mut found = NodeMatch::Other;

            if &name.local == "link" {
                for attr in attrs_mut.iter_mut() {
                    if &attr.name.local == "rel" {
                        if is_icon(&attr.value.to_string()) {
                            found = NodeMatch::Icon;
                            break;
                        } else if attr.value.to_string() == "stylesheet" {
                            found = NodeMatch::StyleSheet;
                            break;
                        }
                    }
                }
            } else if &name.local == "img" {
                found = NodeMatch::Image;
            } else if &name.local == "a" {
                found = NodeMatch::Anchor;
            } else if &name.local == "script" {
                found = NodeMatch::Script;
            }

            match found {
                NodeMatch::Icon => {
                    for attr in attrs_mut.iter_mut() {
                        if &attr.name.local == "href" {
                            let href_full_url = resolve_url(&url, &attr.value.to_string());
                            let favicon_datauri = retrieve_asset(&href_full_url.unwrap(), true, "");
                            attr.value.clear();
                            attr.value.push_slice(favicon_datauri.unwrap().as_str());
                        }
                    }
                },
                NodeMatch::Image => {
                    for attr in attrs_mut.iter_mut() {
                        if &attr.name.local == "src" {
                            let href_full_url = resolve_url(&url, &attr.value.to_string());
                            let favicon_datauri = retrieve_asset(&href_full_url.unwrap(), true, "");
                            attr.value.clear();
                            attr.value.push_slice(favicon_datauri.unwrap().as_str());
                        }
                    }
                },
                NodeMatch::Anchor => {
                    for attr in attrs_mut.iter_mut() {
                        if &attr.name.local == "href" {
                            // Do not touch hrefs which begin with a hash sign
                            if attr.value.to_string().chars().nth(0) == Some('#') {
                                continue;
                            }

                            let href_full_url = resolve_url(&url, &attr.value.to_string());
                            attr.value.clear();
                            attr.value.push_slice(href_full_url.unwrap().as_str());
                        }
                    }
                },
                NodeMatch::StyleSheet => {
                    for attr in attrs_mut.iter_mut() {
                        if &attr.name.local == "href" {
                            let href_full_url = resolve_url(&url, &attr.value.to_string());
                            let favicon_datauri = retrieve_asset(&href_full_url.unwrap(), true, "text/css");
                            attr.value.clear();
                            attr.value.push_slice(favicon_datauri.unwrap().as_str());
                        }
                    }
                },
                NodeMatch::Script => {
                    if opt_no_js {
                        // Get rid of src and inner content of SCRIPT tags
                        for attr in attrs_mut.iter_mut() {
                            if &attr.name.local == "src" {
                                attr.value.clear();
                            }
                        }
                        node.children.borrow_mut().clear();
                    } else {
                        for attr in attrs_mut.iter_mut() {
                            if &attr.name.local == "src" {
                                let href_full_url = resolve_url(&url, &attr.value.to_string());
                                let favicon_datauri = retrieve_asset(&href_full_url.unwrap(), true, "application/javascript");
                                attr.value.clear();
                                attr.value.push_slice(favicon_datauri.unwrap().as_str());
                            }
                        }
                    }
                },
                NodeMatch::Other => {},
            }

            if opt_no_js {
                // Get rid of JS event attributes
                for attr in attrs_mut.iter_mut() {
                    if JS_DOM_EVENT_ATTRS.contains(&attr.name.local.to_lowercase().as_str()) {
                        attr.value.clear();
                    }
                }
            }

            // Dig deeper
            for child in node.children.borrow().iter() {
                walk_and_embed_assets(&url, child, opt_no_js);
            }
        },

        NodeData::ProcessingInstruction { .. } => unreachable!(),
    }
}

pub fn html_to_dom(data: &str) -> html5ever::rcdom::RcDom {
    parse_document(RcDom::default(), Default::default())
        .from_utf8()
        .read_from(&mut data.as_bytes())
        .unwrap()
}

pub fn print_dom(handle: &Handle) {
    serialize(&mut io::stdout(), handle, SerializeOpts::default()).unwrap();
}

fn is_icon(attr_value: &str) -> bool {
    attr_value == "icon"
        || attr_value == "shortcut icon"
        || attr_value == "mask-icon"
        || attr_value == "apple-touch-icon"
}

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

    #[test]
    fn test_is_icon() {
        assert_eq!(is_icon("icon"), true);
        assert_eq!(is_icon("stylesheet"), false);
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// 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.

/*!
 * __ears__ initialization (optional).
 *
 * This module provide a unique function to initialize __ears__.
 * Use this function in the case of you don't use __ears__ for the first time
 * in you program in the main task. This prevent that the context was created
 * and destroyed in a another task.
 */

use record_context::RecordContext;
use internal::OpenAlData;

/**
 * Initialize the internal context
 *
 * # Return
 * true if initialization is made with success, false otherwise
 */
pub fn init() -> bool {
    match OpenAlData::check_al_context() {
        Ok(_)       => true,
        Err(err)    => { println!("{}", err); false }
    }
}

/**
 * Initialize the input device context
 *
 * # Return
 * true if initialization is made with success, false otherwise
 */
pub fn init_in() -> Option<RecordContext> {
    match OpenAlData::check_al_input_context() {
        Ok(ctxt)     => Some(ctxt),
        Err(err)     => { println!("{}", err); None }
    }
}

#[cfg(test)]
mod test {
    use init;
    use init_in;

    #[test]
    fn test_init_ears_OK() -> () {
        assert_eq!(init(), true)
    }

    #[test]
    fn test_init_in_with_normal_init_OK() -> () {
        init();
        assert!(init_in().is_some())
    }

    #[test]
    fn test_init_in_alone_OK() -> () {
        assert!(init_in().is_some())
    }

    #[test]
    fn test_init_in_in_another_task_OK() -> () {
        init();
        spawn(proc() {
            assert_eq!(init_in(), None)
        })
    }
}
<commit_msg>ignore two tests -> capture devices on travis.<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// 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.

/*!
 * __ears__ initialization (optional).
 *
 * This module provide a unique function to initialize __ears__.
 * Use this function in the case of you don't use __ears__ for the first time
 * in you program in the main task. This prevent that the context was created
 * and destroyed in a another task.
 */

use record_context::RecordContext;
use internal::OpenAlData;

/**
 * Initialize the internal context
 *
 * # Return
 * true if initialization is made with success, false otherwise
 */
pub fn init() -> bool {
    match OpenAlData::check_al_context() {
        Ok(_)       => true,
        Err(err)    => { println!("{}", err); false }
    }
}

/**
 * Initialize the input device context
 *
 * # Return
 * true if initialization is made with success, false otherwise
 */
pub fn init_in() -> Option<RecordContext> {
    match OpenAlData::check_al_input_context() {
        Ok(ctxt)     => Some(ctxt),
        Err(err)     => { println!("{}", err); None }
    }
}

#[cfg(test)]
mod test {
    use init;
    use init_in;

    #[test]
    fn test_init_ears_OK() -> () {
        assert_eq!(init(), true)
    }

    #[test]
    #[ignore]
    fn test_init_in_with_normal_init_OK() -> () {
        init();
        assert!(init_in().is_some())
    }

    #[test]
    #[ignore]
    fn test_init_in_alone_OK() -> () {
        assert!(init_in().is_some())
    }

    #[test]
    fn test_init_in_in_another_task_OK() -> () {
        init();
        spawn(proc() {
            assert_eq!(init_in(), None)
        })
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// 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.

/*!
 * __ears__ initialization (optional).
 *
 * This module provide a unique function to initialize __ears__.
 * Use this function in the case of you don't use __ears__ for the first time
 * in you program in the main task. This prevent that the context was created
 * and destroyed in a another task.
 */

use record_context::RecordContext;
use internal::OpenAlData;

/**
 * Initialize the internal context
 *
 * # Return
 * true if initialization is made with success, false otherwise
 *
 * # Example
 * ```
 * match ears::init() {
 *     true  => {
 *         // do stuff
 *     },
 *     false => panic!("ears init error")
 * }
 * ```
 */
pub fn init() -> bool {
    match OpenAlData::check_al_context() {
        Ok(_)    => true,
        Err(err) => { println!("{}", err); false }
    }
}

/**
 * Initialize the input device context
 *
 * # Return
 * true if initialization is made with success, false otherwise
 *
 * # Example
 * ```no_run
 * match ears::init_in() {
 *     Some(rc) => {
 *         // do stuff
 *     },
 *     None     => panic!("ears init input error")
 * }
 * ```
 */
pub fn init_in() -> Option<RecordContext> {
    match OpenAlData::check_al_input_context() {
        Ok(ctxt) => Some(ctxt),
        Err(err) => { println!("{}", err); None }
    }
}

#[cfg(test)]
mod test {
    #![allow(non_snake_case)]

    use init;
    use init_in;
	use std::thread;

    #[test]
    #[ignore]
    fn test_init_ears_OK() -> () {
        assert_eq!(init(), true)
    }

    #[test]
    #[ignore]
    fn test_init_in_with_normal_init_OK() -> () {
        init();
        assert!(init_in().is_some())
    }

    #[test]
    #[ignore]
    fn test_init_in_alone_OK() -> () {
        assert!(init_in().is_some())
    }

    #[test]
    #[ignore]
    fn test_init_in_in_another_task_OK() -> () {
        init();
        thread::spawn(move || {
            assert_eq!(init_in(), None)
        });
    }
}
<commit_msg>Don't run test on CI<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// 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.

/*!
 * __ears__ initialization (optional).
 *
 * This module provide a unique function to initialize __ears__.
 * Use this function in the case of you don't use __ears__ for the first time
 * in you program in the main task. This prevent that the context was created
 * and destroyed in a another task.
 */

use record_context::RecordContext;
use internal::OpenAlData;

/**
 * Initialize the internal context
 *
 * # Return
 * true if initialization is made with success, false otherwise
 *
 * # Example
 * ```no_run
 * match ears::init() {
 *     true  => {
 *         // do stuff
 *     },
 *     false => panic!("ears init error")
 * }
 * ```
 */
pub fn init() -> bool {
    match OpenAlData::check_al_context() {
        Ok(_)    => true,
        Err(err) => { println!("{}", err); false }
    }
}

/**
 * Initialize the input device context
 *
 * # Return
 * true if initialization is made with success, false otherwise
 *
 * # Example
 * ```no_run
 * match ears::init_in() {
 *     Some(rc) => {
 *         // do stuff
 *     },
 *     None     => panic!("ears init input error")
 * }
 * ```
 */
pub fn init_in() -> Option<RecordContext> {
    match OpenAlData::check_al_input_context() {
        Ok(ctxt) => Some(ctxt),
        Err(err) => { println!("{}", err); None }
    }
}

#[cfg(test)]
mod test {
    #![allow(non_snake_case)]

    use init;
    use init_in;
	use std::thread;

    #[test]
    #[ignore]
    fn test_init_ears_OK() -> () {
        assert_eq!(init(), true)
    }

    #[test]
    #[ignore]
    fn test_init_in_with_normal_init_OK() -> () {
        init();
        assert!(init_in().is_some())
    }

    #[test]
    #[ignore]
    fn test_init_in_alone_OK() -> () {
        assert!(init_in().is_some())
    }

    #[test]
    #[ignore]
    fn test_init_in_in_another_task_OK() -> () {
        init();
        thread::spawn(move || {
            assert_eq!(init_in(), None)
        });
    }
}
<|endoftext|>


<commit_before>use conf;
use itertools::Itertools;
use lisp::LispExpr;
use lisp;
use rusqlite as sql;
use rustc::front::map::Node;
use rustc::lint::{LateContext, LintArray, LintContext, LintPass, LateLintPass};
use rustc::middle::ty::TypeVariants;
use rustc_front::hir::*;
use std::borrow::Cow;
use std::io::{Read, Write};
use std::process::{Command, Stdio};
use std::time::Duration;
use std;
use syntax::ast::MetaItemKind;
use syntax::ast::{Attribute, FloatTy};
use wait_timeout::ChildExt;

#[derive(Debug)]
pub struct Herbie {
    conf: Option<conf::Conf>,
    initialized: bool,
    subs: Vec<(LispExpr, LispExpr)>,
}

#[derive(Debug)]
pub enum InitError {
    Conf {
        error: conf::ConfError,
    },
    SQL {
        error: sql::Error,
    },
}

impl From<conf::ConfError> for InitError {
    fn from(err: conf::ConfError) -> InitError {
        InitError::Conf { error: err }
    }
}

impl From<sql::Error> for InitError {
    fn from(err: sql::Error) -> InitError {
        InitError::SQL { error: err }
    }
}

impl std::fmt::Display for InitError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        match *self {
            InitError::Conf { ref error } => write!(f, "Configuration error: {}", error),
            InitError::SQL { ref error } => write!(f, "Got SQL error: {}", error),
        }
    }
}

impl Herbie {
    pub fn new() -> Herbie {
        Herbie {
            conf: None,
            initialized: false,
            subs: Vec::new(),
        }
    }

    pub fn init(&mut self) -> Result<(), InitError> {
        if self.initialized {
            return Ok(())
        }

        self.initialized = true;

        let conf = try!(conf::read_conf());
        let conn = try!(sql::Connection::open_with_flags(
            conf.db_path.as_ref(), sql::SQLITE_OPEN_READ_ONLY
        ));
        let mut query = try!(conn.prepare("SELECT * FROM HerbieResults"));

        self.subs = try!(query.query(&[])).filter_map(|row| {
            match row {
                Ok(row) => {
                    let cmdin : String = row.get(1);
                    let cmdout : String = row.get(2);
                    // row.get(3) is opts ↔ Herbies options
                    let errin = row.get_checked(4).unwrap_or(0.);
                    let errout = row.get_checked(5).unwrap_or(0.);

                    if cmdin == cmdout || errin <= errout {
                        return None;
                    }

                    let mut parser = lisp::Parser::new();
                    match parser.parse(&cmdin) {
                        Ok(cmdin) => {
                            match parser.parse(&cmdout) {
                                Ok(cmdout) => {
                                    Some((cmdin, cmdout))
                                }
                                Err(..) => None,
                            }
                        }
                        Err(..) => None,
                    }
                }
                Err(..) => None,
            }
        }).collect();

        self.conf = Some(conf);

        Ok(())
    }

}

declare_lint!(pub HERBIE, Warn,
              "checks for numerical instability");

impl LintPass for Herbie {
    fn get_lints(&self) -> LintArray {
        lint_array!(HERBIE)
    }
}

impl LateLintPass for Herbie {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        fn is_herbie_ignore(attr: &Attribute) -> bool {
            if let MetaItemKind::Word(ref word) = attr.node.value.node {
                word == &"herbie_ignore"
            }
            else {
                false
            }
        }

        let attrs = match cx.tcx.map.find(cx.tcx.map.get_parent(expr.id)) {
            Some(Node::NodeItem(item)) => &item.attrs,
            Some(Node::NodeTraitItem(item)) => &item.attrs,
            Some(Node::NodeImplItem(item)) => &item.attrs,
            _ => panic!("In herbie-lint: how did I get there?"),
        };

        if attrs.iter().any(is_herbie_ignore) {
            return;
        }

        let ty = cx.tcx.expr_ty(expr);

        if ty.sty != TypeVariants::TyFloat(FloatTy::F64) {
            return;
        }

        if let Err(err) =  self.init() {
            cx.span_lint_note(
                HERBIE,
                cx.krate.span,
                "Could not initialize Herbie-Lint",
                cx.krate.span,
                &err.to_string()
            );
            return;
        }

        let mut got_match = false;
        for &(ref cmdin, ref cmdout) in &self.subs {
            if let Some(bindings) = LispExpr::match_expr(expr, cmdin) {
                report(cx, expr, cmdout, &bindings);
                got_match = true;
            }
        }

        let conf = self.conf.as_ref().expect("Configuration should be read by now");
        if !got_match && conf.use_herbie != conf::UseHerbieConf::No {
            if let Err(err) = try_with_herbie(cx, expr, &conf) {
                cx.span_lint(HERBIE, expr.span, &err);
            }
        }
    }
}

fn try_with_herbie(cx: &LateContext, expr: &Expr, conf: &conf::Conf) -> Result<(), Cow<'static, str>> {
    let (lisp_expr, nb_ids, bindings) = match LispExpr::from_expr(expr) {
        Some(r) => r,
        // not an error, the expression might for example contain a function unknown to Herbie
        None => return Ok(()),
    };

    if lisp_expr.depth() <= 2 {
        return Ok(());
    }

    let seed: &str = &conf.herbie_seed;
    let mut command = Command::new("herbie-inout");
    let command = command
        .arg("--seed").arg(seed)
        .arg("-o").arg("rules:numerics")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
    ;

    let mut child = match command.spawn() {
        Ok(child) => child,
        Err(err) => {
            return if conf.use_herbie == conf::UseHerbieConf::Yes {
                // TODO: wiki
                Err(format!("Could not call Herbie: {}", err).into())
            }
            else {
                Ok(())
            };
        }
    };

    // TODO: link to wiki about Herbie.toml
    cx.sess().diagnostic().span_note_without_error(
        expr.span,
        "Calling Herbie on the following expression, it might take a while"
    );

    let params = (0..nb_ids).map(|id| format!("herbie{}", id)).join(" ");
    let cmdin = lisp_expr.to_lisp("herbie");
    let lisp_expr = format!("(lambda ({}) {})\n", params, cmdin);
    let lisp_expr = lisp_expr.as_bytes();
    child.stdin
        .as_mut().expect("Herbie-inout's stdin not captured")
        .write(lisp_expr).expect("Could not write on herbie-inout's stdin")
    ;

    match conf.timeout {
        Some(timeout) => {
            match child.wait_timeout(Duration::from_secs(timeout as u64)) {
                Ok(Some(status)) if status.success() => (),
                Ok(Some(status)) => {
                    return Err(format!("herbie-inout did not return successfully: status={}", status).into());
                }
                Ok(None) => {
                    cx.sess().diagnostic().span_note_without_error(expr.span, "Herbie timed out");
                    return Ok(());
                }
                Err(err) => {
                    return Err(format!("herbie-inout did not return successfully: {}", err).into());
                }
            }
        }
        None => {
            match child.wait() {
                Ok(status) if status.success() => (),
                Ok(status) => {
                    return Err(format!("herbie-inout did not return successfully: status={}", status).into());
                }
                Err(err) => {
                    return Err(format!("herbie-inout did not return successfully: {}", err).into());
                }
            }
        }
    }

    let mut stdout = if let Some(output) = child.stdout {
        output
    }
    else {
        return Err("cannot capture herbie-inout output".into());
    };

    let mut output = String::new();
    if let Err(err) = stdout.read_to_string(&mut output) {
        return Err(format!("cannot read output: {}", err).into());
    }

    let mut output = output.lines();

    let parse_error = |s: Option<&str>| -> Option<f64> {
        match s {
            Some(s) => {
                match s.split(' ').last().map(str::parse::<f64>) {
                    Some(Ok(f)) => Some(f),
                    _ => None,
                }
            }
            _ => None,
        }
    };

    let (errin, errout, cmdout) = match (parse_error(output.next()), parse_error(output.next()), output.next()) {
        (Some(errin), Some(errout), Some(cmdout)) => {
            (errin, errout, cmdout)
        }
        _ => {
            return Err("Could not parse herbie-inout output".into())
        }
    };

    if errin <= errout {
        return Ok(());
    }

    let mut parser = lisp::Parser::new();
    let cmdout = match parser.parse(cmdout) {
        Ok(cmdout) => cmdout,
        _ => return Err("Could not understand herbie-inout cmdout".into()),
    };

    report(cx, expr, &cmdout, &bindings);
    save(conf, &cmdin, &cmdout, "", errin, errout)
        .map_err(|err| format!("Could not save database, got SQL error {}", err).into())
}

fn report(cx: &LateContext, expr: &Expr, cmdout: &LispExpr, bindings: &lisp::MatchBindings) {
    cx.struct_span_lint(HERBIE, expr.span, "Numerically unstable expression")
      .span_suggestion(expr.span, "Try this", cmdout.to_rust(cx, &bindings))
      .emit();
}

fn save(
    conf: &conf::Conf,
    cmdin: &str, cmdout: &LispExpr,
    seed: &str,
    errin: f64, errout: f64
) -> Result<(), sql::Error> {
    let conn = try!(sql::Connection::open_with_flags(
        conf.db_path.as_ref(), sql::SQLITE_OPEN_READ_WRITE
    ));

    try!(conn.execute("INSERT INTO HerbieResults (cmdin, cmdout, opts, errin, errout)
                       VALUES ($1, $2, $3, $4, $5)",
                       &[&cmdin, &cmdout.to_lisp("herbie"), &seed, &errin, &errout]));

    Ok(())
}
<commit_msg>Rustup to *1.9.0-nightly (d5a91e695 2016-03-26)*<commit_after>use conf;
use itertools::Itertools;
use lisp::LispExpr;
use lisp;
use rusqlite as sql;
use rustc::front::map::Node;
use rustc::lint::{LateContext, LintArray, LintContext, LintPass, LateLintPass};
use rustc::ty::TypeVariants;
use rustc_front::hir::*;
use std::borrow::Cow;
use std::io::{Read, Write};
use std::process::{Command, Stdio};
use std::time::Duration;
use std;
use syntax::ast::MetaItemKind;
use syntax::ast::{Attribute, FloatTy};
use wait_timeout::ChildExt;

#[derive(Debug)]
pub struct Herbie {
    conf: Option<conf::Conf>,
    initialized: bool,
    subs: Vec<(LispExpr, LispExpr)>,
}

#[derive(Debug)]
pub enum InitError {
    Conf {
        error: conf::ConfError,
    },
    SQL {
        error: sql::Error,
    },
}

impl From<conf::ConfError> for InitError {
    fn from(err: conf::ConfError) -> InitError {
        InitError::Conf { error: err }
    }
}

impl From<sql::Error> for InitError {
    fn from(err: sql::Error) -> InitError {
        InitError::SQL { error: err }
    }
}

impl std::fmt::Display for InitError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        match *self {
            InitError::Conf { ref error } => write!(f, "Configuration error: {}", error),
            InitError::SQL { ref error } => write!(f, "Got SQL error: {}", error),
        }
    }
}

impl Herbie {
    pub fn new() -> Herbie {
        Herbie {
            conf: None,
            initialized: false,
            subs: Vec::new(),
        }
    }

    pub fn init(&mut self) -> Result<(), InitError> {
        if self.initialized {
            return Ok(())
        }

        self.initialized = true;

        let conf = try!(conf::read_conf());
        let conn = try!(sql::Connection::open_with_flags(
            conf.db_path.as_ref(), sql::SQLITE_OPEN_READ_ONLY
        ));
        let mut query = try!(conn.prepare("SELECT * FROM HerbieResults"));

        self.subs = try!(query.query(&[])).filter_map(|row| {
            match row {
                Ok(row) => {
                    let cmdin : String = row.get(1);
                    let cmdout : String = row.get(2);
                    // row.get(3) is opts ↔ Herbies options
                    let errin = row.get_checked(4).unwrap_or(0.);
                    let errout = row.get_checked(5).unwrap_or(0.);

                    if cmdin == cmdout || errin <= errout {
                        return None;
                    }

                    let mut parser = lisp::Parser::new();
                    match parser.parse(&cmdin) {
                        Ok(cmdin) => {
                            match parser.parse(&cmdout) {
                                Ok(cmdout) => {
                                    Some((cmdin, cmdout))
                                }
                                Err(..) => None,
                            }
                        }
                        Err(..) => None,
                    }
                }
                Err(..) => None,
            }
        }).collect();

        self.conf = Some(conf);

        Ok(())
    }

}

declare_lint!(pub HERBIE, Warn,
              "checks for numerical instability");

impl LintPass for Herbie {
    fn get_lints(&self) -> LintArray {
        lint_array!(HERBIE)
    }
}

impl LateLintPass for Herbie {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        fn is_herbie_ignore(attr: &Attribute) -> bool {
            if let MetaItemKind::Word(ref word) = attr.node.value.node {
                word == &"herbie_ignore"
            }
            else {
                false
            }
        }

        let attrs = match cx.tcx.map.find(cx.tcx.map.get_parent(expr.id)) {
            Some(Node::NodeItem(item)) => &item.attrs,
            Some(Node::NodeTraitItem(item)) => &item.attrs,
            Some(Node::NodeImplItem(item)) => &item.attrs,
            _ => panic!("In herbie-lint: how did I get there?"),
        };

        if attrs.iter().any(is_herbie_ignore) {
            return;
        }

        let ty = cx.tcx.expr_ty(expr);

        if ty.sty != TypeVariants::TyFloat(FloatTy::F64) {
            return;
        }

        if let Err(err) =  self.init() {
            cx.span_lint_note(
                HERBIE,
                cx.krate.span,
                "Could not initialize Herbie-Lint",
                cx.krate.span,
                &err.to_string()
            );
            return;
        }

        let mut got_match = false;
        for &(ref cmdin, ref cmdout) in &self.subs {
            if let Some(bindings) = LispExpr::match_expr(expr, cmdin) {
                report(cx, expr, cmdout, &bindings);
                got_match = true;
            }
        }

        let conf = self.conf.as_ref().expect("Configuration should be read by now");
        if !got_match && conf.use_herbie != conf::UseHerbieConf::No {
            if let Err(err) = try_with_herbie(cx, expr, &conf) {
                cx.span_lint(HERBIE, expr.span, &err);
            }
        }
    }
}

fn try_with_herbie(cx: &LateContext, expr: &Expr, conf: &conf::Conf) -> Result<(), Cow<'static, str>> {
    let (lisp_expr, nb_ids, bindings) = match LispExpr::from_expr(expr) {
        Some(r) => r,
        // not an error, the expression might for example contain a function unknown to Herbie
        None => return Ok(()),
    };

    if lisp_expr.depth() <= 2 {
        return Ok(());
    }

    let seed: &str = &conf.herbie_seed;
    let mut command = Command::new("herbie-inout");
    let command = command
        .arg("--seed").arg(seed)
        .arg("-o").arg("rules:numerics")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
    ;

    let mut child = match command.spawn() {
        Ok(child) => child,
        Err(err) => {
            return if conf.use_herbie == conf::UseHerbieConf::Yes {
                // TODO: wiki
                Err(format!("Could not call Herbie: {}", err).into())
            }
            else {
                Ok(())
            };
        }
    };

    // TODO: link to wiki about Herbie.toml
    cx.sess().diagnostic().span_note_without_error(
        expr.span,
        "Calling Herbie on the following expression, it might take a while"
    );

    let params = (0..nb_ids).map(|id| format!("herbie{}", id)).join(" ");
    let cmdin = lisp_expr.to_lisp("herbie");
    let lisp_expr = format!("(lambda ({}) {})\n", params, cmdin);
    let lisp_expr = lisp_expr.as_bytes();
    child.stdin
        .as_mut().expect("Herbie-inout's stdin not captured")
        .write(lisp_expr).expect("Could not write on herbie-inout's stdin")
    ;

    match conf.timeout {
        Some(timeout) => {
            match child.wait_timeout(Duration::from_secs(timeout as u64)) {
                Ok(Some(status)) if status.success() => (),
                Ok(Some(status)) => {
                    return Err(format!("herbie-inout did not return successfully: status={}", status).into());
                }
                Ok(None) => {
                    cx.sess().diagnostic().span_note_without_error(expr.span, "Herbie timed out");
                    return Ok(());
                }
                Err(err) => {
                    return Err(format!("herbie-inout did not return successfully: {}", err).into());
                }
            }
        }
        None => {
            match child.wait() {
                Ok(status) if status.success() => (),
                Ok(status) => {
                    return Err(format!("herbie-inout did not return successfully: status={}", status).into());
                }
                Err(err) => {
                    return Err(format!("herbie-inout did not return successfully: {}", err).into());
                }
            }
        }
    }

    let mut stdout = if let Some(output) = child.stdout {
        output
    }
    else {
        return Err("cannot capture herbie-inout output".into());
    };

    let mut output = String::new();
    if let Err(err) = stdout.read_to_string(&mut output) {
        return Err(format!("cannot read output: {}", err).into());
    }

    let mut output = output.lines();

    let parse_error = |s: Option<&str>| -> Option<f64> {
        match s {
            Some(s) => {
                match s.split(' ').last().map(str::parse::<f64>) {
                    Some(Ok(f)) => Some(f),
                    _ => None,
                }
            }
            _ => None,
        }
    };

    let (errin, errout, cmdout) = match (parse_error(output.next()), parse_error(output.next()), output.next()) {
        (Some(errin), Some(errout), Some(cmdout)) => {
            (errin, errout, cmdout)
        }
        _ => {
            return Err("Could not parse herbie-inout output".into())
        }
    };

    if errin <= errout {
        return Ok(());
    }

    let mut parser = lisp::Parser::new();
    let cmdout = match parser.parse(cmdout) {
        Ok(cmdout) => cmdout,
        _ => return Err("Could not understand herbie-inout cmdout".into()),
    };

    report(cx, expr, &cmdout, &bindings);
    save(conf, &cmdin, &cmdout, "", errin, errout)
        .map_err(|err| format!("Could not save database, got SQL error {}", err).into())
}

fn report(cx: &LateContext, expr: &Expr, cmdout: &LispExpr, bindings: &lisp::MatchBindings) {
    cx.struct_span_lint(HERBIE, expr.span, "Numerically unstable expression")
      .span_suggestion(expr.span, "Try this", cmdout.to_rust(cx, &bindings))
      .emit();
}

fn save(
    conf: &conf::Conf,
    cmdin: &str, cmdout: &LispExpr,
    seed: &str,
    errin: f64, errout: f64
) -> Result<(), sql::Error> {
    let conn = try!(sql::Connection::open_with_flags(
        conf.db_path.as_ref(), sql::SQLITE_OPEN_READ_WRITE
    ));

    try!(conn.execute("INSERT INTO HerbieResults (cmdin, cmdout, opts, errin, errout)
                       VALUES ($1, $2, $3, $4, $5)",
                       &[&cmdin, &cmdout.to_lisp("herbie"), &seed, &errin, &errout]));

    Ok(())
}
<|endoftext|>


<commit_before>//! Utilities used for working with erlang linked lists.
//!
//! Right now the only supported way to read lists are through the NifListIterator.

use super::{ NifTerm, NifError, NifResult, NifDecoder, NifEncoder, NifEnv };
use ::wrapper::list;

/// Enables iteration over the items in the list.
///
/// Although this behaves like a standard Rust iterator
/// ([book](https://doc.rust-lang.org/book/iterators.html) /
/// [docs](https://doc.rust-lang.org/std/iter/trait.Iterator.html)), there are a couple of tricky
/// parts to using it.
///
/// Because the iterator is an iterator over `NifTerm`s, you need to decode the terms before you
/// can do anything with them.
///
/// ## Example
/// An easy way to decode all terms in a list, is to use the `.map()` function of the iterator, and
/// decode every entry in the list. This will produce an iterator of `Result`s, and will therefore
/// not be directly usable in the way you might immediately expect.
///
/// For this case, the the `.collect()` function of rust iterators is useful, as it can lift
/// the `Result`s out of the list. (Contains extra type annotations for clarity)
///
/// ```
/// let list_iterator: NifListIterator = try!(list_term.decode());
///
/// let result: NifResult<Vec<i64>> = iter
///     // Produces an iterator of NifResult<i64>
///     .map(|x| x.decode::<i64>())
///     // Lifts each value out of the result. Returns Ok(Vec<i64>) if successful, the first error
///     // Error(NifError) on failure.
///     .collect::<NifResult<Vec<i64>>>();
/// ```
pub struct NifListIterator<'a> {
    term: NifTerm<'a>,
}

impl<'a> NifListIterator<'a> {

    fn new(term: NifTerm<'a>) -> Option<Self> {
        let term_c = term.as_c_arg();
        let env_c = term.get_env().as_c_arg();
        if list::is_list(env_c, term_c) || list::is_empty_list(env_c, term_c) {
            let iter = NifListIterator {
                term: term,
            };
            Some(iter)
        } else {
            None
        }
    }

}

impl<'a> Iterator for NifListIterator<'a> {
    type Item = NifTerm<'a>;

    fn next(&mut self) -> Option<NifTerm<'a>> {
        let env = self.term.get_env();
        let cell = list::get_list_cell(env.as_c_arg(), self.term.as_c_arg());

        match cell {
            Some((head, tail)) => {
                self.term = NifTerm::new(self.term.get_env(), tail);
                Some(NifTerm::new(self.term.get_env(), head))
            }
            None => {
                if list::is_empty_list(env.as_c_arg(), self.term.as_c_arg()) {
                    // We reached the end of the list, finish the iterator.
                    None
                } else {
                    panic!("list iterator found improper list")
                }
            }
        }
    }
}

impl<'a> NifDecoder<'a> for NifListIterator<'a> {
    fn decode(term: NifTerm<'a>) -> NifResult<Self> {
        match NifListIterator::new(term) {
            Some(iter) => Ok(iter),
            None => Err(NifError::BadArg)
        }
    }
}

//impl<'a, T> NifEncoder for Iterator<Item = T> where T: NifEncoder {
//    fn encode<'b>(&self, env: &'b NifEnv) -> NifTerm<'b> {
//        let term_arr: Vec<::wrapper::nif_interface::NIF_TERM> =
//            self.map(|x| x.encode(env).as_c_arg()).collect();
//    }
//}

impl<'a, T> NifEncoder for Vec<T> where T: NifEncoder {
    fn encode<'b>(&self, env: &'b NifEnv) -> NifTerm<'b> {
        let term_array: Vec<::wrapper::nif_interface::NIF_TERM> =
            self.iter().map(|x| x.encode(env).as_c_arg()).collect();
        NifTerm::new(env, list::make_list(env.as_c_arg(), &term_array))
    }
}

impl<'a, T> NifDecoder<'a> for Vec<T> where T: NifDecoder<'a> {
    fn decode(term: NifTerm<'a>) -> NifResult<Self> {
        let iter: NifListIterator = try!(term.decode());
        let res: NifResult<Self> = iter
            .map(|x| x.decode::<T>())
            .collect();
        res
    }
}
<commit_msg>fix variable name in the doc example (#31)<commit_after>//! Utilities used for working with erlang linked lists.
//!
//! Right now the only supported way to read lists are through the NifListIterator.

use super::{ NifTerm, NifError, NifResult, NifDecoder, NifEncoder, NifEnv };
use ::wrapper::list;

/// Enables iteration over the items in the list.
///
/// Although this behaves like a standard Rust iterator
/// ([book](https://doc.rust-lang.org/book/iterators.html) /
/// [docs](https://doc.rust-lang.org/std/iter/trait.Iterator.html)), there are a couple of tricky
/// parts to using it.
///
/// Because the iterator is an iterator over `NifTerm`s, you need to decode the terms before you
/// can do anything with them.
///
/// ## Example
/// An easy way to decode all terms in a list, is to use the `.map()` function of the iterator, and
/// decode every entry in the list. This will produce an iterator of `Result`s, and will therefore
/// not be directly usable in the way you might immediately expect.
///
/// For this case, the the `.collect()` function of rust iterators is useful, as it can lift
/// the `Result`s out of the list. (Contains extra type annotations for clarity)
///
/// ```
/// let list_iterator: NifListIterator = try!(list_term.decode());
///
/// let result: NifResult<Vec<i64>> = list_interator
///     // Produces an iterator of NifResult<i64>
///     .map(|x| x.decode::<i64>())
///     // Lifts each value out of the result. Returns Ok(Vec<i64>) if successful, the first error
///     // Error(NifError) on failure.
///     .collect::<NifResult<Vec<i64>>>();
/// ```
pub struct NifListIterator<'a> {
    term: NifTerm<'a>,
}

impl<'a> NifListIterator<'a> {

    fn new(term: NifTerm<'a>) -> Option<Self> {
        let term_c = term.as_c_arg();
        let env_c = term.get_env().as_c_arg();
        if list::is_list(env_c, term_c) || list::is_empty_list(env_c, term_c) {
            let iter = NifListIterator {
                term: term,
            };
            Some(iter)
        } else {
            None
        }
    }

}

impl<'a> Iterator for NifListIterator<'a> {
    type Item = NifTerm<'a>;

    fn next(&mut self) -> Option<NifTerm<'a>> {
        let env = self.term.get_env();
        let cell = list::get_list_cell(env.as_c_arg(), self.term.as_c_arg());

        match cell {
            Some((head, tail)) => {
                self.term = NifTerm::new(self.term.get_env(), tail);
                Some(NifTerm::new(self.term.get_env(), head))
            }
            None => {
                if list::is_empty_list(env.as_c_arg(), self.term.as_c_arg()) {
                    // We reached the end of the list, finish the iterator.
                    None
                } else {
                    panic!("list iterator found improper list")
                }
            }
        }
    }
}

impl<'a> NifDecoder<'a> for NifListIterator<'a> {
    fn decode(term: NifTerm<'a>) -> NifResult<Self> {
        match NifListIterator::new(term) {
            Some(iter) => Ok(iter),
            None => Err(NifError::BadArg)
        }
    }
}

//impl<'a, T> NifEncoder for Iterator<Item = T> where T: NifEncoder {
//    fn encode<'b>(&self, env: &'b NifEnv) -> NifTerm<'b> {
//        let term_arr: Vec<::wrapper::nif_interface::NIF_TERM> =
//            self.map(|x| x.encode(env).as_c_arg()).collect();
//    }
//}

impl<'a, T> NifEncoder for Vec<T> where T: NifEncoder {
    fn encode<'b>(&self, env: &'b NifEnv) -> NifTerm<'b> {
        let term_array: Vec<::wrapper::nif_interface::NIF_TERM> =
            self.iter().map(|x| x.encode(env).as_c_arg()).collect();
        NifTerm::new(env, list::make_list(env.as_c_arg(), &term_array))
    }
}

impl<'a, T> NifDecoder<'a> for Vec<T> where T: NifDecoder<'a> {
    fn decode(term: NifTerm<'a>) -> NifResult<Self> {
        let iter: NifListIterator = try!(term.decode());
        let res: NifResult<Self> = iter
            .map(|x| x.decode::<T>())
            .collect();
        res
    }
}
<|endoftext|>


<commit_before>#![feature(env,old_io,old_path,os)]

extern crate mesh;
extern crate getopts;
extern crate nalgebra;

use std::old_io::BufferedReader;
use std::old_io::fs::File;
use mesh::StlFile;
use mesh::AmfFile;
use mesh::POV;
use mesh::Mesh;
use mesh::Vector3D;
use getopts::Options;
use std::os;
use nalgebra::*;

fn main() {
    let args: Vec<String> = os::args();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optopt("i", "input", "File name to process", "FILE");
    opts.optflag("p", "povray", "Export the model into POV-Ray format");
    opts.optflag("a", "amf", "Export the model into AMF format");
    opts.optflag("v", "view", "Print the model to the console");
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(args.tail()) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };

    if matches.opt_present("h") {
        print_usage(program.as_slice(), opts);
        return;
    };

    let export_to_povray = matches.opt_present("p");
    let export_to_amf = matches.opt_present("a");
    let export_to_console = matches.opt_present("v");

    let input_file = match matches.opt_str("i") {
        Some(x) => x,
        None => panic!("No input file"),
    };

    let input_file_copy = input_file.clone();

    let meshfile = File::open(&Path::new(input_file));

    let file = match StlFile::read(&mut BufferedReader::new(meshfile)) {
        Ok(f) => f,
        Err(e) => { println!("STL file error: {}", e); return; }
    };

    let mesh = file.as_mesh();

    // Process free as commands
    let mut commands: Vec<Box<MeshOperation>> = Vec::new();
    let mut iter = matches.free.iter();
    loop {
        let command_name = match iter.next() {
            None => break, // empty
            Some(x) => x.clone(),
        };
        let vector = match iter.next() {
            None => panic!("Every command requires a vector"),
            Some(y) => arg_to_vector(y.clone()),
        };
        let command = match command_name.as_slice() {
            "rotate" => Box::new(RotateOperation { v: vector }),
            _ => panic!("Unknown command: {}", command_name)
        };
        commands.push( command );
    }

    // Engine
    let mut it = commands.iter();
    let mut changed_mesh = mesh;
    loop {
        match it.next() {
            Some(command) => {
                changed_mesh = command.apply(changed_mesh);
            }
            None => { break }
        }
    }

    if export_to_povray {
        POV::export_to_pov(&input_file_copy, changed_mesh);
    } else if export_to_amf {
        AmfFile::write(&changed_mesh, input_file_copy);
    } else if export_to_console {
        //file.println_debug();
        println!("Mesh: {:?}", &changed_mesh);
    };

}

// Command pattern
trait MeshOperation {
    fn apply(&self, mesh: Mesh) -> Mesh;
}

pub struct RotateOperation {
    v: Vector3D,
}

impl MeshOperation for RotateOperation {
    fn apply(&self, mesh: Mesh) -> Mesh {
        let rot = Vec3::new(self.v.x, self.v.y, self.v.z);

        let v3s = mesh.vertices.iter()
            .map(|v| Vec3::new(v.x, v.y, v.z) )
            .map(|v3| rot.rotate(&v3))
            .map(|v3| Vector3D {x: v3.x, y: v3.y, z: v3.z} )
            .collect();

        //println!("{:?}", v3s);
        return Mesh::new_from_parts(v3s, mesh.facets);
    }
}

fn arg_to_vector(arg: String) -> Vector3D {
    let parts: Vec<f32> = arg.split(',').filter_map(|s| s.parse::<f32>().ok() ).collect();
    if (parts.len() != 3) {
        panic!("Vector must have three elements: {}", arg)
    };
    Vector3D{x: parts[0], y: parts[1], z: parts[2]}
}

#[test]
fn converts_arg_to_vector() {
    let result = arg_to_vector("1,2,3".to_string());
    assert_eq!(result.x, 1.0);
    assert_eq!(result.y, 2.0);
    assert_eq!(result.z, 3.0);
}

#[test]
fn able_to_rotate() {
    let a = Vec3::new(1.0, 1.0, 1.0);
    let c = Vec3::new(1.0, 1.0, 1.0);
    let d = a.rotate(&c);

    assert_eq!(a.as_array(), d.as_array());
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options] [operation vector]", program);
    print!("{}", opts.usage(brief.as_slice()));
}
<commit_msg>Fill in stubs for translate and scale.<commit_after>#![feature(env,old_io,old_path,os)]

extern crate mesh;
extern crate getopts;
extern crate nalgebra;

use std::old_io::BufferedReader;
use std::old_io::fs::File;
use mesh::StlFile;
use mesh::AmfFile;
use mesh::POV;
use mesh::Mesh;
use mesh::Vector3D;
use getopts::Options;
use std::os;
use nalgebra::*;

fn main() {
    let args: Vec<String> = os::args();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optopt("i", "input", "File name to process", "FILE");
    opts.optflag("p", "povray", "Export the model into POV-Ray format");
    opts.optflag("a", "amf", "Export the model into AMF format");
    opts.optflag("v", "view", "Print the model to the console");
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(args.tail()) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };

    if matches.opt_present("h") {
        print_usage(program.as_slice(), opts);
        return;
    };

    let export_to_povray = matches.opt_present("p");
    let export_to_amf = matches.opt_present("a");
    let export_to_console = matches.opt_present("v");

    let input_file = match matches.opt_str("i") {
        Some(x) => x,
        None => panic!("No input file"),
    };

    let input_file_copy = input_file.clone();

    let meshfile = File::open(&Path::new(input_file));

    let file = match StlFile::read(&mut BufferedReader::new(meshfile)) {
        Ok(f) => f,
        Err(e) => { println!("STL file error: {}", e); return; }
    };

    let mesh = file.as_mesh();

    // Process free as commands
    let mut commands: Vec<Box<MeshOperation>> = Vec::new();
    let mut iter = matches.free.iter();
    loop {
        let command_name = match iter.next() {
            None => break, // empty
            Some(x) => x.clone(),
        };
        let vector = match iter.next() {
            None => panic!("Every command requires a vector"),
            Some(y) => arg_to_vector(y.clone()),
        };
        let command:Box<MeshOperation> = match command_name.as_slice() {
            "rotate" => Box::new(RotateOperation { v: vector }),
            "scale" => Box::new(ScaleOperation { v: vector }),
            "translate" => Box::new(TranslateOperation { v: vector }),
            _ => panic!("Unknown command: {}", command_name)
        };
        commands.push( command );
    }

    // Engine
    let mut it = commands.iter();
    let mut changed_mesh = mesh;
    loop {
        match it.next() {
            Some(command) => {
                changed_mesh = command.apply(changed_mesh);
            }
            None => { break }
        }
    }

    if export_to_povray {
        POV::export_to_pov(&input_file_copy, changed_mesh);
    } else if export_to_amf {
        AmfFile::write(&changed_mesh, input_file_copy);
    } else if export_to_console {
        //file.println_debug();
        println!("Mesh: {:?}", &changed_mesh);
    };

}

// Command pattern
trait MeshOperation {
    fn apply(&self, mesh: Mesh) -> Mesh;
}

pub struct RotateOperation {
    v: Vector3D,
}
pub struct ScaleOperation {
    v: Vector3D,
}
pub struct TranslateOperation {
    v: Vector3D,
}

impl MeshOperation for RotateOperation {
    fn apply(&self, mesh: Mesh) -> Mesh {
        let rot = Vec3::new(self.v.x, self.v.y, self.v.z);

        let v3s = mesh.vertices.iter()
            .map(|v| Vec3::new(v.x, v.y, v.z) )
            .map(|v3| rot.rotate(&v3))
            .map(|v3| Vector3D {x: v3.x, y: v3.y, z: v3.z} )
            .collect();

        //println!("{:?}", v3s);
        return Mesh::new_from_parts(v3s, mesh.facets);
    }
}
impl MeshOperation for ScaleOperation {
    fn apply(&self, mesh: Mesh) -> Mesh {
        let rot = Vec3::new(self.v.x, self.v.y, self.v.z);

        let v3s = mesh.vertices.iter()
        .map(|v| Vec3::new(v.x, v.y, v.z) )
        .map(|v3| rot.transform(&v3))
        .map(|v3| Vector3D {x: v3.x, y: v3.y, z: v3.z} )
        .collect();

        //println!("{:?}", v3s);
        return Mesh::new_from_parts(v3s, mesh.facets);
    }
}

impl MeshOperation for TranslateOperation {
    fn apply(&self, mesh: Mesh) -> Mesh {
        let rot = Vec3::new(self.v.x, self.v.y, self.v.z);

        let v3s = mesh.vertices.iter()
        .map(|v| Vec3::new(v.x, v.y, v.z) )
        .map(|v3| rot.transform(&v3))
        .map(|v3| Vector3D {x: v3.x, y: v3.y, z: v3.z} )
        .collect();

        //println!("{:?}", v3s);
        return Mesh::new_from_parts(v3s, mesh.facets);
    }
}

fn arg_to_vector(arg: String) -> Vector3D {
    let parts: Vec<f32> = arg.split(',').filter_map(|s| s.parse::<f32>().ok() ).collect();
    if (parts.len() != 3) {
        panic!("Vector must have three elements: {}", arg)
    };
    Vector3D{x: parts[0], y: parts[1], z: parts[2]}
}

#[test]
fn converts_arg_to_vector() {
    let result = arg_to_vector("1,2,3".to_string());
    assert_eq!(result.x, 1.0);
    assert_eq!(result.y, 2.0);
    assert_eq!(result.z, 3.0);
}

#[test]
fn able_to_rotate() {
    let a = Vec3::new(1.0, 1.0, 1.0);
    let c = Vec3::new(1.0, 1.0, 1.0);
    let d = a.rotate(&c);

    assert_eq!(a.as_array(), d.as_array());
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options] [operation vector]", program);
    print!("{}", opts.usage(brief.as_slice()));
}
<|endoftext|>


<commit_before>extern crate rgmk;
extern crate clap;

use clap::{App, SubCommand, AppSettings};
use std::io::{self, stdin, stdout, stderr, BufReader};
use std::io::prelude::*;
use rgmk::GameData;
use std::path::Path;

fn main() {
    std::process::exit(run());
}

fn run() -> i32 {
    let strings_subcommand = SubCommand::with_name("strings")
                                 .about("Manipulate strings")
                                 .setting(AppSettings::SubcommandRequired)
                                 .setting(AppSettings::ArgRequiredElseHelp)
                                 .subcommand(SubCommand::with_name("dump")
                                                 .about("Dump strings.")
                                                 .args_from_usage("[OUTPUT_FILE] 'The file to \
                                                                   write the strings to. By \
                                                                   default, standard output.'"))
                                 .subcommand(SubCommand::with_name("repack")
                                                 .about("Repack strings")
                                                 .args_from_usage("[INPUT_FILE] 'The file \
                                                                   containing the strings to \
                                                                   repack. By default, standard \
                                                                   input.'"));
    let textures_subcommand = SubCommand::with_name("textures")
                                  .about("Manipulate textures")
                                  .setting(AppSettings::SubcommandRequired)
                                  .subcommand(SubCommand::with_name("dump").about("Dump textures"))
                                  .subcommand(SubCommand::with_name("repack")
                                                  .about("Repack textures"));
    let matches = App::new("gmktool")
                      .setting(AppSettings::SubcommandRequired)
                      .version(env!("CARGO_PKG_VERSION"))
                      .about("Tool for manipulating Game Maker Stdudio data files")
                      .args_from_usage("-b --backup=[BACKUP_FILE] 'Create a backup. By default, \
                                        it's DATA_FILE.bk'
                                    \
                                        <DATA_FILE> 'The game maker data file to operate on'")
                      .subcommand(strings_subcommand)
                      .subcommand(textures_subcommand)
                      .get_matches();
    let data_file_path = matches.value_of("DATA_FILE").unwrap();
    let backup = matches.is_present("backup");
    let backup_path = format!("{}.bk", data_file_path);
    let backup_path = matches.value_of("BACKUP_FILE").unwrap_or(&backup_path);
    let mut game_data = match GameData::from_file(data_file_path) {
        Ok(g) => g,
        Err(e) => {
            writeln!(stderr(),
                     "Failed to load game data for {:?}: {}",
                     data_file_path,
                     e)
                .unwrap();
            return 1;
        }
    };
    if let Some(matches) = matches.subcommand_matches("strings") {
        if let Some(matches) = matches.subcommand_matches("dump") {
            match matches.value_of("OUTPUT_FILE") {
                Some(path) => {
                    let mut file = match std::fs::File::create(path) {
                        Ok(f) => f,
                        Err(e) => {
                            writeln!(stderr(), "Failed to create output file: {}", e).unwrap();
                            return 1;
                        }
                    };
                    if let Err(e) = dump_strings(&game_data, &mut file) {
                        writeln!(stderr(), "Failed to dump strings: {}", e).unwrap();
                    }
                }
                None => {
                    let stdout = stdout();
                    let mut lock = stdout.lock();
                    if let Err(e) = dump_strings(&game_data, &mut lock) {
                        writeln!(stderr(), "Failed to dump strings: {}", e).unwrap();
                    }
                }
            }
        } else if let Some(matches) = matches.subcommand_matches("repack") {
            if backup {
                if let Err(e) = std::fs::copy(data_file_path, backup_path) {
                    writeln!(stderr(), "Failed to create backup: {}", e).unwrap();
                }
            }
            match matches.value_of("INPUT_FILE") {
                Some(path) => {
                    let file = match std::fs::File::open(path) {
                        Ok(f) => f,
                        Err(e) => {
                            writeln!(stderr(), "Failed to open input file: {}", e).unwrap();
                            return 1;
                        }
                    };
                    if let Err(e) = repack_strings(&mut game_data,
                                                   &mut BufReader::new(file),
                                                   data_file_path) {
                        writeln!(stderr(), "Failed to repack strings: {}", e).unwrap();
                    }
                }
                None => {
                    if let Err(e) = repack_strings(&mut game_data,
                                                   &mut BufReader::new(stdin()),
                                                   data_file_path) {
                        writeln!(stderr(), "Failed to repack strings: {}", e).unwrap();
                    }
                }
            }
        }
    } else if let Some(matches) = matches.subcommand_matches("textures") {
        if let Some(_) = matches.subcommand_matches("dump") {
            if let Err(e) = dump_textures(&game_data) {
                writeln!(stderr(), "Failed to dump textures: {}", e).unwrap();
                return 1;
            }
        } else if let Some(_) = matches.subcommand_matches("repack") {
            if let Err(e) = repack_textures(&mut game_data, data_file_path) {
                writeln!(stderr(), "Failed to repack textures: {}", e).unwrap();
            }
        }
    }
    0
}

fn dump_strings<W: Write>(game_data: &GameData, writer: &mut W) -> io::Result<()> {
    for s in &game_data.strings.strings {
        try!(writeln!(writer, "{}", s));
    }
    Ok(())
}

fn repack_strings<R: BufRead, P: AsRef<Path>>(game_data: &mut GameData,
                                              reader: &mut R,
                                              path: P)
                                              -> io::Result<()> {
    for (s, l) in game_data.strings.strings.iter_mut().zip(reader.lines()) {
        *s = try!(l);
    }
    game_data.save_to_file(path)
}

fn dump_textures(game_data: &GameData) -> io::Result<()> {
    for (i, t) in game_data.textures.textures.iter().enumerate() {
        let path = format!("{}.png", i);
        let mut f = try!(std::fs::File::create(path));
        try!(f.write_all(&t.png_data));
    }
    Ok(())
}

fn repack_textures<P: AsRef<Path>>(game_data: &mut GameData, path: P) -> io::Result<()> {
    for (i, t) in game_data.textures.textures.iter_mut().enumerate() {
        let path = format!("{}.png", i);
        let mut f = try!(std::fs::File::open(path));
        let mut png_data = Vec::new();
        try!(f.read_to_end(&mut png_data));
        (*t).png_data = png_data;
    }
    game_data.save_to_file(path)
}
<commit_msg>Print help if no subcommand was provided<commit_after>extern crate rgmk;
extern crate clap;

use clap::{App, SubCommand, AppSettings};
use std::io::{self, stdin, stdout, stderr, BufReader};
use std::io::prelude::*;
use rgmk::GameData;
use std::path::Path;

fn main() {
    std::process::exit(run());
}

fn run() -> i32 {
    let strings_subcommand = SubCommand::with_name("strings")
                                 .about("Manipulate strings")
                                 .setting(AppSettings::SubcommandRequiredElseHelp)
                                 .setting(AppSettings::ArgRequiredElseHelp)
                                 .subcommand(SubCommand::with_name("dump")
                                                 .about("Dump strings.")
                                                 .args_from_usage("[OUTPUT_FILE] 'The file to \
                                                                   write the strings to. By \
                                                                   default, standard output.'"))
                                 .subcommand(SubCommand::with_name("repack")
                                                 .about("Repack strings")
                                                 .args_from_usage("[INPUT_FILE] 'The file \
                                                                   containing the strings to \
                                                                   repack. By default, standard \
                                                                   input.'"));
    let textures_subcommand = SubCommand::with_name("textures")
                                  .about("Manipulate textures")
                                  .setting(AppSettings::SubcommandRequiredElseHelp)
                                  .subcommand(SubCommand::with_name("dump").about("Dump textures"))
                                  .subcommand(SubCommand::with_name("repack")
                                                  .about("Repack textures"));
    let matches = App::new("gmktool")
                      .setting(AppSettings::SubcommandRequiredElseHelp)
                      .version(env!("CARGO_PKG_VERSION"))
                      .about("Tool for manipulating Game Maker Stdudio data files")
                      .args_from_usage("-b --backup=[BACKUP_FILE] 'Create a backup. By default, \
                                        it's DATA_FILE.bk'
                                    \
                                        <DATA_FILE> 'The game maker data file to operate on'")
                      .subcommand(strings_subcommand)
                      .subcommand(textures_subcommand)
                      .get_matches();
    let data_file_path = matches.value_of("DATA_FILE").unwrap();
    let backup = matches.is_present("backup");
    let backup_path = format!("{}.bk", data_file_path);
    let backup_path = matches.value_of("BACKUP_FILE").unwrap_or(&backup_path);
    let mut game_data = match GameData::from_file(data_file_path) {
        Ok(g) => g,
        Err(e) => {
            writeln!(stderr(),
                     "Failed to load game data for {:?}: {}",
                     data_file_path,
                     e)
                .unwrap();
            return 1;
        }
    };
    if let Some(matches) = matches.subcommand_matches("strings") {
        if let Some(matches) = matches.subcommand_matches("dump") {
            match matches.value_of("OUTPUT_FILE") {
                Some(path) => {
                    let mut file = match std::fs::File::create(path) {
                        Ok(f) => f,
                        Err(e) => {
                            writeln!(stderr(), "Failed to create output file: {}", e).unwrap();
                            return 1;
                        }
                    };
                    if let Err(e) = dump_strings(&game_data, &mut file) {
                        writeln!(stderr(), "Failed to dump strings: {}", e).unwrap();
                    }
                }
                None => {
                    let stdout = stdout();
                    let mut lock = stdout.lock();
                    if let Err(e) = dump_strings(&game_data, &mut lock) {
                        writeln!(stderr(), "Failed to dump strings: {}", e).unwrap();
                    }
                }
            }
        } else if let Some(matches) = matches.subcommand_matches("repack") {
            if backup {
                if let Err(e) = std::fs::copy(data_file_path, backup_path) {
                    writeln!(stderr(), "Failed to create backup: {}", e).unwrap();
                }
            }
            match matches.value_of("INPUT_FILE") {
                Some(path) => {
                    let file = match std::fs::File::open(path) {
                        Ok(f) => f,
                        Err(e) => {
                            writeln!(stderr(), "Failed to open input file: {}", e).unwrap();
                            return 1;
                        }
                    };
                    if let Err(e) = repack_strings(&mut game_data,
                                                   &mut BufReader::new(file),
                                                   data_file_path) {
                        writeln!(stderr(), "Failed to repack strings: {}", e).unwrap();
                    }
                }
                None => {
                    if let Err(e) = repack_strings(&mut game_data,
                                                   &mut BufReader::new(stdin()),
                                                   data_file_path) {
                        writeln!(stderr(), "Failed to repack strings: {}", e).unwrap();
                    }
                }
            }
        }
    } else if let Some(matches) = matches.subcommand_matches("textures") {
        if let Some(_) = matches.subcommand_matches("dump") {
            if let Err(e) = dump_textures(&game_data) {
                writeln!(stderr(), "Failed to dump textures: {}", e).unwrap();
                return 1;
            }
        } else if let Some(_) = matches.subcommand_matches("repack") {
            if let Err(e) = repack_textures(&mut game_data, data_file_path) {
                writeln!(stderr(), "Failed to repack textures: {}", e).unwrap();
            }
        }
    }
    0
}

fn dump_strings<W: Write>(game_data: &GameData, writer: &mut W) -> io::Result<()> {
    for s in &game_data.strings.strings {
        try!(writeln!(writer, "{}", s));
    }
    Ok(())
}

fn repack_strings<R: BufRead, P: AsRef<Path>>(game_data: &mut GameData,
                                              reader: &mut R,
                                              path: P)
                                              -> io::Result<()> {
    for (s, l) in game_data.strings.strings.iter_mut().zip(reader.lines()) {
        *s = try!(l);
    }
    game_data.save_to_file(path)
}

fn dump_textures(game_data: &GameData) -> io::Result<()> {
    for (i, t) in game_data.textures.textures.iter().enumerate() {
        let path = format!("{}.png", i);
        let mut f = try!(std::fs::File::create(path));
        try!(f.write_all(&t.png_data));
    }
    Ok(())
}

fn repack_textures<P: AsRef<Path>>(game_data: &mut GameData, path: P) -> io::Result<()> {
    for (i, t) in game_data.textures.textures.iter_mut().enumerate() {
        let path = format!("{}.png", i);
        let mut f = try!(std::fs::File::open(path));
        let mut png_data = Vec::new();
        try!(f.read_to_end(&mut png_data));
        (*t).png_data = png_data;
    }
    game_data.save_to_file(path)
}
<|endoftext|>