<commit_before>extern crate libc;
#[macro_use]
extern crate log;
extern crate env_logger as logger;
use log::LogLevel;
use std::io::prelude::*;
use std::str;
use std::char;
use std::ptr;
use std::path::Path;
use std::fs;
use std::fs::File;
use std::ffi::CStr;
use std::ffi::CString;

enum spsps_loc_ {}
enum spsps_errno {}

/*
#[repr(C)]
struct Loc{
	name: *const libc::c_char,
	line: u32,
	column: u32,
}
*/
//This is for the opaque C pointer
enum spsps_parser_ {}
//this will be the safe abstraction
#[derive(Debug)]
struct Parser{
	_ptr: *mut spsps_parser_,
	_fd: *mut libc::FILE
}

#[derive(Debug)]
struct Loc{
	ptr: *mut spsps_loc_
}

#[link(name = "spsps")]
extern{
	//This returns an owned Parser
	fn spsps_new(name: *const libc::c_char, stream: *mut libc::FILE) -> *mut spsps_parser_;
	fn spsps_free(parser: *mut spsps_parser_);
	//This returns an owned C string.
	fn spsps_loc_to_string(loc: *mut spsps_loc_) -> *mut libc::c_char;
	//This returns a borrowed string
	fn spsps_printchar(xch: libc::c_char) -> *mut libc::c_char;
	fn spsps_consume(parser: *mut spsps_parser_) -> libc::c_char;
	fn spsps_consume_n(parser: *mut spsps_parser_, n: libc::size_t);
	fn spsps_consume_whitespace(parser: *mut spsps_parser_);
	//Not sure what return type to use for bool
	fn spsps_eof(parser: *mut spsps_parser_) -> libc::c_int;
	//This returns an owned Loc
	fn spsps_loc(parser: *mut spsps_parser_) -> *mut spsps_loc_;
	fn spsps_peek(parser: *mut spsps_parser_) -> libc::c_char;
	fn spsps_peek_n(parser: *mut spsps_parser_, n: libc::size_t) -> *mut libc::c_char;
	fn spsps_peek_str(parser: *mut spsps_parser_, next: *const libc::c_char) -> libc::c_int;
	fn spsps_peek_and_consume(parser: *mut spsps_parser_, next: *const libc::c_char) -> libc::c_int;
}

impl Parser{
	fn from_file(name: Option<&str>, path: &Path) -> Parser {
		unsafe{
			let c_path = CString::new(path.to_str().unwrap()).unwrap().as_ptr();
			debug!("from_file path: {:?}", CString::new(path.to_str().unwrap()).unwrap());
			let fd = libc::funcs::c95::stdio::fopen(c_path,  CString::new("r").unwrap().as_ptr());
			if fd.is_null() {
				panic!("Unable to open file to parse.");
			}
			match name{
			    Some(n) => Parser{
				    	_ptr: spsps_new(CString::new(n).unwrap().as_ptr(), fd),
				    	_fd: fd
			    	},
			    None => Parser{
				    	_ptr: spsps_new(ptr::null(), fd),
				    	_fd: fd
			    	}
			}
		 }
	}

	fn consume(&self) -> String {
		unsafe {
			char::from_u32(spsps_consume(self._ptr) as u32).unwrap().to_string()
		}
	}

	fn consume_n(&self, n: usize){
		unsafe { spsps_consume_n(self._ptr, n as libc::size_t); }
	}

	fn consume_whitespace(&self){
		unsafe { spsps_consume_whitespace(self._ptr); }
	}

	fn eof(&self) -> bool{
		unsafe { spsps_eof(self._ptr) as usize != 0 }
	}

	fn get_loc(&self) -> Loc {
		unsafe{
			Loc { ptr: spsps_loc(self._ptr) }
		}
	}

	fn peek(&self) -> String{
		let c_char = unsafe { spsps_peek(self._ptr) };
		char::from_u32(c_char as u32).unwrap().to_string()
	}

	fn peek_n(&self, n: usize) -> String{
		let cstr = unsafe{ spsps_peek_n(self._ptr, n as libc::size_t) };
		let safe_cstr = unsafe { CStr::from_ptr(cstr) };
		let retval = str::from_utf8(safe_cstr.to_bytes()).unwrap_or("").to_owned();
		unsafe { libc::free(safe_cstr.as_ptr() as *mut libc::c_void); }
		return retval;
	}

	fn peek_str(&self, needle: &str) -> bool {
		unsafe { spsps_peek_str(self._ptr, CString::new(needle).unwrap().as_ptr()) != 0 }
	}

	fn peek_str_and_consume(&self, needle: &str) -> bool {
		unsafe { spsps_peek_and_consume(self._ptr, CString::new(needle).unwrap().as_ptr()) != 0 }
	}
}

impl Drop for Parser{
	fn drop(&mut self) {
		unsafe{
			libc::fclose(self._fd);
			spsps_free(self._ptr);
		}
	}
}

impl Loc{
	fn to_string(&self) -> String{
		let tmp = unsafe { CStr::from_ptr(spsps_loc_to_string(self.ptr)) };
		let retval = str::from_utf8(tmp.to_bytes()).unwrap_or("").to_owned();
		unsafe {libc::free(tmp.as_ptr() as *mut libc::c_void);}
		retval
	}
}

impl Drop for Loc{
	fn drop(&mut self) {
		unsafe{ libc::free(self.ptr as *mut libc::c_void); }
	}
}

fn test_parser() -> Parser {
	let mut f = File::create("./foo.txt").unwrap();
	f.write_all(b"This is a test.\n");
	f.sync_data();
	let test_path = Path::new("./foo.txt");
	Parser::from_file(Some("test"), test_path)
}

#[test]
fn test_from_file(){
	logger::init().unwrap();
	let p = test_parser();
	//fs::remove_file("foo.txt").unwrap();
	println!("{:?}", p);
}

#[test]
fn test_peek_n(){
	let p = test_parser();
	p.consume_whitespace();
	let first_chars = p.peek_n(3);
	println!("{:?}", first_chars);
	assert_eq!(first_chars, "Thi");
}

#[test]
fn test_peek(){
	let p = test_parser();
	p.consume_whitespace();
	let first_char = p.peek();
	println!("{:?}", first_char);
	assert_eq!(first_char, "T");
}

#[test]
fn test_consume(){
	let p = test_parser();
	p.consume_whitespace();
	let first_char = p.consume();
	println!("{:?}", first_char);
	assert_eq!(first_char, "T");
}

#[test]
fn test_loc_to_string(){
	let p = test_parser();
	let location = p.get_loc();
	let loc_string = location.to_string();
	println!("{}",loc_string);
	assert_eq!(loc_string, "test:1:1");
}

#[test]
fn test_peek_consume(){
	let parser = test_parser();
	parser.consume_whitespace();
	let p = parser.peek();
	let c = parser.consume();
	assert_eq!(p, c);
}

#[test]
fn test_zzz_cleanup()
{
	//fs::remove_file("foo.txt").unwrap();
}<commit_msg>Remove consume_whitespace() workararound for  upstream bugfix.<commit_after>extern crate libc;
#[macro_use]
extern crate log;
extern crate env_logger as logger;
use log::LogLevel;
use std::io::prelude::*;
use std::str;
use std::char;
use std::ptr;
use std::path::Path;
use std::fs;
use std::fs::File;
use std::ffi::CStr;
use std::ffi::CString;

enum spsps_loc_ {}
enum spsps_errno {}

/*
#[repr(C)]
struct Loc{
	name: *const libc::c_char,
	line: u32,
	column: u32,
}
*/
//This is for the opaque C pointer
enum spsps_parser_ {}
//this will be the safe abstraction
#[derive(Debug)]
struct Parser{
	_ptr: *mut spsps_parser_,
	_fd: *mut libc::FILE
}

#[derive(Debug)]
struct Loc{
	ptr: *mut spsps_loc_
}

#[link(name = "spsps")]
extern{
	//This returns an owned Parser
	fn spsps_new(name: *const libc::c_char, stream: *mut libc::FILE) -> *mut spsps_parser_;
	fn spsps_free(parser: *mut spsps_parser_);
	//This returns an owned C string.
	fn spsps_loc_to_string(loc: *mut spsps_loc_) -> *mut libc::c_char;
	//This returns a borrowed string
	fn spsps_printchar(xch: libc::c_char) -> *mut libc::c_char;
	fn spsps_consume(parser: *mut spsps_parser_) -> libc::c_char;
	fn spsps_consume_n(parser: *mut spsps_parser_, n: libc::size_t);
	fn spsps_consume_whitespace(parser: *mut spsps_parser_);
	//Not sure what return type to use for bool
	fn spsps_eof(parser: *mut spsps_parser_) -> libc::c_int;
	//This returns an owned Loc
	fn spsps_loc(parser: *mut spsps_parser_) -> *mut spsps_loc_;
	fn spsps_peek(parser: *mut spsps_parser_) -> libc::c_char;
	fn spsps_peek_n(parser: *mut spsps_parser_, n: libc::size_t) -> *mut libc::c_char;
	fn spsps_peek_str(parser: *mut spsps_parser_, next: *const libc::c_char) -> libc::c_int;
	fn spsps_peek_and_consume(parser: *mut spsps_parser_, next: *const libc::c_char) -> libc::c_int;
}

impl Parser{
	fn from_file(name: Option<&str>, path: &Path) -> Parser {
		unsafe{
			let c_path = CString::new(path.to_str().unwrap()).unwrap().as_ptr();
			debug!("from_file path: {:?}", CString::new(path.to_str().unwrap()).unwrap());
			let fd = libc::funcs::c95::stdio::fopen(c_path,  CString::new("r").unwrap().as_ptr());
			if fd.is_null() {
				panic!("Unable to open file to parse.");
			}
			match name{
			    Some(n) => Parser{
				    	_ptr: spsps_new(CString::new(n).unwrap().as_ptr(), fd),
				    	_fd: fd
			    	},
			    None => Parser{
				    	_ptr: spsps_new(ptr::null(), fd),
				    	_fd: fd
			    	}
			}
		 }
	}

	fn consume(&self) -> String {
		unsafe {
			char::from_u32(spsps_consume(self._ptr) as u32).unwrap().to_string()
		}
	}

	fn consume_n(&self, n: usize){
		unsafe { spsps_consume_n(self._ptr, n as libc::size_t); }
	}

	fn consume_whitespace(&self){
		unsafe { spsps_consume_whitespace(self._ptr); }
	}

	fn eof(&self) -> bool{
		unsafe { spsps_eof(self._ptr) as usize != 0 }
	}

	fn get_loc(&self) -> Loc {
		unsafe{
			Loc { ptr: spsps_loc(self._ptr) }
		}
	}

	fn peek(&self) -> String{
		let c_char = unsafe { spsps_peek(self._ptr) };
		char::from_u32(c_char as u32).unwrap().to_string()
	}

	fn peek_n(&self, n: usize) -> String{
		let cstr = unsafe{ spsps_peek_n(self._ptr, n as libc::size_t) };
		let safe_cstr = unsafe { CStr::from_ptr(cstr) };
		let retval = str::from_utf8(safe_cstr.to_bytes()).unwrap_or("").to_owned();
		unsafe { libc::free(safe_cstr.as_ptr() as *mut libc::c_void); }
		return retval;
	}

	fn peek_str(&self, needle: &str) -> bool {
		unsafe { spsps_peek_str(self._ptr, CString::new(needle).unwrap().as_ptr()) != 0 }
	}

	fn peek_str_and_consume(&self, needle: &str) -> bool {
		unsafe { spsps_peek_and_consume(self._ptr, CString::new(needle).unwrap().as_ptr()) != 0 }
	}
}

impl Drop for Parser{
	fn drop(&mut self) {
		unsafe{
			libc::fclose(self._fd);
			spsps_free(self._ptr);
		}
	}
}

impl Loc{
	fn to_string(&self) -> String{
		let tmp = unsafe { CStr::from_ptr(spsps_loc_to_string(self.ptr)) };
		let retval = str::from_utf8(tmp.to_bytes()).unwrap_or("").to_owned();
		unsafe {libc::free(tmp.as_ptr() as *mut libc::c_void);}
		retval
	}
}

impl Drop for Loc{
	fn drop(&mut self) {
		unsafe{ libc::free(self.ptr as *mut libc::c_void); }
	}
}

fn test_parser() -> Parser {
	let mut f = File::create("./foo.txt").unwrap();
	f.write_all(b"This is a test.\n");
	f.sync_data();
	let test_path = Path::new("./foo.txt");
	Parser::from_file(Some("test"), test_path)
}

#[test]
fn test_from_file(){
	logger::init().unwrap();
	let p = test_parser();
	//fs::remove_file("foo.txt").unwrap();
	println!("{:?}", p);
}

#[test]
fn test_peek_n(){
	let p = test_parser();
	let first_chars = p.peek_n(3);
	println!("{:?}", first_chars);
	assert_eq!(first_chars, "Thi");
}

#[test]
fn test_peek(){
	let p = test_parser();
	let first_char = p.peek();
	println!("{:?}", first_char);
	assert_eq!(first_char, "T");
}

#[test]
fn test_consume(){
	let p = test_parser();
	let first_char = p.consume();
	println!("{:?}", first_char);
	assert_eq!(first_char, "T");
}

#[test]
fn test_loc_to_string(){
	let p = test_parser();
	let location = p.get_loc();
	let loc_string = location.to_string();
	println!("{}",loc_string);
	assert_eq!(loc_string, "test:1:1");
}

#[test]
fn test_peek_consume(){
	let parser = test_parser();
	let p = parser.peek();
	let c = parser.consume();
	assert_eq!(p, c);
}

#[test]
fn test_zzz_cleanup()
{
	//fs::remove_file("foo.txt").unwrap();
}<|endoftext|>


<commit_before>#![feature(proc_macro)]
#![recursion_limit = "1024"]

#[macro_use] extern crate log;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate error_chain;
extern crate cargo;
extern crate git2;
extern crate serde_json;
extern crate clap;
extern crate toml;

mod errors;

use std::env;
use std::path::{Path, PathBuf};
use std::fs::{DirBuilder, File, OpenOptions, self};
use std::collections::HashMap;
use std::io::{Read, Write};

use cargo::util;
use git2::Repository;
use git2::Config as GitConfig;
use clap::{App, Arg, ArgSettings};

use errors::*;

const DEFAULT_INDEX: &'static str = "https://github.com/rusttemplates/templates";

fn ensure_exists<P: AsRef<Path>>(p: P) -> Result<()> {
        let p = p.as_ref();
        let _ = DirBuilder::new().recursive(true).create(p)?;
        Ok(())
}

pub struct Config {
    pub index: String,
    pub index_path: PathBuf,
    pub templates_path: PathBuf,
    pub resolved_index_path: Option<PathBuf>,
}

impl Config {
    fn new() -> Result<Config> {
        let cargo_config = util::Config::default()?;
        let index = cargo_config.get_string("template.registry.index")?;
        let index = match index {
            None => DEFAULT_INDEX.to_string(),
            Some(val) => {
                val.val.to_string()
            },
        };

        let config_dir = Path::new(&env::var("CARGO_HOME")?).join("cargo-template");
        ensure_exists(&config_dir)?;

        let index_path = config_dir.join("index");
        ensure_exists(&index_path)?;

        let templates_path = config_dir.join("templates");
        ensure_exists(&templates_path)?;

        Ok(Config {
            index: index,
            index_path: index_path,
            templates_path: templates_path,
            resolved_index_path: None,
        })
    }
}

#[derive(Deserialize, Debug)]
struct IndexMember {
    name: String,
    loc: String,
}

#[derive(Deserialize, Debug)]
struct IndexTopLevel {
    index: Vec<IndexMember>,
}

impl IntoIterator for IndexTopLevel {
    type Item = (String, String);
    type IntoIter = IndexIter;

    fn into_iter(self) -> IndexIter {
        IndexIter {
            next: 0,
            inner: self,
        }
    }
}

struct IndexIter {
    next: usize,
    inner: IndexTopLevel,
}

impl Iterator for IndexIter {
    type Item = (String, String);

    fn next(&mut self) -> Option<Self::Item> {
        let el = self.inner.index.get(self.next).map(|el| (el.name.clone(), el.loc.clone()));
        self.next += 1;
        el
    }
}

struct IndexLoader<'a> {
    index: &'a Path,
}

impl<'a> IndexLoader<'a> {
    fn new(index: &'a Path) -> IndexLoader<'a> {
        IndexLoader {
            index: index,
        }
    }

    fn update_or_clone(&self, source: &str, frozen: bool) -> Result<PathBuf> {
        let repo = self.index.join(self.url_to_repo_dir(source));
        if repo.exists()  && repo.is_dir() {
            if !frozen {
                self.update_index(&repo)
            } else {
                Ok(repo)
            }
        } else {
            self.clone_index(source)
        }
    }

    fn update_index<P: AsRef<Path>>(&self, source: P) -> Result<PathBuf> {
        let source = source.as_ref();
        Ok(source.to_path_buf())
    }

    fn clone_index(&self, source: &str) -> Result<PathBuf> {
        // hacky and not-sufficient way to turn a url into a valid (single) directory name
        let p = self.index.join(self.url_to_repo_dir(source));
        let _ = Repository::clone(source, &p)?;
        debug!("cloned index at {:?}", &p);
        Ok(p)
    }

    fn url_to_repo_dir(&self, url: &str) -> String {
        url.replace(':', "_").replace('/', "_").replace(' ', "-")
    }
}

fn get_index(config: &mut Config, frozen: bool) -> Result<HashMap<String, String>> {
    let i = IndexLoader::new(&config.index_path);
    if let Ok(p) = i.update_or_clone(&config.index, frozen) {
        config.resolved_index_path = Some(p);
    }
    let index_file = match config.resolved_index_path {
        Some(ref p) => p.join("index.json"),
        None => {
            error!("Could not find an index");
            return Err(ErrorKind::GenericError.into());
        }
    };
    debug!("looking for index file {:?}", index_file);
    let index_file = File::open(index_file)?;
    let index_members = serde_json::from_reader::<File, IndexTopLevel>(index_file)?;
    let index_members: HashMap<String, String> = index_members.into_iter().collect();
    Ok(index_members)
}

fn get_template<P: AsRef<Path>>(name: &str, url: &str, templates_dir: P, frozen: bool) -> Result<PathBuf> {
    let templates_dir = templates_dir.as_ref();
    let location = templates_dir.join(name);
    if !location.exists() {
        if frozen {
            return Err(ErrorKind::TemplateNotFound(name.into()).into())
        }
        let _ = Repository::clone(url, &location);
    }

    Ok(location)
}

fn copy_dir<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> {
    let from = from.as_ref();
    let to = to.as_ref();

    debug!("copy_dir({}, {})", from.to_str().unwrap(), to.to_str().unwrap());

    if !from.exists() || !from.is_dir() {
        return Err(ErrorKind::SourceDoesNotExist(from.to_string_lossy().into_owned()).into());
    }
    ensure_exists(to)?;

    for entry in fs::read_dir(from)? {
        let entry = entry?;
        let file_name = entry.file_name();
        let lossy = file_name.to_string_lossy();
        if lossy == ".git" {
            continue;
        }
        let path = entry.path();

        if path.is_dir() {
            let new_to = to.join(&file_name);
            ensure_exists(&new_to)?;
            debug!("from {} to {}", path.to_str().unwrap(), new_to.to_str().unwrap());
            copy_dir(path, new_to)?;
        } else if path.is_file() {
            let new_to = to.join(&file_name);
            debug!("copy {} to {}", path.to_str().unwrap(), new_to.to_str().unwrap());
            fs::copy(&path, &new_to)?;
        } else {
            error!("Oops, this isn't a directory or a file, I don't know how to handle this so I'm just gonna ignore it");
            error!("problem entry: {:?}", path.to_str());
        }
    }
    Ok(())
}

// Basically just a port of "get_environment_variable" from cargo/src/cargo/ops/cargo_new.rs
fn get_environment_variable(variables: &[&str]) -> Option<String> {
    variables.iter()
             .filter_map(|var| env::var(var).ok())
             .next()
}

// Basically just a port of "discover_author" from cargo/src/cargo/ops/cargo_new.rs
fn get_name_and_email() -> Result<(String, Option<String>)> {
    let git_config = GitConfig::open_default().ok();
    let git_config = git_config.as_ref();
    let name_variables = ["CARGO_NAME", "GIT_AUTHOR_NAME", "GIT_COMMITTER_NAME",
                          "USER", "USERNAME", "NAME"];
    let name = get_environment_variable(&name_variables[0..3])
                    .or_else(|| git_config.and_then(|g| g.get_string("user.name").ok()))
                    .or_else(|| get_environment_variable(&name_variables[3..]));
    let name = match name {
        Some(name) => name,
        None => {
            let username_var = if cfg!(windows) { "USERNAME" } else { "USER" };
            return Err(ErrorKind::UserError(username_var.into()).into());
        }
    };
    let email_variables = ["CARGO_EMAIL", "GIT_AUTHOR_EMAIL", "GIT_COMMITTER_EMAIL",
                           "EMAIL"];
    let email = get_environment_variable(&email_variables[0..3])
                    .or_else(|| git_config.and_then(|g| g.get_string("user.email").ok()))
                    .or_else(|| get_environment_variable(&email_variables[3..]));
    let name = name.trim().to_string();
    let email = email.map(|s| s.trim().to_string());

    Ok((name, email))
}

fn format_author(author_name: &str, author_email: &Option<String>) -> String {
    match *author_email {
        Some(ref email) => format!("{} <{}>", author_name, email),
        None => format!("{}", author_name),
    }
}

fn write_toml<P: AsRef<Path>>(file: P, val: toml::Value) -> Result<()> {
    let file = file.as_ref();
    let mut file = OpenOptions::new().read(true).write(true).open(file)?;
    let contents = format!("{}", val);
    write!(file, "{}", contents)?;
    Ok(())
}
fn edit_cargo_toml<P: AsRef<Path>>(file: P, project_name: &str, author_name: &str,
                                   author_email: &Option<String>) -> Result<()> {
    let file = file.as_ref();
    let mut contents = String::new();
    File::open(file)?.read_to_string(&mut contents)?;
    let contents = contents;
    let mut parser = toml::Parser::new(&contents);
    let mut value = match parser.parse() {
        Some(val) => val,
        None => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
    };
    match value.get_mut("package") {
        Some(&mut toml::Value::Table(ref mut t)) => {
            t.insert("name".into(), toml::Value::String(project_name.to_string()));
        },
        Some(_) => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
        None => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
    };

    match value.get_mut("package") {
        Some(&mut toml::Value::Table(ref mut t)) => {
            t.insert("authors".into(),
                     toml::Value::Array(
                         vec![toml::Value::String(format_author(author_name, author_email))]));
        },
        Some(_) => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
        None => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
    }

    write_toml(&file, toml::Value::Table(value))?;

    Ok(())
}
fn find_cargo_toml<P: AsRef<Path>>(project_dir: P, project_name: &str,
                                      author_name: &str, author_email: &Option<String>) -> Result<()> {
    let project_dir = project_dir.as_ref();
    for entry in fs::read_dir(project_dir)? {
        let entry = entry?;
        let path = entry.path();
        if path.is_file() && entry.file_name().to_string_lossy() == "Cargo.toml" {
            edit_cargo_toml(&path, project_name, author_name, author_email)?;
        }
    }
    Ok(())
}

fn cli() -> App<'static, 'static> {
    App::new("cargo-template")
        .about("initialize new cargo projects from a predefined template")
        .arg(Arg::with_name("frozen")
                .long("frozen")
                .help("Asserts that we shouldn't touch the network"))
        .arg(Arg::with_name("CARGO_ADDS_THIS")
                .set(ArgSettings::Hidden)
                .required(true)
                .index(1))
        .arg(Arg::with_name("TEMPLATE")
                .help("The template to use")
                .required(true)
                .index(2))
        .arg(Arg::with_name("NAME")
                .help("the project name")
                .required(true)
                .index(3))
}

pub fn main() -> Result<()> {
    let matches = cli().get_matches();
    let frozen = matches.is_present("frozen");
    let template = matches.value_of("TEMPLATE").unwrap(); // If we've gotten here, clap has verified that we have this
    let project_name = matches.value_of("NAME").unwrap();
    let cwd = env::current_dir()?;
    let project_dir = cwd.join(project_name);
    if project_dir.exists() {
        return Err(ErrorKind::ExistsError(project_dir.to_string_lossy().into_owned()).into());
    }
    debug!("template: {:?}", template);
    debug!("project name: {:?}", project_name);
    let mut config = Config::new()?;
    let metadata = fs::metadata(template);
    let from = if metadata.is_ok() && metadata.unwrap().is_dir() {
        debug!("found template on filesystem");
        Path::new(template).to_path_buf()
    } else {
        let index = get_index(&mut config, frozen)?;
        let location = match index.get(template) {
            Some(loc) => loc,
            None => return Err(ErrorKind::TemplateDoesNotExist(template.into()).into())
        };
        debug!("template url is {:?}", location);
        let from = match get_template(template, location, &config.templates_path, frozen) {
            Ok(loc) => loc,
            Err(e) => {
                error!("Error getting template: {}", e);
                return Err(e);
            }
        };
        from
    };
    debug!("creating project at {:?}", project_dir);
    copy_dir(&from, &project_dir)?;
    debug!("substituting name & author values");
    // open new Cargo.toml && change the name & author lines
    let (author_name, author_email) = get_name_and_email()?;
    debug!("using author info `({:?}, {:?})`", author_name, author_email);
    find_cargo_toml(&project_dir, &project_name, &author_name, &author_email)?;
    Ok(())
}<commit_msg>Set the usage string manually<commit_after>#![feature(proc_macro)]
#![recursion_limit = "1024"]

#[macro_use] extern crate log;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate error_chain;
#[macro_use] extern crate clap;
extern crate cargo;
extern crate git2;
extern crate serde_json;
extern crate toml;

mod errors;

use std::env;
use std::path::{Path, PathBuf};
use std::fs::{DirBuilder, File, OpenOptions, self};
use std::collections::HashMap;
use std::io::{Read, Write};

use cargo::util;
use git2::Repository;
use git2::Config as GitConfig;
use clap::{App, Arg, ArgSettings};

use errors::*;

const DEFAULT_INDEX: &'static str = "https://github.com/rusttemplates/templates";

fn ensure_exists<P: AsRef<Path>>(p: P) -> Result<()> {
        let p = p.as_ref();
        let _ = DirBuilder::new().recursive(true).create(p)?;
        Ok(())
}

pub struct Config {
    pub index: String,
    pub index_path: PathBuf,
    pub templates_path: PathBuf,
    pub resolved_index_path: Option<PathBuf>,
}

impl Config {
    fn new() -> Result<Config> {
        let cargo_config = util::Config::default()?;
        let index = cargo_config.get_string("template.registry.index")?;
        let index = match index {
            None => DEFAULT_INDEX.to_string(),
            Some(val) => {
                val.val.to_string()
            },
        };

        let config_dir = Path::new(&env::var("CARGO_HOME")?).join("cargo-template");
        ensure_exists(&config_dir)?;

        let index_path = config_dir.join("index");
        ensure_exists(&index_path)?;

        let templates_path = config_dir.join("templates");
        ensure_exists(&templates_path)?;

        Ok(Config {
            index: index,
            index_path: index_path,
            templates_path: templates_path,
            resolved_index_path: None,
        })
    }
}

#[derive(Deserialize, Debug)]
struct IndexMember {
    name: String,
    loc: String,
}

#[derive(Deserialize, Debug)]
struct IndexTopLevel {
    index: Vec<IndexMember>,
}

impl IntoIterator for IndexTopLevel {
    type Item = (String, String);
    type IntoIter = IndexIter;

    fn into_iter(self) -> IndexIter {
        IndexIter {
            next: 0,
            inner: self,
        }
    }
}

struct IndexIter {
    next: usize,
    inner: IndexTopLevel,
}

impl Iterator for IndexIter {
    type Item = (String, String);

    fn next(&mut self) -> Option<Self::Item> {
        let el = self.inner.index.get(self.next).map(|el| (el.name.clone(), el.loc.clone()));
        self.next += 1;
        el
    }
}

struct IndexLoader<'a> {
    index: &'a Path,
}

impl<'a> IndexLoader<'a> {
    fn new(index: &'a Path) -> IndexLoader<'a> {
        IndexLoader {
            index: index,
        }
    }

    fn update_or_clone(&self, source: &str, frozen: bool) -> Result<PathBuf> {
        let repo = self.index.join(self.url_to_repo_dir(source));
        if repo.exists()  && repo.is_dir() {
            if !frozen {
                self.update_index(&repo)
            } else {
                Ok(repo)
            }
        } else {
            self.clone_index(source)
        }
    }

    fn update_index<P: AsRef<Path>>(&self, source: P) -> Result<PathBuf> {
        let source = source.as_ref();
        Ok(source.to_path_buf())
    }

    fn clone_index(&self, source: &str) -> Result<PathBuf> {
        // hacky and not-sufficient way to turn a url into a valid (single) directory name
        let p = self.index.join(self.url_to_repo_dir(source));
        let _ = Repository::clone(source, &p)?;
        debug!("cloned index at {:?}", &p);
        Ok(p)
    }

    fn url_to_repo_dir(&self, url: &str) -> String {
        url.replace(':', "_").replace('/', "_").replace(' ', "-")
    }
}

fn get_index(config: &mut Config, frozen: bool) -> Result<HashMap<String, String>> {
    let i = IndexLoader::new(&config.index_path);
    if let Ok(p) = i.update_or_clone(&config.index, frozen) {
        config.resolved_index_path = Some(p);
    }
    let index_file = match config.resolved_index_path {
        Some(ref p) => p.join("index.json"),
        None => {
            error!("Could not find an index");
            return Err(ErrorKind::GenericError.into());
        }
    };
    debug!("looking for index file {:?}", index_file);
    let index_file = File::open(index_file)?;
    let index_members = serde_json::from_reader::<File, IndexTopLevel>(index_file)?;
    let index_members: HashMap<String, String> = index_members.into_iter().collect();
    Ok(index_members)
}

fn get_template<P: AsRef<Path>>(name: &str, url: &str, templates_dir: P, frozen: bool) -> Result<PathBuf> {
    let templates_dir = templates_dir.as_ref();
    let location = templates_dir.join(name);
    if !location.exists() {
        if frozen {
            return Err(ErrorKind::TemplateNotFound(name.into()).into())
        }
        let _ = Repository::clone(url, &location);
    }

    Ok(location)
}

fn copy_dir<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> {
    let from = from.as_ref();
    let to = to.as_ref();

    debug!("copy_dir({}, {})", from.to_str().unwrap(), to.to_str().unwrap());

    if !from.exists() || !from.is_dir() {
        return Err(ErrorKind::SourceDoesNotExist(from.to_string_lossy().into_owned()).into());
    }
    ensure_exists(to)?;

    for entry in fs::read_dir(from)? {
        let entry = entry?;
        let file_name = entry.file_name();
        let lossy = file_name.to_string_lossy();
        if lossy == ".git" {
            continue;
        }
        let path = entry.path();

        if path.is_dir() {
            let new_to = to.join(&file_name);
            ensure_exists(&new_to)?;
            debug!("from {} to {}", path.to_str().unwrap(), new_to.to_str().unwrap());
            copy_dir(path, new_to)?;
        } else if path.is_file() {
            let new_to = to.join(&file_name);
            debug!("copy {} to {}", path.to_str().unwrap(), new_to.to_str().unwrap());
            fs::copy(&path, &new_to)?;
        } else {
            error!("Oops, this isn't a directory or a file, I don't know how to handle this so I'm just gonna ignore it");
            error!("problem entry: {:?}", path.to_str());
        }
    }
    Ok(())
}

// Basically just a port of "get_environment_variable" from cargo/src/cargo/ops/cargo_new.rs
fn get_environment_variable(variables: &[&str]) -> Option<String> {
    variables.iter()
             .filter_map(|var| env::var(var).ok())
             .next()
}

// Basically just a port of "discover_author" from cargo/src/cargo/ops/cargo_new.rs
fn get_name_and_email() -> Result<(String, Option<String>)> {
    let git_config = GitConfig::open_default().ok();
    let git_config = git_config.as_ref();
    let name_variables = ["CARGO_NAME", "GIT_AUTHOR_NAME", "GIT_COMMITTER_NAME",
                          "USER", "USERNAME", "NAME"];
    let name = get_environment_variable(&name_variables[0..3])
                    .or_else(|| git_config.and_then(|g| g.get_string("user.name").ok()))
                    .or_else(|| get_environment_variable(&name_variables[3..]));
    let name = match name {
        Some(name) => name,
        None => {
            let username_var = if cfg!(windows) { "USERNAME" } else { "USER" };
            return Err(ErrorKind::UserError(username_var.into()).into());
        }
    };
    let email_variables = ["CARGO_EMAIL", "GIT_AUTHOR_EMAIL", "GIT_COMMITTER_EMAIL",
                           "EMAIL"];
    let email = get_environment_variable(&email_variables[0..3])
                    .or_else(|| git_config.and_then(|g| g.get_string("user.email").ok()))
                    .or_else(|| get_environment_variable(&email_variables[3..]));
    let name = name.trim().to_string();
    let email = email.map(|s| s.trim().to_string());

    Ok((name, email))
}

fn format_author(author_name: &str, author_email: &Option<String>) -> String {
    match *author_email {
        Some(ref email) => format!("{} <{}>", author_name, email),
        None => format!("{}", author_name),
    }
}

fn write_toml<P: AsRef<Path>>(file: P, val: toml::Value) -> Result<()> {
    let file = file.as_ref();
    let mut file = OpenOptions::new().read(true).write(true).open(file)?;
    let contents = format!("{}", val);
    write!(file, "{}", contents)?;
    Ok(())
}
fn edit_cargo_toml<P: AsRef<Path>>(file: P, project_name: &str, author_name: &str,
                                   author_email: &Option<String>) -> Result<()> {
    let file = file.as_ref();
    let mut contents = String::new();
    File::open(file)?.read_to_string(&mut contents)?;
    let contents = contents;
    let mut parser = toml::Parser::new(&contents);
    let mut value = match parser.parse() {
        Some(val) => val,
        None => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
    };
    match value.get_mut("package") {
        Some(&mut toml::Value::Table(ref mut t)) => {
            t.insert("name".into(), toml::Value::String(project_name.to_string()));
        },
        Some(_) => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
        None => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
    };

    match value.get_mut("package") {
        Some(&mut toml::Value::Table(ref mut t)) => {
            t.insert("authors".into(),
                     toml::Value::Array(
                         vec![toml::Value::String(format_author(author_name, author_email))]));
        },
        Some(_) => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
        None => return Err(ErrorKind::TomlParseError(file.to_string_lossy().into_owned()).into()),
    }

    write_toml(&file, toml::Value::Table(value))?;

    Ok(())
}
fn find_cargo_toml<P: AsRef<Path>>(project_dir: P, project_name: &str,
                                      author_name: &str, author_email: &Option<String>) -> Result<()> {
    let project_dir = project_dir.as_ref();
    for entry in fs::read_dir(project_dir)? {
        let entry = entry?;
        let path = entry.path();
        if path.is_file() && entry.file_name().to_string_lossy() == "Cargo.toml" {
            edit_cargo_toml(&path, project_name, author_name, author_email)?;
        }
    }
    Ok(())
}

fn cli() -> App<'static, 'static> {
    App::new("cargo-template")
        .author(crate_authors!())
        .version(crate_version!())
        .usage("cargo template [FLAGS] <TEMPLATE> <NAME>")
        .about("initialize new cargo projects from a predefined template")
        .arg(Arg::with_name("frozen")
                .long("frozen")
                .help("Asserts that we shouldn't touch the network"))
        .arg(Arg::with_name("CARGO_ADDS_THIS")
                .set(ArgSettings::Hidden)
                .required(true)
                .index(1))
        .arg(Arg::with_name("TEMPLATE")
                .help("The template to use")
                .required(true)
                .index(2))
        .arg(Arg::with_name("NAME")
                .help("the project name")
                .required(true)
                .index(3))
}

pub fn main() -> Result<()> {
    let matches = cli().get_matches();
    let frozen = matches.is_present("frozen");
    let template = matches.value_of("TEMPLATE").unwrap(); // If we've gotten here, clap has verified that we have this
    let project_name = matches.value_of("NAME").unwrap();
    let cwd = env::current_dir()?;
    let project_dir = cwd.join(project_name);
    if project_dir.exists() {
        return Err(ErrorKind::ExistsError(project_dir.to_string_lossy().into_owned()).into());
    }
    debug!("template: {:?}", template);
    debug!("project name: {:?}", project_name);
    let mut config = Config::new()?;
    let metadata = fs::metadata(template);
    let from = if metadata.is_ok() && metadata.unwrap().is_dir() {
        debug!("found template on filesystem");
        Path::new(template).to_path_buf()
    } else {
        let index = get_index(&mut config, frozen)?;
        let location = match index.get(template) {
            Some(loc) => loc,
            None => return Err(ErrorKind::TemplateDoesNotExist(template.into()).into())
        };
        debug!("template url is {:?}", location);
        let from = match get_template(template, location, &config.templates_path, frozen) {
            Ok(loc) => loc,
            Err(e) => {
                error!("Error getting template: {}", e);
                return Err(e);
            }
        };
        from
    };
    debug!("creating project at {:?}", project_dir);
    copy_dir(&from, &project_dir)?;
    debug!("substituting name & author values");
    // open new Cargo.toml && change the name & author lines
    let (author_name, author_email) = get_name_and_email()?;
    debug!("using author info `({:?}, {:?})`", author_name, author_email);
    find_cargo_toml(&project_dir, &project_name, &author_name, &author_email)?;
    debug!("adding project & author info to the Cargo.toml");
    Ok(())
}<|endoftext|>


<commit_before>//! Provides a procedural macro that allows a struct to be easily converted
//! to/from arrays and slices.
//!
//! The `StructArray` derive macro implements the necessary traits such that
//! the struct can be easily converted to/from arrays and slices. The macro
//! works for normal structs and tuple structs. The struct must have the
//! following properties:
//!
//!   * all the fields must be public (indicated with the `pub` keyword)
//!   * all the fields must have the same type
//!   * the struct must have at least one field
//!   * the struct must have the `#[repr(C)]` attribute
//!
//! # Example
//!
//! ```ignore
//! #[macro_use]
//! extern crate struct_array;
//!
//! /// Example struct array.
//! #[derive(Clone,Debug,PartialEq,StructArray)]
//! #[repr(C)]
//! struct Example {
//!     /// x member
//!     pub x: u32,
//!     /// y member
//!     pub y: u32,
//! }
//!
//! fn main() {
//!     // Deref as an array.
//!     {
//!         let example = Example { x: 42, y: 56 };
//!         let array: [u32; 2] = *example;
//!         assert_eq!(array, [42, 56]);
//!     }
//!
//!     // Deref as a slice (via derefing as an array).
//!     {
//!         let example = Example { x: 42, y: 56 };
//!         let slice: &[u32] = &*example;
//!         assert_eq!(slice, &[42, 56]);
//!     }
//!
//!     // Index (via derefing as an array).
//!     {
//!         let mut example = Example { x: 42, y: 56 };
//!         example[1] = 23;
//!         assert_eq!(example, Example { x: 42, y: 23 });
//!     }
//!
//!     // Convert into an array.
//!     {
//!         let example = Example { x: 42, y: 56 };
//!         let array: [u32; 2] = example.into();
//!         assert_eq!(array, [42, 56]);
//!     }
//!
//!     // Convert from an array to a struct.
//!     {
//!         let array = [42, 56];
//!         let example: Example = array.into();
//!         assert_eq!(example, Example { x: 42, y: 56 });
//!     }
//!
//!     // Convert from a slice to a struct reference.
//!     {
//!         let slice = &[42, 56][..];
//!         let example: &Example = slice.into();
//!         assert_eq!(example, &Example { x: 42, y: 56 });
//!     }
//! }
//!
//! ```
//!
//! # Trait implementations
//!
//! Deriving `StructArray` for a struct `Foo` causes it to implement:
//!
//! * `Deref<Target=[T; len]> for Foo`
//! * `DerefMut<Target=[T; len]> for Foo`
//! * `Into<[T; len] for Foo`
//! * `From<[T; len]> for Foo`
//! * `Into<&[T; len] for &Foo`
//! * `AsRef<[T; len] for Foo`
//! * `From<&[T; len] for &Foo`
//! * `AsRef<Foo> for [T; len]`
//! * `Into<&mut [T; len] for &mut Foo`
//! * `AsMut<[T; len] for Foo`
//! * `From<&mut [T; len] for &mut Foo`
//! * `AsMut<Foo> for [T; len]`
//! * `Into<&[T]> for &Foo`
//! * `AsRef<[T]> for Foo`
//! * `From<&[T]> for &Foo`
//! * `AsRef<Foo> for [T]`
//! * `Into<&mut [T]> for &mut Foo`
//! * `AsMut<[T]> for Foo`
//! * `From<&mut [T]> for &mut Foo`
//! * `AsMut<Foo> for [T]`
//!
//! Note that converting from a slice will panic if the `len()` of the slice
//! does not must match the `len` specified for the struct.

#![feature(proc_macro, proc_macro_lib)]

#![recursion_limit = "500"]

extern crate proc_macro;
use proc_macro::TokenStream;

extern crate syn;

#[macro_use]
extern crate quote;

/// Implements derive of `StructArray`.
///
/// This function is called by the Rust compiler when compiling code that uses
/// `#[derive(StructArray)]`.
#[proc_macro_derive(StructArray)]
pub fn derive_struct_array(input: TokenStream) -> TokenStream {
    let source = input.to_string();

    // Parse the string representation into a syntax tree
    let ast = syn::parse_macro_input(&source).unwrap();

    // Build the output
    let expanded = impl_struct_array(&ast);

    // Return the generated impl as a TokenStream
    expanded.parse().unwrap()
}

fn impl_struct_array(ast: &syn::MacroInput) -> quote::Tokens {
    let name = &ast.ident;
    let (field_type, field_count) = match ast.body {
        syn::Body::Struct(ref data) => {
            let field_type = &data.fields().first().expect(
                "#[derive(StructArray)] can only be used with structs that have at least one field"
            ).ty;
            for field in data.fields() {
                if field.vis != syn::Visibility::Public {
                    panic!("#[derive(StructArray)] can only used if all the fields in the struct are public")
                }
                if field.ty != *field_type {
                    panic!("#[derive(StructArray)] can only used with structs that have identical field types")
                }
            }
            (field_type, data.fields().len())
        },
        syn::Body::Enum(_) => panic!("#[derive(StructArray)] can only be used with structs"),
    };
    let repr_c = syn::MetaItem::List("repr".into(), vec![syn::NestedMetaItem::MetaItem(syn::MetaItem::Word("C".into()))]);
    if !ast.attrs.iter().any(|attr| attr.value == repr_c) {
        panic!("#[derive(StructArray)] can only be used with structs that are #[repr(C)]");
    }

    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
    quote! {
        impl #impl_generics ::std::ops::Deref for #name #ty_generics #where_clause {
            type Target = [#field_type; #field_count];

            fn deref(&self) -> &[#field_type; #field_count] {
                unsafe {
                    &*(self as *const #name as *const [#field_type; #field_count])
                }
            }
        }

        impl #impl_generics ::std::ops::DerefMut for #name #ty_generics #where_clause {
            fn deref_mut(&mut self) -> &mut [#field_type; #field_count] {
                unsafe {
                    &mut *(self as *mut #name as *mut [#field_type; #field_count])
                }
            }
        }

        impl #impl_generics Into<[#field_type; #field_count]> for #name #ty_generics #where_clause {
            fn into(self) -> [#field_type; #field_count] {
                unsafe {
                    ::std::mem::transmute(self)
                }
            }
        }

        impl #impl_generics From<[#field_type; #field_count]> for #name #ty_generics #where_clause {
            fn from(array: [#field_type; #field_count]) -> #name {
                unsafe {
                    ::std::mem::transmute(array)
                }
            }
        }

        impl<'a> #impl_generics Into<&'a [#field_type; #field_count]> for &'a #name #ty_generics #where_clause {
            fn into(self) -> &'a [#field_type; #field_count] {
                unsafe {
                    &*(self as *const #name as *const [#field_type; #field_count])
                }
            }
        }

        impl #impl_generics ::std::convert::AsRef<[#field_type; #field_count]> for #name #ty_generics #where_clause {
            fn as_ref(&self) -> &[#field_type; #field_count] {
                unsafe {
                    &*(self as *const #name as *const [#field_type; #field_count])
                }
            }
        }

        impl<'a> #impl_generics From<&'a [#field_type; #field_count]> for &'a #name #ty_generics #where_clause {
            fn from(array: &[#field_type; #field_count]) -> &#name {
                unsafe {
                    &*(array as *const [#field_type; #field_count] as *const #name)
                }
            }
        }

        impl #impl_generics ::std::convert::AsRef<#name> for [#field_type; #field_count] #ty_generics #where_clause {
            fn as_ref(&self) -> &#name {
                unsafe {
                    &*(self as *const [#field_type; #field_count] as *const #name)
                }
            }
        }

        impl<'a> #impl_generics Into<&'a mut [#field_type; #field_count]> for &'a mut #name #ty_generics #where_clause {
            fn into(self) -> &'a mut [#field_type; #field_count] {
                unsafe {
                    &mut *(self as *mut #name as *mut [#field_type; #field_count])
                }
            }
        }

        impl #impl_generics ::std::convert::AsMut<[#field_type; #field_count]> for #name #ty_generics #where_clause {
            fn as_mut(&mut self) -> &mut [#field_type; #field_count] {
                unsafe {
                    &mut *(self as *mut #name as *mut [#field_type; #field_count])
                }
            }
        }

        impl<'a> #impl_generics From<&'a mut [#field_type; #field_count]> for &'a mut #name #ty_generics #where_clause {
            fn from(array: &mut [#field_type; #field_count]) -> &mut #name {
                unsafe {
                    &mut *(array as *mut [#field_type; #field_count] as *mut #name)
                }
            }
        }

        impl #impl_generics ::std::convert::AsMut<#name> for [#field_type; #field_count] #ty_generics #where_clause {
            fn as_mut(&mut self) -> &mut #name {
                unsafe {
                    &mut *(self as *mut [#field_type; #field_count] as *mut #name)
                }
            }
        }

        impl<'a> #impl_generics Into<&'a [#field_type]> for &'a #name #ty_generics #where_clause {
            fn into(self) -> &'a [#field_type] {
                unsafe {
                    ::std::slice::from_raw_parts(self as *const #name as *const #field_type, #field_count)
                }
            }
        }

        impl #impl_generics ::std::convert::AsRef<[#field_type]> for #name #ty_generics #where_clause {
            fn as_ref(&self) -> &[#field_type] {
                unsafe {
                    ::std::slice::from_raw_parts(self as *const #name as *const #field_type, #field_count)
                }
            }
        }

        impl<'a> #impl_generics From<&'a [#field_type]> for &'a #name #ty_generics #where_clause {
            fn from(slice: &'a [#field_type]) -> &'a #name {
                assert!(slice.len() == #field_count);
                unsafe {
                    &*(slice.as_ptr() as *const #name)
                }
            }
        }

        impl #impl_generics ::std::convert::AsRef<#name> for [#field_type] #ty_generics #where_clause {
            fn as_ref(&self) -> &#name {
                assert!(self.len() == #field_count);
                unsafe {
                    &*(self.as_ptr() as *const #name)
                }
            }
        }

        impl<'a> #impl_generics Into<&'a mut [#field_type]> for &'a mut #name #ty_generics #where_clause {
            fn into(self) -> &'a mut [#field_type] {
                unsafe {
                    ::std::slice::from_raw_parts_mut(self as *mut #name as *mut #field_type, #field_count)
                }
            }
        }

        impl #impl_generics ::std::convert::AsMut<[#field_type]> for #name #ty_generics #where_clause {
            fn as_mut(&mut self) -> &mut [#field_type] {
                unsafe {
                    ::std::slice::from_raw_parts_mut(self as *mut #name as *mut #field_type, #field_count)
                }
            }
        }

        impl<'a> #impl_generics From<&'a mut [#field_type]> for &'a mut #name #ty_generics #where_clause {
            fn from(slice: &'a mut [#field_type]) -> &'a mut #name {
                assert!(slice.len() == #field_count);
                unsafe {
                    &mut *(slice.as_mut_ptr() as *mut #name)
                }
            }
        }

        impl #impl_generics ::std::convert::AsMut<#name> for [#field_type] #ty_generics #where_clause {
            fn as_mut(&mut self) -> &mut #name {
                assert!(self.len() == #field_count);
                unsafe {
                    &mut *(self.as_mut_ptr() as *mut #name)
                }
            }
        }
    }
}
<commit_msg>Change Into impls to equivalent From impls<commit_after>//! Provides a procedural macro that allows a struct to be easily converted
//! to/from arrays and slices.
//!
//! The `StructArray` derive macro implements the necessary traits such that
//! the struct can be easily converted to/from arrays and slices. The macro
//! works for normal structs and tuple structs. The struct must have the
//! following properties:
//!
//!   * all the fields must be public (indicated with the `pub` keyword)
//!   * all the fields must have the same type
//!   * the struct must have at least one field
//!   * the struct must have the `#[repr(C)]` attribute
//!
//! # Example
//!
//! ```ignore
//! #[macro_use]
//! extern crate struct_array;
//!
//! /// Example struct array.
//! #[derive(Clone,Debug,PartialEq,StructArray)]
//! #[repr(C)]
//! struct Example {
//!     /// x member
//!     pub x: u32,
//!     /// y member
//!     pub y: u32,
//! }
//!
//! fn main() {
//!     // Deref as an array.
//!     {
//!         let example = Example { x: 42, y: 56 };
//!         let array: [u32; 2] = *example;
//!         assert_eq!(array, [42, 56]);
//!     }
//!
//!     // Deref as a slice (via derefing as an array).
//!     {
//!         let example = Example { x: 42, y: 56 };
//!         let slice: &[u32] = &*example;
//!         assert_eq!(slice, &[42, 56]);
//!     }
//!
//!     // Index (via derefing as an array).
//!     {
//!         let mut example = Example { x: 42, y: 56 };
//!         example[1] = 23;
//!         assert_eq!(example, Example { x: 42, y: 23 });
//!     }
//!
//!     // Convert into an array.
//!     {
//!         let example = Example { x: 42, y: 56 };
//!         let array: [u32; 2] = example.into();
//!         assert_eq!(array, [42, 56]);
//!     }
//!
//!     // Convert from an array to a struct.
//!     {
//!         let array = [42, 56];
//!         let example: Example = array.into();
//!         assert_eq!(example, Example { x: 42, y: 56 });
//!     }
//!
//!     // Convert from a slice to a struct reference.
//!     {
//!         let slice = &[42, 56][..];
//!         let example: &Example = slice.into();
//!         assert_eq!(example, &Example { x: 42, y: 56 });
//!     }
//! }
//!
//! ```
//!
//! # Trait implementations
//!
//! Deriving `StructArray` for a struct `Foo` causes it to implement:
//!
//! * `Deref<Target=[T; len]> for Foo`
//! * `DerefMut<Target=[T; len]> for Foo`
//! * `From<Foo> for [T; len]`
//! * `From<[T; len]> for Foo`
//! * `From<&Foo> for &[T; len]`
//! * `AsRef<[T; len] for Foo`
//! * `From<&[T; len] for &Foo`
//! * `AsRef<Foo> for [T; len]`
//! * `From<&mut Foo> for &mut [T; len]`
//! * `AsMut<[T; len] for Foo`
//! * `From<&mut [T; len] for &mut Foo`
//! * `AsMut<Foo> for [T; len]`
//! * `From<&Foo> for &[T]`
//! * `AsRef<[T]> for Foo`
//! * `From<&[T]> for &Foo`
//! * `AsRef<Foo> for [T]`
//! * `From<&mut Foo> for &mut [T]`
//! * `AsMut<[T]> for Foo`
//! * `From<&mut [T]> for &mut Foo`
//! * `AsMut<Foo> for [T]`
//!
//! Note that converting from a slice will panic if the `len()` of the slice
//! does not must match the `len` specified for the struct.

#![feature(proc_macro, proc_macro_lib)]

#![recursion_limit = "500"]

extern crate proc_macro;
use proc_macro::TokenStream;

extern crate syn;

#[macro_use]
extern crate quote;

/// Implements derive of `StructArray`.
///
/// This function is called by the Rust compiler when compiling code that uses
/// `#[derive(StructArray)]`.
#[proc_macro_derive(StructArray)]
pub fn derive_struct_array(input: TokenStream) -> TokenStream {
    let source = input.to_string();

    // Parse the string representation into a syntax tree
    let ast = syn::parse_macro_input(&source).unwrap();

    // Build the output
    let expanded = impl_struct_array(&ast);

    // Return the generated impl as a TokenStream
    expanded.parse().unwrap()
}

fn impl_struct_array(ast: &syn::MacroInput) -> quote::Tokens {
    let name = &ast.ident;
    let (field_type, field_count) = match ast.body {
        syn::Body::Struct(ref data) => {
            let field_type = &data.fields().first().expect(
                "#[derive(StructArray)] can only be used with structs that have at least one field"
            ).ty;
            for field in data.fields() {
                if field.vis != syn::Visibility::Public {
                    panic!("#[derive(StructArray)] can only used if all the fields in the struct are public")
                }
                if field.ty != *field_type {
                    panic!("#[derive(StructArray)] can only used with structs that have identical field types")
                }
            }
            (field_type, data.fields().len())
        },
        syn::Body::Enum(_) => panic!("#[derive(StructArray)] can only be used with structs"),
    };
    let repr_c = syn::MetaItem::List("repr".into(), vec![syn::NestedMetaItem::MetaItem(syn::MetaItem::Word("C".into()))]);
    if !ast.attrs.iter().any(|attr| attr.value == repr_c) {
        panic!("#[derive(StructArray)] can only be used with structs that are #[repr(C)]");
    }

    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
    quote! {
        impl #impl_generics ::std::ops::Deref for #name #ty_generics #where_clause {
            type Target = [#field_type; #field_count];

            fn deref(&self) -> &[#field_type; #field_count] {
                unsafe {
                    &*(self as *const #name as *const [#field_type; #field_count])
                }
            }
        }

        impl #impl_generics ::std::ops::DerefMut for #name #ty_generics #where_clause {
            fn deref_mut(&mut self) -> &mut [#field_type; #field_count] {
                unsafe {
                    &mut *(self as *mut #name as *mut [#field_type; #field_count])
                }
            }
        }

        impl #impl_generics From<#name> for [#field_type; #field_count] #ty_generics #where_clause {
            fn from(s: #name) -> [#field_type; #field_count] {
                unsafe {
                    ::std::mem::transmute(s)
                }
            }
        }

        impl #impl_generics From<[#field_type; #field_count]> for #name #ty_generics #where_clause {
            fn from(array: [#field_type; #field_count]) -> #name {
                unsafe {
                    ::std::mem::transmute(array)
                }
            }
        }

        impl<'a> #impl_generics From<&'a #name> for &'a [#field_type; #field_count] #ty_generics #where_clause {
            fn from(s: &'a #name) -> &'a [#field_type; #field_count] {
                unsafe {
                    &*(s as *const #name as *const [#field_type; #field_count])
                }
            }
        }

        impl #impl_generics ::std::convert::AsRef<[#field_type; #field_count]> for #name #ty_generics #where_clause {
            fn as_ref(&self) -> &[#field_type; #field_count] {
                unsafe {
                    &*(self as *const #name as *const [#field_type; #field_count])
                }
            }
        }

        impl<'a> #impl_generics From<&'a [#field_type; #field_count]> for &'a #name #ty_generics #where_clause {
            fn from(array: &[#field_type; #field_count]) -> &#name {
                unsafe {
                    &*(array as *const [#field_type; #field_count] as *const #name)
                }
            }
        }

        impl #impl_generics ::std::convert::AsRef<#name> for [#field_type; #field_count] #ty_generics #where_clause {
            fn as_ref(&self) -> &#name {
                unsafe {
                    &*(self as *const [#field_type; #field_count] as *const #name)
                }
            }
        }

        impl<'a> #impl_generics From<&'a mut #name> for &'a mut [#field_type; #field_count] #ty_generics #where_clause {
            fn from(s: &'a mut #name) -> &'a mut [#field_type; #field_count] {
                unsafe {
                    &mut *(s as *mut #name as *mut [#field_type; #field_count])
                }
            }
        }

        impl #impl_generics ::std::convert::AsMut<[#field_type; #field_count]> for #name #ty_generics #where_clause {
            fn as_mut(&mut self) -> &mut [#field_type; #field_count] {
                unsafe {
                    &mut *(self as *mut #name as *mut [#field_type; #field_count])
                }
            }
        }

        impl<'a> #impl_generics From<&'a mut [#field_type; #field_count]> for &'a mut #name #ty_generics #where_clause {
            fn from(array: &mut [#field_type; #field_count]) -> &mut #name {
                unsafe {
                    &mut *(array as *mut [#field_type; #field_count] as *mut #name)
                }
            }
        }

        impl #impl_generics ::std::convert::AsMut<#name> for [#field_type; #field_count] #ty_generics #where_clause {
            fn as_mut(&mut self) -> &mut #name {
                unsafe {
                    &mut *(self as *mut [#field_type; #field_count] as *mut #name)
                }
            }
        }

        impl<'a> #impl_generics From<&'a #name> for &'a [#field_type] #ty_generics #where_clause {
            fn from(s: &'a #name) -> &'a [#field_type] {
                unsafe {
                    ::std::slice::from_raw_parts(s as *const #name as *const #field_type, #field_count)
                }
            }
        }

        impl #impl_generics ::std::convert::AsRef<[#field_type]> for #name #ty_generics #where_clause {
            fn as_ref(&self) -> &[#field_type] {
                unsafe {
                    ::std::slice::from_raw_parts(self as *const #name as *const #field_type, #field_count)
                }
            }
        }

        impl<'a> #impl_generics From<&'a [#field_type]> for &'a #name #ty_generics #where_clause {
            fn from(slice: &'a [#field_type]) -> &'a #name {
                assert!(slice.len() == #field_count);
                unsafe {
                    &*(slice.as_ptr() as *const #name)
                }
            }
        }

        impl #impl_generics ::std::convert::AsRef<#name> for [#field_type] #ty_generics #where_clause {
            fn as_ref(&self) -> &#name {
                assert!(self.len() == #field_count);
                unsafe {
                    &*(self.as_ptr() as *const #name)
                }
            }
        }

        impl<'a> #impl_generics From<&'a mut #name> for &'a mut [#field_type] #ty_generics #where_clause {
            fn from(s: &'a mut #name) -> &'a mut [#field_type] {
                unsafe {
                    ::std::slice::from_raw_parts_mut(s as *mut #name as *mut #field_type, #field_count)
                }
            }
        }

        impl #impl_generics ::std::convert::AsMut<[#field_type]> for #name #ty_generics #where_clause {
            fn as_mut(&mut self) -> &mut [#field_type] {
                unsafe {
                    ::std::slice::from_raw_parts_mut(self as *mut #name as *mut #field_type, #field_count)
                }
            }
        }

        impl<'a> #impl_generics From<&'a mut [#field_type]> for &'a mut #name #ty_generics #where_clause {
            fn from(slice: &'a mut [#field_type]) -> &'a mut #name {
                assert!(slice.len() == #field_count);
                unsafe {
                    &mut *(slice.as_mut_ptr() as *mut #name)
                }
            }
        }

        impl #impl_generics ::std::convert::AsMut<#name> for [#field_type] #ty_generics #where_clause {
            fn as_mut(&mut self) -> &mut #name {
                assert!(self.len() == #field_count);
                unsafe {
                    &mut *(self.as_mut_ptr() as *mut #name)
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Daniel P. Clark & other digits Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//
#![deny(missing_docs,trivial_casts,trivial_numeric_casts,
        missing_debug_implementations, missing_copy_implementations,
        unsafe_code,unstable_features,unused_import_braces,unused_qualifications)
]
//! # digits
//!
//! The digits crate is a linked list implementation of a score card flipper.  But
//! in this case it's with any characters you want and you can enumerate through
//! possibilities beyond the numeric limits intrinsic in basic numerc types like `u64`.
//!
//! Primary use case would be brute forcing character sequences.
extern crate base_custom;
#[doc(no_inline)]
pub use base_custom::BaseCustom;
use std::fmt;

/// This struct acts similar to a full number with a custom numeric character base.
/// But the underlying implementation is a linked list where all the methods recurse
/// as far as need to to implement the operations.
#[derive(Clone)]
pub struct Digits<'a> {
  mapping: &'a BaseCustom<char>,
  digit: u64,
  left: Option<Box<Digits<'a>>>,
}

impl<'a> Digits<'a> {
  /// Add two Digits instances together.  The one the `add` method is called on
  /// must be mutable and modifies itself.  The other is consumed.
  ///
  /// # Example
  ///
  /// ```
  /// use digits::{BaseCustom,Digits};
  ///
  /// let base10 = BaseCustom::<char>::new("0123456789".chars().collect());
  ///
  /// let mut eleven = Digits::new(&base10, "11".to_string());
  /// let two = Digits::new(&base10, "2".to_string());
  ///
  /// assert_eq!(eleven.add(two).to_s(), "13");
  /// ```
  ///
  /// # Output
  ///
  /// ```text
  /// "13"
  /// ```
  pub fn add(&mut self, other: Self) -> Self {
    assert!(self.mapping == other.mapping);
    if other.is_end() { return self.clone(); };
    let (last, rest) = other.head_tail();

    // sums current single digit
    let added = self.propagate(self.mapping.gen(last + self.digit));
    let (l, r) = added.head_tail();
    self.digit = l;

    // sums for left
    let mut intermediate = Digits::new_zero(self.mapping);
    if let Some(dg) = r { intermediate.add(dg.replicate()); }
    if let Some(dg) = rest { intermediate.add(dg.replicate()); }

    let current_left = match self.left.clone() {
      None => { Box::new(self.zero()) },
      Some(bx) => { bx },
    }.as_ref().clone();

    self.set_left( intermediate.add(current_left).clone() );
    self.clone()
  }

  // the way to recurse and process Digits
  fn head_tail(self) -> (u64, Option<Box<Self>>) {
    match self.left {
      Some(bx) => (self.digit, Some(bx)),
      None => (self.digit, None),
    }
  }

  // A non-consuming quick end check.
  // More efficient than calling `is_zero` when this applies.
  fn is_end(&self) -> bool {
    self.digit == 0 && match self.left { None => true, _ => false }
  }

  /// Returns bool value of if the number is one.
  pub fn is_one(&self) -> bool {
    if self.digit != 1 { return false }
    match &self.left {
      &None => { true },
      &Some(ref bx) => { bx.is_zero() },
    }
  }

  /// Returns bool value of if the number is zero.
  pub fn is_zero(&self) -> bool {
    if self.digit != 0 { return false }
    match &self.left {
      &None => { true },
      &Some(ref bx) => { bx.is_zero() },
    }
  }

  /// Returns a `usize` of the total linked list length.
  pub fn length(&self) -> usize {
    match &self.left {
      &None => 1,
      &Some(ref l) => { l.length() + 1 }
    }
  }

  /// Multiply two Digits instances together.  The one the `mul` method is called on
  /// must be mutable and modifies itself.  The other is consumed.
  ///
  /// # Example
  ///
  /// ```
  /// use digits::{BaseCustom,Digits};
  ///
  /// let base10 = BaseCustom::<char>::new("0123456789".chars().collect());
  ///
  /// let mut eleven = Digits::new(&base10, "11".to_string());
  /// let two = Digits::new(&base10, "2".to_string());
  ///
  /// assert_eq!(eleven.mul(two).to_s(), "22");
  /// ```
  ///
  /// # Output
  ///
  /// ```text
  /// "22"
  /// ```
  pub fn mul(&mut self, other: Self) -> Self {
    let (d, r) = self.multiply(other, 0).head_tail();
    self.digit = d;
    if let Some(rest) = r { self.set_left(rest.replicate()); }
    self.clone()
  }

  // Internal implementation for multiply. Needs the recursive
  // value of powers of ten for addition.
  fn multiply(&mut self, other: Self, power_of_ten: usize) -> Self {
    let mut position: usize = power_of_ten;
    let mut o = Some(Box::new(other));
    let mut result = self.zero();

    loop {
      match o.clone() {
        Some(thing) => {
          let (dgt, tail) = thing.head_tail();
          o = tail;

          let mltply = self.propagate((self.digit * dgt).to_string()).pow_ten(position);

          if let Some(ref mut bx) = self.left {
            let mapping = self.mapping.clone();
            result.add(
              bx.clone().multiply(
                Digits::new(
                  mapping,
                  self.mapping.gen(dgt).to_string()
                ),
                position + 1
              )
            );
          };

          if !mltply.is_zero() { result.add( mltply ); }
        },
        None => break,
      }

      position += 1;
    }

    result
  }

  /// Creates a new Digits instance with the provided character set and value.
  ///
  /// The first parameter must be a BaseCustom object which defines and maps all values.
  /// The second parameter is a string value with all valid characters from the BaseCustom set.
  pub fn new<S>(mapping: &'a BaseCustom<char>, number: S) -> Digits<'a>
  where S: Into<String> {
    let number = number.into();
    if number.is_empty() { return Digits { mapping: mapping, digit: 0, left: None }; };
    let (last, rest) = {
      let mut n = number.chars().rev();
      (n.next().unwrap(), n.rev().collect::<String>())
    };

    let continuation = {
      if rest.is_empty() {
        None
      } else {
        Some(Box::new(Digits::new(&mapping, rest)))
      }
    };
    Digits {
      mapping: mapping,
      digit: mapping.decimal(last.to_string()),
      left: continuation,
    }
  }

  /// Creates a new Digits instance with value of one and the provided character mapping.
  pub fn new_one(mapping: &'a BaseCustom<char>) -> Self {
    Digits { mapping: mapping, digit: 1, left: None }
  }

  /// Creates a new Digits instance with value of zero and uses the provided character mapping.
  pub fn new_zero(mapping: &'a BaseCustom<char>) -> Self {
    Digits { mapping: mapping, digit: 0, left: None }
  }

  /// Creates a new Digits instance with value of one and uses the current character mapping.
  pub fn one(&self) -> Self {
    Digits::new_one(self.mapping)
  }

  /// The “pinky” is the smallest digit
  /// a.k.a. current digit in the linked list
  /// a.k.a. the right most digit.
  /// This will be a `char` value for that digit.
  pub fn pinky(&self) -> char {
    self.mapping.char(self.digit as usize).unwrap()
  }

  /// Multiplies self times the power-of given Digits parameter.
  ///
  /// # Example
  ///
  /// ```
  /// use digits::{BaseCustom,Digits};
  ///
  /// let base10 = BaseCustom::<char>::new("0123456789".chars().collect());
  ///
  /// let mut eleven = Digits::new(&base10, "11".to_string());
  /// let two = Digits::new(&base10, "2".to_string());
  ///
  /// assert_eq!(eleven.pow(two).to_s(), "121");
  /// ```
  ///
  /// # Output
  ///
  /// ```text
  /// "121"
  /// ```
  pub fn pow(&mut self, mut pwr: Self) -> Self {
    loop {
      match pwr.is_one() {
        true => break,
        false => {
          let copy = self.clone();
          self.mul(copy);
        }
      }
      pwr.pred_till_zero();
    }
    self.clone()
  }

  // multiply self by 10^x without using typical multiplication
  fn pow_ten(&self, positions: usize) -> Self {
    let mut result: Digits = self.clone();
    for _ in 0..positions {
      let original = result;
      result = Digits::new_zero(self.mapping);
      result.set_left(original);
    }
    result
  }

  /// Minuses one unless it's zero, then it just returns a Digits instance of zero.
  pub fn pred_till_zero(&mut self) -> Self {
    if self.digit == 0 {
      if self.is_end() { return self.clone(); }
      self.digit = self.mapping.base - 1;
      let mut one = false;
      if let Some(ref mut bx) = self.left {
        if bx.is_one() {
          one = true;
        } else {
          bx.pred_till_zero();
        }
      };
      if one { self.left = None; }
    } else {
      self.digit -= 1;
    }
    self.clone()
  }

  /// Creates a new Digits instance with the internal character set and given value.
  ///
  /// The parameter is a string value with all valid characters from the BaseCustom set.
  pub fn propagate<S>(&self, number: S) -> Self
  where S: Into<String> {
    Digits::new(self.mapping, number)
  }

  /// An alias for `clone`. _Useful for unboxing._
  pub fn replicate(self) -> Self { self.clone() }

  // logic for setting left linked list continuation
  fn set_left(&mut self, d: Digits<'a>) {
    if d.is_end() {
      self.left = None;
    } else {
      self.left = Some(Box::new(d));
    }
  }

  /// Plus one.
  pub fn succ(&mut self) -> Self {
    let one = self.one();
    self.add(one)
  }

  /// Gives the full value of all digits within the linked list as a String.
  pub fn to_s(&self) -> String {
    let num = self.mapping.gen(self.digit);
    match &self.left {
      &None => format!("{}", num),
      &Some(ref bx) => format!("{}{}", bx.to_s(), num),
    }
  }

  /// Gives the full value of all digits within the linked list as a String.
  pub fn to_string(&self) -> String {
    self.to_s()
  }

  /// Creates a new Digits instance with value of zero and the current character mapping.
  pub fn zero(&self) -> Self {
    Digits::new_zero(self.mapping)
  }
}

/// NODOC
pub trait Into<String> {
  /// NODOC
  fn into(self) -> String;
}

impl<'a> From<Digits<'a>> for String {
  fn from(d: Digits) -> String {
    d.to_s()
  }
}

impl<'a> Into<String> for Digits<'a> {
  fn into(self) -> String {
    self.to_s()
  }
}

impl Into<String> for String {
  fn into(self) -> String {
    self.clone()
  }
}

impl<'a> fmt::Display for Digits<'a> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
   write!(f, "Digits<'a> — (Character: '{}', Decimal Value: {}{})",
     self.mapping.gen(self.digit), self.digit, {
       match self.left {
         None => "".to_string(),
         Some(ref l) => format!(", With Preceeding: '{}'", l.to_s()),
       }
     }
     )
  }
}

impl<'a> fmt::Debug for Digits<'a> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{} with base: {:?}", self, self.mapping)
  }
}
<commit_msg>Small opt<commit_after>// Copyright 2017 Daniel P. Clark & other digits Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//
#![deny(missing_docs,trivial_casts,trivial_numeric_casts,
        missing_debug_implementations, missing_copy_implementations,
        unsafe_code,unstable_features,unused_import_braces,unused_qualifications)
]
//! # digits
//!
//! The digits crate is a linked list implementation of a score card flipper.  But
//! in this case it's with any characters you want and you can enumerate through
//! possibilities beyond the numeric limits intrinsic in basic numerc types like `u64`.
//!
//! Primary use case would be brute forcing character sequences.
extern crate base_custom;
#[doc(no_inline)]
pub use base_custom::BaseCustom;
use std::fmt;

/// This struct acts similar to a full number with a custom numeric character base.
/// But the underlying implementation is a linked list where all the methods recurse
/// as far as need to to implement the operations.
#[derive(Clone)]
pub struct Digits<'a> {
  mapping: &'a BaseCustom<char>,
  digit: u64,
  left: Option<Box<Digits<'a>>>,
}

impl<'a> Digits<'a> {
  /// Add two Digits instances together.  The one the `add` method is called on
  /// must be mutable and modifies itself.  The other is consumed.
  ///
  /// # Example
  ///
  /// ```
  /// use digits::{BaseCustom,Digits};
  ///
  /// let base10 = BaseCustom::<char>::new("0123456789".chars().collect());
  ///
  /// let mut eleven = Digits::new(&base10, "11".to_string());
  /// let two = Digits::new(&base10, "2".to_string());
  ///
  /// assert_eq!(eleven.add(two).to_s(), "13");
  /// ```
  ///
  /// # Output
  ///
  /// ```text
  /// "13"
  /// ```
  pub fn add(&mut self, other: Self) -> Self {
    assert!(self.mapping == other.mapping);
    if other.is_end() { return self.clone(); };
    let (last, rest) = other.head_tail();

    // sums current single digit
    let added = self.propagate(self.mapping.gen(last + self.digit));
    let (l, r) = added.head_tail();
    self.digit = l;

    // sums for left
    let mut intermediate = Digits::new_zero(self.mapping);
    if let Some(dg) = r { intermediate.add(dg.replicate()); }
    if let Some(dg) = rest { intermediate.add(dg.replicate()); }

    let current_left = match self.left.clone() {
      None => { Box::new(self.zero()) },
      Some(bx) => { bx },
    }.as_ref().clone();

    self.set_left( intermediate.add(current_left).clone() );
    self.clone()
  }

  // the way to recurse and process Digits
  fn head_tail(self) -> (u64, Option<Box<Self>>) {
    match self.left {
      Some(bx) => (self.digit, Some(bx)),
      None => (self.digit, None),
    }
  }

  // A non-consuming quick end check.
  // More efficient than calling `is_zero` when this applies.
  fn is_end(&self) -> bool {
    self.digit == 0 && match self.left { None => true, _ => false }
  }

  /// Returns bool value of if the number is one.
  pub fn is_one(&self) -> bool {
    if self.digit != 1 { return false }
    match &self.left {
      &None => { true },
      &Some(ref bx) => { bx.is_zero() },
    }
  }

  /// Returns bool value of if the number is zero.
  pub fn is_zero(&self) -> bool {
    if self.digit != 0 { return false }
    match &self.left {
      &None => { true },
      &Some(ref bx) => { bx.is_zero() },
    }
  }

  /// Returns a `usize` of the total linked list length.
  pub fn length(&self) -> usize {
    match &self.left {
      &None => 1,
      &Some(ref l) => { l.length() + 1 }
    }
  }

  /// Multiply two Digits instances together.  The one the `mul` method is called on
  /// must be mutable and modifies itself.  The other is consumed.
  ///
  /// # Example
  ///
  /// ```
  /// use digits::{BaseCustom,Digits};
  ///
  /// let base10 = BaseCustom::<char>::new("0123456789".chars().collect());
  ///
  /// let mut eleven = Digits::new(&base10, "11".to_string());
  /// let two = Digits::new(&base10, "2".to_string());
  ///
  /// assert_eq!(eleven.mul(two).to_s(), "22");
  /// ```
  ///
  /// # Output
  ///
  /// ```text
  /// "22"
  /// ```
  pub fn mul(&mut self, other: Self) -> Self {
    let (d, r) = self.multiply(other, 0).head_tail();
    self.digit = d;
    if let Some(rest) = r { self.set_left(rest.replicate()); }
    self.clone()
  }

  // Internal implementation for multiply. Needs the recursive
  // value of powers of ten for addition.
  fn multiply(&mut self, other: Self, power_of_ten: usize) -> Self {
    let mut position: usize = power_of_ten;
    let mut o = Some(Box::new(other));
    let mut result = self.zero();

    loop {
      match o.clone() {
        Some(thing) => {
          let (dgt, tail) = thing.head_tail();
          o = tail;

          let mltply = self.propagate((self.digit * dgt).to_string()).pow_ten(position);

          if let Some(ref mut bx) = self.left {
            let mapping = self.mapping.clone();
            result.add(
              bx.clone().multiply(
                Digits::new(
                  mapping,
                  self.mapping.gen(dgt).to_string()
                ),
                position + 1
              )
            );
          };

          result.add( mltply );
        },
        None => break,
      }

      position += 1;
    }

    result
  }

  /// Creates a new Digits instance with the provided character set and value.
  ///
  /// The first parameter must be a BaseCustom object which defines and maps all values.
  /// The second parameter is a string value with all valid characters from the BaseCustom set.
  pub fn new<S>(mapping: &'a BaseCustom<char>, number: S) -> Digits<'a>
  where S: Into<String> {
    let number = number.into();
    if number.is_empty() { return Digits { mapping: mapping, digit: 0, left: None }; };
    let (last, rest) = {
      let mut n = number.chars().rev();
      (n.next().unwrap(), n.rev().collect::<String>())
    };

    let continuation = {
      if rest.is_empty() {
        None
      } else {
        Some(Box::new(Digits::new(&mapping, rest)))
      }
    };
    Digits {
      mapping: mapping,
      digit: mapping.decimal(last.to_string()),
      left: continuation,
    }
  }

  /// Creates a new Digits instance with value of one and the provided character mapping.
  pub fn new_one(mapping: &'a BaseCustom<char>) -> Self {
    Digits { mapping: mapping, digit: 1, left: None }
  }

  /// Creates a new Digits instance with value of zero and uses the provided character mapping.
  pub fn new_zero(mapping: &'a BaseCustom<char>) -> Self {
    Digits { mapping: mapping, digit: 0, left: None }
  }

  /// Creates a new Digits instance with value of one and uses the current character mapping.
  pub fn one(&self) -> Self {
    Digits::new_one(self.mapping)
  }

  /// The “pinky” is the smallest digit
  /// a.k.a. current digit in the linked list
  /// a.k.a. the right most digit.
  /// This will be a `char` value for that digit.
  pub fn pinky(&self) -> char {
    self.mapping.char(self.digit as usize).unwrap()
  }

  /// Multiplies self times the power-of given Digits parameter.
  ///
  /// # Example
  ///
  /// ```
  /// use digits::{BaseCustom,Digits};
  ///
  /// let base10 = BaseCustom::<char>::new("0123456789".chars().collect());
  ///
  /// let mut eleven = Digits::new(&base10, "11".to_string());
  /// let two = Digits::new(&base10, "2".to_string());
  ///
  /// assert_eq!(eleven.pow(two).to_s(), "121");
  /// ```
  ///
  /// # Output
  ///
  /// ```text
  /// "121"
  /// ```
  pub fn pow(&mut self, mut pwr: Self) -> Self {
    loop {
      match pwr.is_one() {
        true => break,
        false => {
          let copy = self.clone();
          self.mul(copy);
        }
      }
      pwr.pred_till_zero();
    }
    self.clone()
  }

  // multiply self by 10^x without using typical multiplication
  fn pow_ten(&self, positions: usize) -> Self {
    let mut result: Digits = self.clone();
    for _ in 0..positions {
      let original = result;
      result = Digits::new_zero(self.mapping);
      result.set_left(original);
    }
    result
  }

  /// Minuses one unless it's zero, then it just returns a Digits instance of zero.
  pub fn pred_till_zero(&mut self) -> Self {
    if self.digit == 0 {
      if self.is_end() { return self.clone(); }
      self.digit = self.mapping.base - 1;
      let mut one = false;
      if let Some(ref mut bx) = self.left {
        if bx.is_one() {
          one = true;
        } else {
          bx.pred_till_zero();
        }
      };
      if one { self.left = None; }
    } else {
      self.digit -= 1;
    }
    self.clone()
  }

  /// Creates a new Digits instance with the internal character set and given value.
  ///
  /// The parameter is a string value with all valid characters from the BaseCustom set.
  pub fn propagate<S>(&self, number: S) -> Self
  where S: Into<String> {
    Digits::new(self.mapping, number)
  }

  /// An alias for `clone`. _Useful for unboxing._
  pub fn replicate(self) -> Self { self.clone() }

  // logic for setting left linked list continuation
  fn set_left(&mut self, d: Digits<'a>) {
    if d.is_end() {
      self.left = None;
    } else {
      self.left = Some(Box::new(d));
    }
  }

  /// Plus one.
  pub fn succ(&mut self) -> Self {
    let one = self.one();
    self.add(one)
  }

  /// Gives the full value of all digits within the linked list as a String.
  pub fn to_s(&self) -> String {
    let num = self.mapping.gen(self.digit);
    match &self.left {
      &None => format!("{}", num),
      &Some(ref bx) => format!("{}{}", bx.to_s(), num),
    }
  }

  /// Gives the full value of all digits within the linked list as a String.
  pub fn to_string(&self) -> String {
    self.to_s()
  }

  /// Creates a new Digits instance with value of zero and the current character mapping.
  pub fn zero(&self) -> Self {
    Digits::new_zero(self.mapping)
  }
}

/// NODOC
pub trait Into<String> {
  /// NODOC
  fn into(self) -> String;
}

impl<'a> From<Digits<'a>> for String {
  fn from(d: Digits) -> String {
    d.to_s()
  }
}

impl<'a> Into<String> for Digits<'a> {
  fn into(self) -> String {
    self.to_s()
  }
}

impl Into<String> for String {
  fn into(self) -> String {
    self.clone()
  }
}

impl<'a> fmt::Display for Digits<'a> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
   write!(f, "Digits<'a> — (Character: '{}', Decimal Value: {}{})",
     self.mapping.gen(self.digit), self.digit, {
       match self.left {
         None => "".to_string(),
         Some(ref l) => format!(", With Preceeding: '{}'", l.to_s()),
       }
     }
     )
  }
}

impl<'a> fmt::Debug for Digits<'a> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{} with base: {:?}", self, self.mapping)
  }
}
<|endoftext|>


<commit_before>#[macro_use] mod macros;
mod std_impls;

/// A collection.
pub trait Collection {
    /// Removes all items from the collection.
    fn clear(&mut self);

    /// Checks if the collection is empty.
    fn is_empty(&self) -> bool { self.len() == 0 }

    /// Returns the number of items in the collection.
    fn len(&self) -> usize;
}

/// A trait that declares a map's key and value types.
///
/// It is unusual to bound types by this trait directly. Consider using [`Map`](trait.Map.html)
/// instead.
pub trait BaseMap: Collection {
    /// The map's key type.
    type Key;

    /// The map's value type.
    type Value;
}

/// A map.
pub trait Map: MapLookup<<Self as BaseMap>::Key> {
    /// Inserts the given key and value into the map, returning the previous value associated with
    /// the key, or `None` if the map did not already contain the key.
    fn insert(&mut self, key: Self::Key, value: Self::Value) -> Option<Self::Value>;
}

/// A map that supports alternate key lookups.
pub trait MapLookup<Q: ?Sized>: BaseMap {
    /// Checks if the map contains the given key.
    fn contains_key(&self, key: &Q) -> bool { self.get(key).is_some() }

    /// Returns a reference to the value associated with the given key in the map, or `None` if
    /// the map does not contain the key.
    fn get(&self, key: &Q) -> Option<&Self::Value>;

    /// Returns a mutable reference to the value associated with the given key in the map, or
    /// `None` if the map does not contain the key.
    fn get_mut(&mut self, key: &Q) -> Option<&mut Self::Value>;

    /// Removes the given key from the map, returning the value associated with it, or `None` if
    /// the map did not contain the key.
    fn remove(&mut self, key: &Q) -> Option<Self::Value>;
}

/// A map that supports the entry API.
pub trait EntryMap<'a>: Map {
    /// The occupied entry type.
    type Occupied: OccupiedEntry<'a, Key = Self::Key, Value = Self::Value>;

    /// The vacant entry type.
    type Vacant: VacantEntry<'a, Key = Self::Key, Value = Self::Value>;

    /// Returns the given key's corresponding entry in the map for in-place manipulation.
    fn entry(&'a mut self, key: Self::Key) -> Entry<Self::Occupied, Self::Vacant>;
}

/// A map entry.
pub enum Entry<O, V> {
    /// An occupied entry.
    Occupied(O),
    /// A vacant entry.
    Vacant(V),
}

impl<'a, O, V> Entry<O, V>
where
    O: OccupiedEntry<'a>,
    V: VacantEntry<'a, Key = O::Key, Value = O::Value>
{
    /// Ensures that a value is in the entry by inserting the default if it is empty, and returns a
    /// mutable reference to the value.
    pub fn or_insert(self, default: O::Value) -> &'a mut O::Value {
        match self {
            Entry::Occupied(e) => e.into_mut(),
            Entry::Vacant(e) => e.insert(default),
        }
    }

    /// Ensures that a value is in the entry by inserting the result of the default function if it
    /// is empty, and returns a mutable reference to the value.
    pub fn or_insert_with<F>(self, default: F) -> &'a mut O::Value where F: FnOnce() -> O::Value {
        match self {
            Entry::Occupied(e) => e.into_mut(),
            Entry::Vacant(e) => e.insert(default()),
        }
    }
}

/// An occupied map entry.
pub trait OccupiedEntry<'a> {
    /// The entry's key type.
    type Key: 'a;

    /// The entry's value type.
    type Value: 'a;

    /// Returns a reference to the entry's value.
    fn get(&self) -> &Self::Value;

    /// Returns a mutable reference to the entry's value.
    fn get_mut(&mut self) -> &mut Self::Value;

    /// Sets the entry's value to the given one, returning the old value.
    fn insert(&mut self, value: Self::Value) -> Self::Value;

    /// Returns a mutable reference to the entry's value with the lifetime of the map.
    fn into_mut(self) -> &'a mut Self::Value;

    /// Removes the entry, returning its value.
    fn remove(self) -> Self::Value;
}

/// A vacant map entry.
pub trait VacantEntry<'a> {
    /// The entry's key type.
    type Key: 'a;

    /// The entry's value type.
    type Value: 'a;

    /// Sets the entry's value to the given one, returning a mutable reference to the value with
    /// the lifetime of the map.
    fn insert(self, value: Self::Value) -> &'a mut Self::Value;
}

/// A trait that declares a set's item type.
///
/// It is unusual to bound types by this trait directly. Consider using [`Set`](trait.Set.html)
/// instead.
pub trait BaseSet: Collection {
    /// The set's item type.
    type Item;
}

/// A set.
pub trait Set: SetLookup<<Self as BaseSet>::Item> {
    /// Inserts the given item into the set, returning `true` if the set did not already contain
    /// the item.
    fn insert(&mut self, item: Self::Item) -> bool;
}

/// A set that supports alternate item lookups.
pub trait SetLookup<Q: ?Sized>: BaseSet {
    /// Checks if the set contains the given item.
    fn contains(&self, item: &Q) -> bool;

    /// Removes the given item from the set, returning `true` if the set contained the item.
    fn remove(&mut self, item: &Q) -> bool;
}
<commit_msg>flesh out docs<commit_after>//! Collection traits for generic programming.

#![forbid(missing_docs)]

#[macro_use] mod macros;
mod std_impls;

/// A collection.
pub trait Collection {
    /// Removes all items from the collection.
    ///
    /// After this method returns, `self.len() == 0`.
    fn clear(&mut self);

    /// Checks if the collection is empty.
    ///
    /// This method returns `true` iff `self.len() == 0`.
    fn is_empty(&self) -> bool { self.len() == 0 }

    /// Returns the number of items in the collection.
    ///
    /// This method returns `0` iff `self.is_empty()`.
    fn len(&self) -> usize;
}

/// A trait that declares a map's key and value types.
///
/// It is unusual to bound types by this trait directly. Consider using [`Map`](trait.Map.html)
/// instead.
pub trait BaseMap: Collection {
    /// The map's key type.
    type Key;

    /// The map's value type.
    type Value;
}

/// A map.
pub trait Map: MapLookup<<Self as BaseMap>::Key> {
    /// Inserts the given key and value into the map and returns the previous value, if any,
    /// corresponding to the given key.
    fn insert(&mut self, key: Self::Key, value: Self::Value) -> Option<Self::Value>;
}

/// A map that supports lookups using keys of type `&Q`.
pub trait MapLookup<Q: ?Sized>: BaseMap {
    /// Checks if the map contains the given key.
    fn contains_key(&self, key: &Q) -> bool { self.get(key).is_some() }

    /// Returns a reference to the value in the map, if any, corresponding to the given key.
    fn get(&self, key: &Q) -> Option<&Self::Value>;

    /// Returns a mutable reference to the value in the map, if any, corresponding to the given
    fn get_mut(&mut self, key: &Q) -> Option<&mut Self::Value>;

    /// Removes the given key from the map and returns its corresponding value, if any.
    fn remove(&mut self, key: &Q) -> Option<Self::Value>;
}

/// A map that supports efficient in-place manipulation of its entries.
pub trait EntryMap<'a>: Map {
    /// The map's occupied entry type.
    type Occupied: OccupiedEntry<'a, Key = Self::Key, Value = Self::Value>;

    /// The map's vacant entry type.
    type Vacant: VacantEntry<'a, Key = Self::Key, Value = Self::Value>;

    /// Returns the entry in the map corresponding to the given key.
    ///
    /// # Examples
    ///
    /// Count the unique items yielded by an iterator:
    ///
    /// ```
    /// use eclectic::EntryMap;
    ///
    /// fn count<I, M>(items: I) -> M
    /// where
    ///     M: Default + for<'a> EntryMap<'a, Value = usize>,
    ///     I: IntoIterator<Item = M::Key>,
    /// {
    ///     let mut counts = M::default();
    ///
    ///     for item in items {
    ///         *counts.entry(item).or_insert(0) += 1;
    ///     }
    ///
    ///     counts
    /// }
    /// ```
    ///
    /// Group values into a multimap according to keys yielded by an iterator:
    ///
    /// ```
    /// use eclectic::EntryMap;
    ///
    /// fn group<I, V, M>(key_values: I) -> M
    /// where
    ///     M: Default + for<'a> EntryMap<'a, Value = Vec<V>>,
    ///     I: IntoIterator<Item = (M::Key, V)>,
    /// {
    ///     let mut groups = M::default();
    ///
    ///     for (key, value) in key_values {
    ///         groups.entry(key).or_insert(vec![]).push(value);
    ///     }
    ///
    ///     groups
    /// }
    /// ```
    fn entry(&'a mut self, key: Self::Key) -> Entry<Self::Occupied, Self::Vacant>;
}

/// A map entry.
///
/// See [`EntryMap::entry`](trait.EntryMap.html#tymethod.entry) for an example.
pub enum Entry<O, V> {
    /// An occupied entry.
    Occupied(O),
    /// A vacant entry.
    Vacant(V),
}

impl<'a, O, V> Entry<O, V>
where
    O: OccupiedEntry<'a>,
    V: VacantEntry<'a, Key = O::Key, Value = O::Value>
{
    /// Ensures that the entry is occupied by inserting the given default value if it is vacant,
    /// returning a mutable reference to the value.
    pub fn or_insert(self, default: O::Value) -> &'a mut O::Value {
        match self {
            Entry::Occupied(e) => e.into_mut(),
            Entry::Vacant(e) => e.insert(default),
        }
    }

    /// Ensures that the entry is occupied by inserting the the result of the given function if it
    /// is vacant, returning a mutable reference to the value.
    pub fn or_insert_with<F>(self, default: F) -> &'a mut O::Value where F: FnOnce() -> O::Value {
        match self {
            Entry::Occupied(e) => e.into_mut(),
            Entry::Vacant(e) => e.insert(default()),
        }
    }
}

/// An occupied map entry.
pub trait OccupiedEntry<'a> {
    /// The entry's key type.
    type Key: 'a;

    /// The entry's value type.
    type Value: 'a;

    /// Returns a reference to the entry's value.
    fn get(&self) -> &Self::Value;

    /// Returns a mutable reference to the entry's value.
    fn get_mut(&mut self) -> &mut Self::Value;

    /// Sets the entry's value to the given value and returns the previous one.
    fn insert(&mut self, value: Self::Value) -> Self::Value;

    /// Returns a mutable reference to the entry's value with the lifetime of the map.
    fn into_mut(self) -> &'a mut Self::Value;

    /// Removes the entry from the map and returns its value.
    fn remove(self) -> Self::Value;
}

/// A vacant map entry.
pub trait VacantEntry<'a> {
    /// The entry's key type.
    type Key: 'a;

    /// The entry's value type.
    type Value: 'a;

    /// Inserts the entry into the map with the given value, returning a mutable reference to the
    /// value with the lifetime of the map.
    fn insert(self, value: Self::Value) -> &'a mut Self::Value;
}

/// A trait that declares a set's item type.
///
/// It is unusual to bound types by this trait directly. Consider using [`Set`](trait.Set.html)
/// instead.
pub trait BaseSet: Collection {
    /// The set's item type.
    type Item;
}

/// A set.
pub trait Set: SetLookup<<Self as BaseSet>::Item> {
    /// Inserts the given item into the set and returns `true` if the set did not already contain
    /// it.
    fn insert(&mut self, item: Self::Item) -> bool;
}

/// A set that supports alternate item lookups.
pub trait SetLookup<Q: ?Sized>: BaseSet {
    /// Checks if the set contains the given item.
    fn contains(&self, item: &Q) -> bool;

    /// Removes the given item from the set and returns `true` if the set contained it.
    fn remove(&mut self, item: &Q) -> bool;
}
<|endoftext|>