<commit_before>use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::env;
use std::fmt;
use std::io;
use std::io::Write;
use std::sync::Mutex;

extern crate syn;
use syn::*;

mod rust_lib;

#[derive(Debug, Clone)]
struct ConvertedType {
    /// The type converted to C (e.g. `uint32_t`)
    prefix: String,
    /// Stuff that might need to go after the identifier (e.g. `[3]` for an array).
    postfix: String,
    /// The types this type depends upon. For example a `prefix` of
    /// Foo<Bar> would have both `Foo` and `Bar` in the `deps`.
    deps: BTreeSet<String>,
}

impl ConvertedType {
    fn append_prefix(&self, str: &str) -> ConvertedType {
        let mut clone = self.clone();
        clone.prefix.push_str(str);
        clone
    }

    fn append_postfix(&self, str: &str) -> ConvertedType {
        let mut clone = self.clone();
        clone.postfix.push_str(str);
        clone
    }

    fn add_dep(&self, dep: String) -> ConvertedType {
        let mut clone = self.clone();
        clone.deps.insert(dep);
        clone
    }

    fn format_with_ident(&self, ident: &Ident) -> String {
        format!("{} {}{}", &self.prefix, &ident.to_string(), &self.postfix)
    }
}

impl From<String> for ConvertedType {
    fn from(str: String) -> ConvertedType {
        let mut initial_set = BTreeSet::new();
        initial_set.insert(str.clone());
        ConvertedType {
            prefix: str,
            postfix: String::new(),
            deps: initial_set,
        }
    }
}

impl fmt::Display for ConvertedType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}{}", &self.prefix, &self.postfix)
    }
}

fn has_attribute(target: MetaItem, attrs: &Vec<Attribute>) -> bool {
    return attrs
               .iter()
               .any(|ref attr| attr.style == AttrStyle::Outer && attr.value == target);
}

fn has_no_mangle(attrs: &Vec<Attribute>) -> bool {
    has_attribute(MetaItem::Word(Ident::new("no_mangle")), attrs)
}

fn wr_func_body(attrs: &Vec<Attribute>) -> String {
    if has_attribute(MetaItem::Word(Ident::new("destructor_safe")), attrs) {
        String::from("WR_DESTRUCTOR_SAFE_FUNC")
    } else {
        String::from("WR_FUNC")
    }
}

fn is_repr_c(attrs: &Vec<Attribute>) -> bool {
    let repr_args = vec![NestedMetaItem::MetaItem(MetaItem::Word(Ident::new("C")))];
    has_attribute(MetaItem::List(Ident::new("repr"), repr_args), attrs)
}

fn is_repr_u32(attrs: &Vec<Attribute>) -> bool {
    let repr_args = vec![NestedMetaItem::MetaItem(MetaItem::Word(Ident::new("u32")))];
    has_attribute(MetaItem::List(Ident::new("repr"), repr_args), attrs)
}

fn is_c_abi(abi: &Option<Abi>) -> bool {
    abi == &Some(Abi::Named(String::from("C")))
}

fn map_path(p: &Path) -> ConvertedType {
    let l = p.segments[0].ident.to_string();
    let mut c = ConvertedType::from(match l.as_ref() {
        "usize" => "size_t".to_string(),
        "u8" => "uint8_t".to_string(),
        "u32" => "uint32_t".to_string(),
        "u64" => "uint64_t".to_string(),
        "i8" => "int8_t".to_string(),
        "i32" => "int32_t".to_string(),
        "i64" => "int64_t".to_string(),
        "f32" => "float".to_string(),
        "c_void" => "void".to_string(),
        _ => l,
    });
    if let PathParameters::AngleBracketed(ref d) = p.segments[0].parameters {
        let template_args = d.types
            .iter()
            .map(|ty| {
                let conv = map_ty(ty);
                c = c.add_dep(conv.to_string());
                conv.to_string()
            })
            .collect::<Vec<String>>()
            .join(", ");
        if !template_args.is_empty() {
            c = c.append_prefix(&format!("<{}>", &template_args));
        }
    }
    c
}

fn map_mut_ty(mut_ty: &MutTy) -> ConvertedType {
    map_ty(&mut_ty.ty)
}

fn map_ty(ty: &Ty) -> ConvertedType {
    match ty {
        &Ty::Path(_, ref p) => map_path(p),
        &Ty::Ptr(ref p) => map_ty(&p.ty).append_prefix("*"),
        &Ty::Rptr(_, ref mut_ty) => map_mut_ty(mut_ty).append_prefix("*"),
        &Ty::Array(ref p, ConstExpr::Lit(Lit::Int(sz, _))) => map_ty(&p).append_postfix(&format!("[{}]", sz)),
        _ => ConvertedType::from(format!("unknown {:?}", ty)),
    }
}

fn map_return_type(ret: &FunctionRetTy) -> ConvertedType {
    match ret {
        &FunctionRetTy::Default => ConvertedType::from("void".to_string()),
        &FunctionRetTy::Ty(ref ty) => map_ty(ty),
    }
}

fn map_arg(f: &FnArg, dep_set: &mut BTreeSet<String>) -> String {
    match f {
        &FnArg::Captured(Pat::Ident(_, ref ident, _), ref ty) => {
            let mut converted = map_ty(ty);
            dep_set.append(&mut converted.deps);
            converted.format_with_ident(ident)
        }
        _ => "unknown".to_string(),
    }
}

fn map_field(f: &Field, dep_set: &mut BTreeSet<String>) -> String {
    let mut ret = String::from("  ");
    let mut converted = map_ty(&f.ty);
    dep_set.append(&mut converted.deps);
    ret.push_str(&converted.format_with_ident(f.ident.as_ref().expect("Struct fields must have idents")));
    ret.push_str(";\n");
    ret
}

fn map_generic_param(t: &TyParam) -> String {
    let mut ret = String::from("typename ");
    ret.push_str(&t.ident.to_string());
    ret
}

fn fold_enum_variants(accum: (String, i32), v: &Variant) -> (String, i32) {
    // `accum` contains the combined string of converted enum variants so far, to which
    // we will append the converted version of `v`. The other thing in `accum` is the
    // value of the previous variant. If `v` has an explicit value we keep that, otherwise
    // we increment the value of the previous variant to get the new one. This is all
    // so that we properly support enums with explicitly-specified and discontinuous
    // values.
    let mut ret = accum.0;
    ret.push_str("  ");
    ret.push_str(&v.ident.to_string());
    ret.push_str(" = ");
    let new_value = match &v.discriminant {
        &None => accum.1 + 1,
        &Some(ConstExpr::Lit(Lit::Int(ref specified_value, _))) => *specified_value as i32,
        &Some(_) => {
            // we don't handle this yet, so just put in something that will fail C compilation
            writeln!(io::stderr(), "warning, unsupported enum discriminant").unwrap();
            ret.push_str("???");
            accum.1 + 1
        }
    };
    ret.push_str(&new_value.to_string());
    ret.push_str(",\n");
    (ret, new_value)
}

struct ConvertedItem {
    /// This holds the C code that needs to go into the header file.
    c_code: String,
    /// This holds a set of identifiers that the C code depends on.
    /// So for example if a struct A contains another struct B, the
    /// `ConvertedItem` instance for A will have the string "B" in
    /// `deps`.
    deps: BTreeSet<String>,
}

impl ConvertedItem {
    fn new(c_code: String, deps: BTreeSet<String>) -> ConvertedItem {
        ConvertedItem {
            c_code: c_code,
            deps: deps,
        }
    }
}

/// A structure to store all the results of converting Rust stuff to C
/// stuff, so that we can pick and choose what we output.
struct ConversionResults {
    /// This holds the C function signatures of no_mangle rust functions,
    /// in the order that they were encountered in Rust.
    funcs: Vec<ConvertedItem>,
    /// This holds the C conversions of repr(C) structs and repr(u32) enums
    /// from Rust. The 'ds' in the name stands for 'data structures'. The
    /// key of the map is the name of the type.
    ds: BTreeMap<String, ConvertedItem>,
}

fn main() {
    let p = env::args().nth(1).unwrap();

    let results = Mutex::new(ConversionResults {
        funcs: Vec::new(),
        ds: BTreeMap::new(),
    });

    rust_lib::parse(p, &|mod_name, items| {
        for item in items {
            match item.node {
                ItemKind::Fn(ref decl,
                             ref _unsafe,
                             ref _const,
                             ref abi,
                             ref _generic,
                             ref _block) => {
                    writeln!(io::stderr(), "processing function {}::{}", mod_name, &item.ident).unwrap();
                    if has_no_mangle(&item.attrs) && is_c_abi(&abi) {
                        let mut deps = BTreeSet::new();
                        let mut return_type = map_return_type(&decl.output);
                        deps.append(&mut return_type.deps);
                        let c_code =
                            format!("WR_INLINE {}\n{}({})\n{};\n",
                                    return_type,
                                    item.ident,
                                    decl.inputs
                                        .iter()
                                        .map(|f| map_arg(f, &mut deps))
                                        .collect::<Vec<_>>()
                                        .join(", "),
                                    wr_func_body(&item.attrs));
                        results.lock().unwrap().funcs.push(ConvertedItem::new(c_code, deps));
                    }
                }
                ItemKind::Struct(ref variant,
                                 ref generics) => {
                    writeln!(io::stderr(), "processing struct {}::{}", mod_name, &item.ident).unwrap();
                    if is_repr_c(&item.attrs) {
                        if let &VariantData::Struct(ref fields) = variant {
                            let mut deps = BTreeSet::new();
                            let mut c_code = String::new();
                            if !generics.ty_params.is_empty() {
                                c_code.push_str(&(
                                    format!("template<{}>\n",
                                            generics.ty_params
                                                    .iter()
                                                    .map(map_generic_param)
                                                    .collect::<Vec<_>>()
                                                    .join(", "))));
                            }
                            c_code.push_str(&(
                                format!("struct {} {{\n{}}};\n",
                                        item.ident,
                                        fields.iter()
                                              .map(|f| map_field(f, &mut deps))
                                              .collect::<String>())));
                            results.lock().unwrap().ds.insert(
                                item.ident.to_string(),
                                ConvertedItem::new(c_code, deps));
                        }
                    }
                }
                ItemKind::Enum(ref variants, ref _generics) => {
                    writeln!(io::stderr(), "processing enum {}::{}", mod_name, &item.ident).unwrap();
                    if is_repr_u32(&item.attrs) {
                        let c_code = format!("enum class {}: uint32_t {{\n{}\n  Sentinel /* this must be last for serialization purposes. */\n}};\n",
                                             item.ident,
                                             variants.iter()
                                                     .fold((String::new(), -1), fold_enum_variants)
                                                     .0);
                        results.lock().unwrap().ds.insert(
                            item.ident.to_string(),
                            ConvertedItem::new(c_code, BTreeSet::new()));
                    }
                }
                _ => {}
            }
        }
    });
    for (_, converted) in &results.lock().unwrap().ds {
        println!("{}", converted.c_code);
    }
    for converted in &results.lock().unwrap().funcs {
        println!("{}", converted.c_code);
        // println!("// depends on {:?}", converted.deps);
    }
    //for (k, converted) in &results.lock().unwrap().ds {
    //    println!("// {} -> {:?}", k, converted.deps);
    //}
}
<commit_msg>Actually use the dep tree to only spit out structs and enums we care about<commit_after>use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::env;
use std::fmt;
use std::io;
use std::io::Write;
use std::sync::Mutex;

extern crate syn;
use syn::*;

mod rust_lib;

#[derive(Debug, Clone)]
struct ConvertedType {
    /// The type converted to C (e.g. `uint32_t`)
    prefix: String,
    /// Stuff that might need to go after the identifier (e.g. `[3]` for an array).
    postfix: String,
    /// The types this type depends upon. For example a `prefix` of
    /// Foo<Bar> would have both `Foo` and `Bar` in the `deps`.
    deps: BTreeSet<String>,
}

impl ConvertedType {
    fn append_prefix(&self, str: &str) -> ConvertedType {
        let mut clone = self.clone();
        clone.prefix.push_str(str);
        clone
    }

    fn append_postfix(&self, str: &str) -> ConvertedType {
        let mut clone = self.clone();
        clone.postfix.push_str(str);
        clone
    }

    fn add_dep(&self, dep: String) -> ConvertedType {
        let mut clone = self.clone();
        clone.deps.insert(dep);
        clone
    }

    fn format_with_ident(&self, ident: &Ident) -> String {
        format!("{} {}{}", &self.prefix, &ident.to_string(), &self.postfix)
    }
}

impl From<String> for ConvertedType {
    fn from(str: String) -> ConvertedType {
        let mut initial_set = BTreeSet::new();
        initial_set.insert(str.clone());
        ConvertedType {
            prefix: str,
            postfix: String::new(),
            deps: initial_set,
        }
    }
}

impl fmt::Display for ConvertedType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}{}", &self.prefix, &self.postfix)
    }
}

fn has_attribute(target: MetaItem, attrs: &Vec<Attribute>) -> bool {
    return attrs
               .iter()
               .any(|ref attr| attr.style == AttrStyle::Outer && attr.value == target);
}

fn has_no_mangle(attrs: &Vec<Attribute>) -> bool {
    has_attribute(MetaItem::Word(Ident::new("no_mangle")), attrs)
}

fn wr_func_body(attrs: &Vec<Attribute>) -> String {
    if has_attribute(MetaItem::Word(Ident::new("destructor_safe")), attrs) {
        String::from("WR_DESTRUCTOR_SAFE_FUNC")
    } else {
        String::from("WR_FUNC")
    }
}

fn is_repr_c(attrs: &Vec<Attribute>) -> bool {
    let repr_args = vec![NestedMetaItem::MetaItem(MetaItem::Word(Ident::new("C")))];
    has_attribute(MetaItem::List(Ident::new("repr"), repr_args), attrs)
}

fn is_repr_u32(attrs: &Vec<Attribute>) -> bool {
    let repr_args = vec![NestedMetaItem::MetaItem(MetaItem::Word(Ident::new("u32")))];
    has_attribute(MetaItem::List(Ident::new("repr"), repr_args), attrs)
}

fn is_c_abi(abi: &Option<Abi>) -> bool {
    abi == &Some(Abi::Named(String::from("C")))
}

fn map_path(p: &Path) -> ConvertedType {
    let l = p.segments[0].ident.to_string();
    let mut c = ConvertedType::from(match l.as_ref() {
        "usize" => "size_t".to_string(),
        "u8" => "uint8_t".to_string(),
        "u32" => "uint32_t".to_string(),
        "u64" => "uint64_t".to_string(),
        "i8" => "int8_t".to_string(),
        "i32" => "int32_t".to_string(),
        "i64" => "int64_t".to_string(),
        "f32" => "float".to_string(),
        "c_void" => "void".to_string(),
        _ => l,
    });
    if let PathParameters::AngleBracketed(ref d) = p.segments[0].parameters {
        let template_args = d.types
            .iter()
            .map(|ty| {
                let conv = map_ty(ty);
                c = c.add_dep(conv.to_string());
                conv.to_string()
            })
            .collect::<Vec<String>>()
            .join(", ");
        if !template_args.is_empty() {
            c = c.append_prefix(&format!("<{}>", &template_args));
        }
    }
    c
}

fn map_mut_ty(mut_ty: &MutTy) -> ConvertedType {
    map_ty(&mut_ty.ty)
}

fn map_ty(ty: &Ty) -> ConvertedType {
    match ty {
        &Ty::Path(_, ref p) => map_path(p),
        &Ty::Ptr(ref p) => map_ty(&p.ty).append_prefix("*"),
        &Ty::Rptr(_, ref mut_ty) => map_mut_ty(mut_ty).append_prefix("*"),
        &Ty::Array(ref p, ConstExpr::Lit(Lit::Int(sz, _))) => map_ty(&p).append_postfix(&format!("[{}]", sz)),
        _ => ConvertedType::from(format!("unknown {:?}", ty)),
    }
}

fn map_return_type(ret: &FunctionRetTy) -> ConvertedType {
    match ret {
        &FunctionRetTy::Default => ConvertedType::from("void".to_string()),
        &FunctionRetTy::Ty(ref ty) => map_ty(ty),
    }
}

fn map_arg(f: &FnArg, dep_set: &mut BTreeSet<String>) -> String {
    match f {
        &FnArg::Captured(Pat::Ident(_, ref ident, _), ref ty) => {
            let mut converted = map_ty(ty);
            dep_set.append(&mut converted.deps);
            converted.format_with_ident(ident)
        }
        _ => "unknown".to_string(),
    }
}

fn map_field(f: &Field, dep_set: &mut BTreeSet<String>) -> String {
    let mut ret = String::from("  ");
    let mut converted = map_ty(&f.ty);
    dep_set.append(&mut converted.deps);
    ret.push_str(&converted.format_with_ident(f.ident.as_ref().expect("Struct fields must have idents")));
    ret.push_str(";\n");
    ret
}

fn map_generic_param(t: &TyParam) -> String {
    let mut ret = String::from("typename ");
    ret.push_str(&t.ident.to_string());
    ret
}

fn fold_enum_variants(accum: (String, i32), v: &Variant) -> (String, i32) {
    // `accum` contains the combined string of converted enum variants so far, to which
    // we will append the converted version of `v`. The other thing in `accum` is the
    // value of the previous variant. If `v` has an explicit value we keep that, otherwise
    // we increment the value of the previous variant to get the new one. This is all
    // so that we properly support enums with explicitly-specified and discontinuous
    // values.
    let mut ret = accum.0;
    ret.push_str("  ");
    ret.push_str(&v.ident.to_string());
    ret.push_str(" = ");
    let new_value = match &v.discriminant {
        &None => accum.1 + 1,
        &Some(ConstExpr::Lit(Lit::Int(ref specified_value, _))) => *specified_value as i32,
        &Some(_) => {
            // we don't handle this yet, so just put in something that will fail C compilation
            writeln!(io::stderr(), "warning, unsupported enum discriminant").unwrap();
            ret.push_str("???");
            accum.1 + 1
        }
    };
    ret.push_str(&new_value.to_string());
    ret.push_str(",\n");
    (ret, new_value)
}

struct ConvertedItem {
    /// This holds the C code that needs to go into the header file.
    c_code: String,
    /// This holds a set of identifiers that the C code depends on.
    /// So for example if a struct A contains another struct B, the
    /// `ConvertedItem` instance for A will have the string "B" in
    /// `deps`.
    deps: BTreeSet<String>,
}

impl ConvertedItem {
    fn new(c_code: String, deps: BTreeSet<String>) -> ConvertedItem {
        ConvertedItem {
            c_code: c_code,
            deps: deps,
        }
    }
}

/// A structure to store all the results of converting Rust stuff to C
/// stuff, so that we can pick and choose what we output.
struct ConversionResults {
    /// This holds the C function signatures of no_mangle rust functions,
    /// in the order that they were encountered in Rust.
    funcs: Vec<ConvertedItem>,
    /// This holds the C conversions of repr(C) structs and repr(u32) enums
    /// from Rust. The 'ds' in the name stands for 'data structures'. The
    /// key of the map is the name of the type.
    ds: BTreeMap<String, ConvertedItem>,
}

fn collect_deps(dst: &mut BTreeSet<String>, results_ref: &ConversionResults, deps: &BTreeSet<String>) {
    for dep in deps {
        dst.insert(dep.to_string());
        results_ref.ds.get(dep).map(|converted| collect_deps(dst, results_ref, &converted.deps));
    }
}

fn main() {
    let p = env::args().nth(1).unwrap();

    let results = Mutex::new(ConversionResults {
        funcs: Vec::new(),
        ds: BTreeMap::new(),
    });

    rust_lib::parse(p, &|mod_name, items| {
        for item in items {
            match item.node {
                ItemKind::Fn(ref decl,
                             ref _unsafe,
                             ref _const,
                             ref abi,
                             ref _generic,
                             ref _block) => {
                    writeln!(io::stderr(), "processing function {}::{}", mod_name, &item.ident).unwrap();
                    if has_no_mangle(&item.attrs) && is_c_abi(&abi) {
                        let mut deps = BTreeSet::new();
                        let mut return_type = map_return_type(&decl.output);
                        deps.append(&mut return_type.deps);
                        let c_code =
                            format!("WR_INLINE {}\n{}({})\n{};\n",
                                    return_type,
                                    item.ident,
                                    decl.inputs
                                        .iter()
                                        .map(|f| map_arg(f, &mut deps))
                                        .collect::<Vec<_>>()
                                        .join(", "),
                                    wr_func_body(&item.attrs));
                        results.lock().unwrap().funcs.push(ConvertedItem::new(c_code, deps));
                    }
                }
                ItemKind::Struct(ref variant,
                                 ref generics) => {
                    writeln!(io::stderr(), "processing struct {}::{}", mod_name, &item.ident).unwrap();
                    if is_repr_c(&item.attrs) {
                        if let &VariantData::Struct(ref fields) = variant {
                            let mut deps = BTreeSet::new();
                            let mut c_code = String::new();
                            if !generics.ty_params.is_empty() {
                                c_code.push_str(&(
                                    format!("template<{}>\n",
                                            generics.ty_params
                                                    .iter()
                                                    .map(map_generic_param)
                                                    .collect::<Vec<_>>()
                                                    .join(", "))));
                            }
                            c_code.push_str(&(
                                format!("struct {} {{\n{}}};\n",
                                        item.ident,
                                        fields.iter()
                                              .map(|f| map_field(f, &mut deps))
                                              .collect::<String>())));
                            results.lock().unwrap().ds.insert(
                                item.ident.to_string(),
                                ConvertedItem::new(c_code, deps));
                        }
                    }
                }
                ItemKind::Enum(ref variants, ref _generics) => {
                    writeln!(io::stderr(), "processing enum {}::{}", mod_name, &item.ident).unwrap();
                    if is_repr_u32(&item.attrs) {
                        let c_code = format!("enum class {}: uint32_t {{\n{}\n  Sentinel /* this must be last for serialization purposes. */\n}};\n",
                                             item.ident,
                                             variants.iter()
                                                     .fold((String::new(), -1), fold_enum_variants)
                                                     .0);
                        results.lock().unwrap().ds.insert(
                            item.ident.to_string(),
                            ConvertedItem::new(c_code, BTreeSet::new()));
                    }
                }
                _ => {}
            }
        }
    });

    let mut all_func_deps = BTreeSet::new();
    let results_ref = &results.lock().unwrap();
    for converted in &results_ref.funcs {
        collect_deps(&mut all_func_deps, results_ref, &converted.deps);
    }
    for dep in all_func_deps {
        results_ref.ds.get(&dep).map(|converted| println!("{}", converted.c_code));
    }
    for converted in &results_ref.funcs {
        println!("{}", converted.c_code);
    }
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate mount;
extern crate staticfile;
extern crate urlencoded;

use std::path::Path;
use std::io::Read;

use iron::prelude::*;
use iron::status;
use mount::Mount;
use staticfile::Static;
use urlencoded::UrlEncodedBody;

fn hello_world(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "Hello World!")))
}

fn charge(req: &mut Request) -> IronResult<Response> {
    let mut buf: Vec<u8> = vec![];
    match req.get_ref::<UrlEncodedBody>() {
        Ok(ref hashmap) => println!("Parsed POST request body string:\n {:?}", hashmap),
        Err(ref e) => return Ok(Response::with((status::InternalServerError, e.to_string()))),
    };

    Ok(Response::with((status::Ok, "Got it")))

}

fn main() {
    let mut mount = Mount::new();

    mount.mount("/", Static::new(Path::new("static")));
    mount.mount("/hello", hello_world);
    mount.mount("/charge", charge);

    Iron::new(mount).http("localhost:3000").unwrap();
}
<commit_msg>Enough plumbing to create a customer from checkout<commit_after>extern crate stripe;
extern crate iron;
extern crate mount;
extern crate staticfile;
extern crate urlencoded;

use std::path::Path;
use std::io::Read;
use std::env;

use iron::prelude::*;
use iron::status;
use mount::Mount;
use staticfile::Static;
use urlencoded::UrlEncodedBody;

use stripe::connection::Connection;
use stripe::customer::Customer;

fn hello_world(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "Hello World!")))
}

fn get_conn() -> Connection {
    let secret_key: String = env::var("STRIPE_SECRET_KEY").ok().expect("No STRIPE_SECRET_KEY set");
    return Connection::new(secret_key);
}

fn charge(req: &mut Request) -> IronResult<Response> {
    let mut buf: Vec<u8> = vec![];
    match req.get_ref::<UrlEncodedBody>() {
        Ok(ref hashmap) => {
            let email = hashmap.get("stripeEmail").unwrap()[0].clone();
            let token = hashmap.get("stripeToken").unwrap()[0].clone();

            let customer = Customer::create(get_conn(), email, token);
        },
        Err(ref e) => return Ok(Response::with((status::InternalServerError, e.to_string()))),
    };

    Ok(Response::with((status::Ok, "Got it")))

}

fn main() {
    let mut mount = Mount::new();

    mount.mount("/", Static::new(Path::new("static")));
    mount.mount("/hello", hello_world);
    mount.mount("/charge", charge);

    Iron::new(mount).http("localhost:3000").unwrap();
}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;
use std::iter::repeat;
use std::str::FromStr;

enum Hamming { Encode, Decode, EncodeBinary, DecodeBinary }

fn main() {
    let title = "RUSTYHAM: A HAMMING CODE GENERATOR IN RUST";
    let border: String = repeat('=').take(title.len()).collect::<>();
    println!("{}", border);
    println!("{}", title);
    println!("{}", border);

    loop {
        let mut linebuf = String::new();
        println!("(1) Encode ASCII");
        println!("(2) Encode binary");
        println!("(3) Decode to ASCII");
        println!("(4) Decode to binary");
        print!("Enter your choice: ");
        io::stdout().flush().unwrap();
        io::stdin().read_line(&mut linebuf).unwrap();

        let num = i32::from_str(linebuf.trim());
        match num.ok() {
            Some(n) => {
                let mut good = true;
                println!("{}", match n {
                    1 => hamming(Hamming::Encode, prompt("Enter string to encode: ")),
                    2 => hamming(Hamming::EncodeBinary, prompt("Enter binary string to encode: ")),
                    3 => hamming(Hamming::Decode, prompt("Enter Hamming code to decode: ")),
                    4 => hamming(Hamming::DecodeBinary, prompt("Enter Hamming code to decode to binary: ")),
                    _ => { good = false; "Invalid input.".to_string() }
                });
                if good { break; }
            }
            None => {
                println!("Invalid input.");
            }
        };
    }
}

fn hamming(action: Hamming, s: String) -> String {
    match action {
        Hamming::Encode | Hamming::EncodeBinary => {
            // get an iterator over the individual bits
            let mut bytes;
            let bytes_str = match action {
                Hamming::EncodeBinary => s,
                _ => {
                    // convert ASCII string to binary
                    bytes = s.into_bytes();  // takes ownership of s
                    bytes.iter().map(|&c| format!("{:0>1$b}", c, 7))
                        .collect::<Vec<String>>().concat()
                }
            };
            let mut bytes_iter = bytes_str.chars();
            // we should assume that ownership of s has already been
            // transferred away by this point

            // compute block and message length
            let mlen = bytes_str.len() as u32;
            let lenpow = (2..).find(|&r| 2u32.pow(r) - r - 1 >= mlen).unwrap();
            let len = 2us.pow(lenpow) - 1;

            // the thing we're storing the hamming code in
            let mut code: Vec<bool> = repeat(false).take(len).collect::<>();

            // set data bits
            for i in 1..len {
                if (i & (i - 1)) != 0 {  // if i is not a power of 2
                    code[i-1] = bytes_iter.next().unwrap_or('0') == '1';
                }
            }

            // set parity bits
            for i in 0..lenpow {
                code[2us.pow(i) - 1] = calc_parity(&code, i);
            }

            code.into_iter().map(|x| if x {"1"} else {"0"}).collect::<Vec<_>>().concat()
        },
        Hamming::Decode | Hamming::DecodeBinary => {
            // verify parity bits, fix 1-bit-flipped errors if any
            let len = s.len();
            let lenpow = ((len + 1) as f32).sqrt().round() as u32;
            let mut chars = s.chars().map(|x| x == '1').collect::<Vec<bool>>();
            let mut flipped_bit = -1i32;
            while (0..lenpow).any(|i| calc_parity(&chars, i)) {
                if flipped_bit != -1 {
                    chars[flipped_bit as usize] = !chars[flipped_bit as usize];
                }
                flipped_bit += 1;
                chars[flipped_bit as usize] = !chars[flipped_bit as usize];
            }

            // collect all bits at non-powers-of-2
            let data = chars.iter().enumerate()
                .filter(|x| ((x.0 + 1) & x.0) != 0).map(|x| if *x.1 {'1'} else {'0'});

            // return
            match action {
                Hamming::DecodeBinary => {
                    data.collect::<String>()
                },
                _ => {
                    let chars = (&data.collect::<Vec<char>>()[..]).chunks(7)
                        .map(|x| u8::from_str_radix(&x.iter().cloned().collect::<String>()[..], 2).unwrap())
                        .collect::<Vec<u8>>();
                    String::from_utf8(chars).unwrap()
                }
            }
        }
    }
}

fn calc_parity(code: &Vec<bool>, i: u32) -> bool {
    let bi = 2us.pow(i) - 1;
    let (mut parity, mut ignore, mut counter) = (false, false, 0);
    for j in bi..code.len() {
        if !ignore && code[j] { parity = !parity }
        counter += 1;
        if counter >= 2u32.pow(i) {
            ignore = !ignore;
            counter = 0;
        }
    }
    parity
}

fn prompt(s: &str) -> String {
    let mut input = String::new();
    print!("{}", s);
    io::stdout().flush().unwrap();
    io::stdin().read_line(&mut input).unwrap();
    input.trim().to_string()
}
<commit_msg>cut down on a few super long lines<commit_after>use std::io;
use std::io::prelude::*;
use std::iter::repeat;
use std::str::FromStr;

enum Hamming { Encode, Decode, EncodeBinary, DecodeBinary }

fn main() {
    let title = "RUSTYHAM: A HAMMING CODE GENERATOR IN RUST";
    let border: String = repeat('=').take(title.len()).collect::<>();
    println!("{}", border);
    println!("{}", title);
    println!("{}", border);

    loop {
        let mut linebuf = String::new();
        println!("(1) Encode ASCII");
        println!("(2) Encode binary");
        println!("(3) Decode to ASCII");
        println!("(4) Decode to binary");
        print!("Enter your choice: ");
        io::stdout().flush().unwrap();
        io::stdin().read_line(&mut linebuf).unwrap();

        let num = i32::from_str(linebuf.trim());
        match num.ok() {
            Some(n) => {
                let mut good = true;
                println!("{}", match n {
                    1 => hamming(Hamming::Encode, prompt("Enter string to encode: ")),
                    2 => hamming(Hamming::EncodeBinary, prompt("Enter binary string to encode: ")),
                    3 => hamming(Hamming::Decode, prompt("Enter Hamming code to decode: ")),
                    4 => hamming(Hamming::DecodeBinary, prompt("Enter Hamming code to decode to binary: ")),
                    _ => { good = false; "Invalid input.".to_string() }
                });
                if good { break; }
            }
            None => {
                println!("Invalid input.");
            }
        };
    }
}

fn hamming(action: Hamming, s: String) -> String {
    match action {
        Hamming::Encode | Hamming::EncodeBinary => {
            // get an iterator over the individual bits
            let mut bytes;
            let bytes_str = match action {
                Hamming::EncodeBinary => s,
                _ => {
                    // convert ASCII string to binary
                    bytes = s.into_bytes();  // takes ownership of s
                    bytes.iter().map(|&c| format!("{:0>1$b}", c, 7))
                        .collect::<Vec<String>>().concat()
                }
            };
            let mut bytes_iter = bytes_str.chars();
            // we should assume that ownership of s has already been
            // transferred away by this point

            // compute block and message length
            let mlen = bytes_str.len() as u32;
            let lenpow = (2..).find(|&r| 2u32.pow(r) - r - 1 >= mlen).unwrap();
            let len = 2us.pow(lenpow) - 1;

            // the thing we're storing the hamming code in
            let mut code: Vec<bool> = repeat(false).take(len).collect();

            // set data bits
            for i in 1..len {
                if (i & (i - 1)) != 0 {  // if i is not a power of 2
                    code[i-1] = bytes_iter.next().unwrap_or('0') == '1';
                }
            }

            // set parity bits
            for i in 0..lenpow {
                code[2us.pow(i) - 1] = calc_parity(&code, i);
            }

            code.into_iter().map(|x| if x {"1"} else {"0"})
                .collect::<Vec<_>>().concat()
        },
        Hamming::Decode | Hamming::DecodeBinary => {
            // verify parity bits, fix 1-bit-flipped errors if any
            let len = s.len();
            let lenpow = ((len + 1) as f32).sqrt().round() as u32;
            let mut chars = s.chars().map(|x| x == '1').collect::<Vec<bool>>();
            let mut flipped_bit = -1i32;
            while (0..lenpow).any(|i| calc_parity(&chars, i)) {
                if flipped_bit != -1 {
                    chars[flipped_bit as usize] = !chars[flipped_bit as usize];
                }
                flipped_bit += 1;
                chars[flipped_bit as usize] = !chars[flipped_bit as usize];
            }

            // collect all bits at non-powers-of-2
            let data = chars.iter().enumerate()
                .filter(|x| ((x.0 + 1) & x.0) != 0)
                .map(|x| if *x.1 {'1'} else {'0'});

            // return
            match action {
                Hamming::DecodeBinary => {
                    data.collect::<String>()
                },
                _ => {
                    let chars = (&data.collect::<Vec<char>>()[..]).chunks(7)
                        .map(|x| {
                            let ss = &x.iter().cloned().collect::<String>()[..];
                            u8::from_str_radix(ss, 2).unwrap()
                        })
                        .collect::<Vec<u8>>();
                    String::from_utf8(chars).unwrap()
                }
            }
        }
    }
}

fn calc_parity(code: &Vec<bool>, i: u32) -> bool {
    let bi = 2us.pow(i) - 1;
    let (mut parity, mut ignore, mut counter) = (false, false, 0);
    for j in bi..code.len() {
        if !ignore && code[j] { parity = !parity }
        counter += 1;
        if counter >= 2u32.pow(i) {
            ignore = !ignore;
            counter = 0;
        }
    }
    parity
}

fn prompt(s: &str) -> String {
    let mut input = String::new();
    print!("{}", s);
    io::stdout().flush().unwrap();
    io::stdin().read_line(&mut input).unwrap();
    input.trim().to_string()
}
<|endoftext|>


<commit_before>extern crate docopt;
extern crate iron;
extern crate ladaemon;
#[macro_use(router)]
extern crate router;
extern crate rustc_serialize;

use docopt::Docopt;
use iron::Iron;
use std::str::FromStr;

/// Defines the program's version, as set by Cargo at compile time.
const VERSION: &'static str = env!("CARGO_PKG_VERSION");

/// Defines the program's usage string.
///
/// [Docopt](http://docopt.org) parses this and generates a custom argv parser.
const USAGE: &'static str = r#"
Let's Auth.

Usage:
  ladaemon [options] CONFIG
  ladaemon --version
  ladaemon --help

Options:
  --address=<ip>  Address to listen on [default: 127.0.0.1]
  --port=<port>   Port to listen on [default: 3333]
  --version       Print version information and exit
  --help          Print this help message and exit
"#;

/// Holds parsed command line parameters.
#[derive(RustcDecodable)]
#[allow(non_snake_case)]
struct Args {
    arg_CONFIG: String,
    flag_address: String,
    flag_port: u16,
}

/// The `main()` method. Will loop forever to serve HTTP requests.
fn main() {
    let args: Args = Docopt::new(USAGE)
                         .and_then(|d| d.version(Some(VERSION.to_string())).decode())
                         .unwrap_or_else(|e| e.exit());

    // Read the configuration from the provided file.
    let app = ladaemon::AppConfig::from_json_file(&args.arg_CONFIG);

    // Register all handlers with a router object. TODO: cloning the
    // configuration object is kind of ugly, but is apparently needed with
    // the way the Iron `Handler` trait is defined. Also, it would be cleaner
    // if the handlers could just be a function, instead of single-method
    // impls.
    let router = router!{

        // Human-targeted endpoints
        get "/" => ladaemon::WelcomeHandler { app: app.clone() },
        get "/confirm" => ladaemon::ConfirmHandler { app: app.clone() },

        // OpenID Connect provider endpoints
        get "/.well-known/openid-configuration" =>
               ladaemon::OIDConfigHandler { app: app.clone() },
        get "/keys.json" => ladaemon::KeysHandler { app: app.clone() },
        post "/auth" => ladaemon::AuthHandler { app: app.clone() },

        // OpenID Connect relying party endpoints
        get "/callback" => ladaemon::CallbackHandler { app: app.clone() },

    };

    let ip_address = std::net::IpAddr::from_str(&args.flag_address).unwrap();
    let socket = std::net::SocketAddr::new(ip_address, args.flag_port);

    println!("Listening on http://{}", socket);

    Iron::new(router).http("0.0.0.0:3333").unwrap();
}
<commit_msg>Reflow comment<commit_after>extern crate docopt;
extern crate iron;
extern crate ladaemon;
#[macro_use(router)]
extern crate router;
extern crate rustc_serialize;

use docopt::Docopt;
use iron::Iron;
use std::str::FromStr;

/// Defines the program's version, as set by Cargo at compile time.
const VERSION: &'static str = env!("CARGO_PKG_VERSION");

/// Defines the program's usage string.
///
/// [Docopt](http://docopt.org) parses this and generates a custom argv parser.
const USAGE: &'static str = r#"
Let's Auth.

Usage:
  ladaemon [options] CONFIG
  ladaemon --version
  ladaemon --help

Options:
  --address=<ip>  Address to listen on [default: 127.0.0.1]
  --port=<port>   Port to listen on [default: 3333]
  --version       Print version information and exit
  --help          Print this help message and exit
"#;

/// Holds parsed command line parameters.
#[derive(RustcDecodable)]
#[allow(non_snake_case)]
struct Args {
    arg_CONFIG: String,
    flag_address: String,
    flag_port: u16,
}

/// The `main()` method. Will loop forever to serve HTTP requests.
fn main() {
    let args: Args = Docopt::new(USAGE)
                         .and_then(|d| d.version(Some(VERSION.to_string())).decode())
                         .unwrap_or_else(|e| e.exit());

    // Read the configuration from the provided file.
    let app = ladaemon::AppConfig::from_json_file(&args.arg_CONFIG);

    // TODO: cloning the configuration object is ugly, but apparently necessary
    // with how the Iron `Handler` trait is defined. Also, it would be cleaner
    // if the handlers could just be functions, instead of single-method impls.
    let router = router!{
        // Human-targeted endpoints
        get "/" => ladaemon::WelcomeHandler { app: app.clone() },
        get "/confirm" => ladaemon::ConfirmHandler { app: app.clone() },

        // OpenID Connect provider endpoints
        get "/.well-known/openid-configuration" =>
               ladaemon::OIDConfigHandler { app: app.clone() },
        get "/keys.json" => ladaemon::KeysHandler { app: app.clone() },
        post "/auth" => ladaemon::AuthHandler { app: app.clone() },

        // OpenID Connect relying party endpoints
        get "/callback" => ladaemon::CallbackHandler { app: app.clone() },
    };

    let ip_address = std::net::IpAddr::from_str(&args.flag_address).unwrap();
    let socket = std::net::SocketAddr::new(ip_address, args.flag_port);

    println!("Listening on http://{}", socket);

    Iron::new(router).http("0.0.0.0:3333").unwrap();
}
<|endoftext|>


<commit_before>extern crate liner;

use liner::Context;
use liner::KeyBindings;
use std::collections::HashMap;
use std::io::ErrorKind;

fn main() {
    let mut cache: HashMap<String, String> = HashMap::new();

    let empty_value = String::from("");

    let mut con = Context::new();

    loop {
        let res = con.read_line("> ", &mut |_| {});

        match res {
            Ok(res) => {
                match res.as_str() {
                    "emacs" => {
                        con.key_bindings = KeyBindings::Emacs;
                        println!("emacs mode");
                    }
                    "vi" | "vim" =>  {
                        con.key_bindings = KeyBindings::Vi;
                        println!("vi mode");
                    }
                    s if s.starts_with("get ") =>  {
                        let (_, key) = s.split_at(4);
                        let key_trimmed = String::from(key.trim());
                        println!("{}", cache.get(&key_trimmed).unwrap_or(&empty_value));
                    }
                    s if s.starts_with("set ") =>  {
                        let (_, key_value) = s.split_at(4);
                        match key_value.find(' ') {
                            Some(i) => {
                                let (key, value) = key_value.split_at(i);
                                let key_trimmed = String::from(key.trim());
                                let value_trimmed = String::from(value.trim());
                                cache.insert(key_trimmed, value_trimmed);
                            }
                            None => println!("no value specified")
                        }
                    }
                    "exit" =>  {
                        break;
                    }
                    _ => {}
                }

                con.history.push(res.into()).unwrap();
            }
            Err(e) => {
                match e.kind() {
                    // ctrl-c pressed
                    ErrorKind::Interrupted => {}
                    // ctrl-d pressed
                    ErrorKind::UnexpectedEof => {
                        break;
                    }
                    _ => panic!("error: {:?}", e),
                }
            }
        }
    }
}
<commit_msg>Box cache store<commit_after>extern crate liner;

use liner::Context;
use liner::KeyBindings;
use std::collections::HashMap;
use std::io::ErrorKind;

fn main() {
    let mut cache = Box::new(HashMap::new());

    let empty_value = String::from("");

    let mut con = Context::new();

    loop {
        let res = con.read_line("> ", &mut |_| {});

        match res {
            Ok(res) => {
                match res.as_str() {
                    "emacs" => {
                        con.key_bindings = KeyBindings::Emacs;
                        println!("emacs mode");
                    }
                    "vi" | "vim" =>  {
                        con.key_bindings = KeyBindings::Vi;
                        println!("vi mode");
                    }
                    s if s.starts_with("get ") =>  {
                        let (_, key) = s.split_at(4);
                        let key_trimmed = String::from(key.trim());
                        println!("{}", cache.get(&key_trimmed).unwrap_or(&empty_value));
                    }
                    s if s.starts_with("set ") =>  {
                        let (_, key_value) = s.split_at(4);
                        match key_value.find(' ') {
                            Some(i) => {
                                let (key, value) = key_value.split_at(i);
                                let key_trimmed = String::from(key.trim());
                                let value_trimmed = String::from(value.trim());
                                cache.insert(key_trimmed, value_trimmed);
                            }
                            None => println!("no value specified")
                        }
                    }
                    "exit" =>  {
                        break;
                    }
                    _ => {}
                }

                con.history.push(res.into()).unwrap();
            }
            Err(e) => {
                match e.kind() {
                    // ctrl-c pressed
                    ErrorKind::Interrupted => {}
                    // ctrl-d pressed
                    ErrorKind::UnexpectedEof => {
                        break;
                    }
                    _ => panic!("error: {:?}", e),
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate arguments;
extern crate temporary;

use std::collections::HashMap;
use std::fmt::Display;
use std::fs::File;
use std::io::{stderr, stdout, Read, Write};
use std::process::Command;
use temporary::Directory;

const USAGE: &'static str = "
Usage: cite [options]

Options:
    --bib <FILE>       A bibliography file (required).
    --ref <NAME>       A reference name (required).
    --tex <FILE>       A template file.

    --help             Display this message.
";

const TEMPLATE: &'static str = r#"
\documentclass[journal]{IEEEtran}
\pagestyle{empty}
\renewcommand{\refname}{}

\begin{document}
\nocite{<reference>}
\bibliography{IEEEabrv,<bibliography>}
\bibliographystyle{IEEEtran}
\end{document}
"#;

macro_rules! ok(
    ($result:expr) => (match $result {
        Ok(result) => result,
        Err(error) => raise!(error),
    });
);

macro_rules! raise(
    ($error:expr) => (return Err(Box::new($error)));
    ($($arg:tt)*) => (raise!(format!($($arg)*)));
);

pub type Error = Box<Display>;
pub type Result<T> = std::result::Result<T, Error>;

fn main() {
    start().unwrap_or_else(|error| fail(error));
}

fn start() -> Result<()> {
    let arguments = match arguments::parse(std::env::args()) {
        Ok(arguments) => arguments,
        Err(error) => raise!(error),
    };

    if arguments.get::<bool>("help").unwrap_or(false) {
        help();
    }

    let bibliography = match arguments.get::<String>("bib") {
        Some(bibliography) => bibliography,
        _ => raise!("a bibliography file is required"),
    };
    let reference = match arguments.get::<String>("ref") {
        Some(reference) => reference,
        _ => raise!("a reference name is required"),
    };

    match arguments.get::<String>("tex") {
        Some(ref template) => {
            let mut file = ok!(File::open(template));
            let mut template = String::new();
            ok!(file.read_to_string(&mut template));
            process(&template, &bibliography, &reference)
        },
        _ => {
            process(TEMPLATE, &bibliography, &reference)
        },
    }
}

fn process(template: &str, bibliography: &str, reference: &str) -> Result<()> {
    let root = ok!(Directory::new("cite"));

    macro_rules! run(
        ($program:expr, $argument:expr) => ({
            let mut command = Command::new($program);
            command.arg($argument).current_dir(&root);
            let output = match command.output() {
                Ok(output) => output,
                Err(error) => raise!(format!("`{}` has failed: {}", $program, error)),
            };
            if !output.status.success() {
                let _ = stdout().write_all(&output.stdout);
                let _ = stderr().write_all(&output.stderr);
                raise!(format!("`{}` has failed", $program));
            }
        });
    );

    {
        let mut map = HashMap::new();
        map.insert("<bibliography>", bibliography);
        map.insert("<reference>", reference);
        let tex = replace(template, &map);

        let mut file = ok!(File::create(root.join("paper.tex")));
        ok!(file.write_all(tex.as_bytes()));
    }

    run!("latex", "paper.tex");
    run!("bibtex", "paper");
    run!("latex", "paper.tex");
    run!("latex", "paper.tex");
    run!("dvipdf", "paper.dvi");
    run!("pdftotext", "paper.pdf");

    let mut buffer = Vec::new();
    {
        let mut file = ok!(File::open(root.join("paper.txt")));
        ok!(file.read_to_end(&mut buffer));
    }

    let content = String::from_utf8_lossy(&buffer);
    println!("{}", content.trim());

    Ok(())
}

fn replace(text: &str, map: &HashMap<&str, &str>) -> String {
    let mut text = text.to_string();
    for (key, value) in map {
        text = text.replace(key, value);
    }
    text
}

fn help() -> ! {
    println!("{}", USAGE.trim());
    std::process::exit(0);
}

fn fail(error: Error) -> ! {
    let message = format!("Error: {}.\n{}", &*error, USAGE);
    let _ = stderr().write_all(message.as_bytes());
    std::process::exit(1);
}
<commit_msg>Implement the ability to copy-past bibliographies<commit_after>extern crate arguments;
extern crate temporary;

use std::collections::HashMap;
use std::fmt::Display;
use std::fs::File;
use std::io::{stderr, stdin, stdout, Read, Write};
use std::path::Path;
use std::process::Command;
use temporary::Directory;

const USAGE: &'static str = "
Usage: cite [options]

Options:
    --bib <FILE>       A bibliography file.
    --ref <NAME>       A reference name.
    --tex <FILE>       A template file.

    --help             Display this message.
";

const TEMPLATE: &'static str = r#"
\documentclass[journal]{IEEEtran}
\pagestyle{empty}
\renewcommand{\refname}{}

\begin{document}
\nocite{<reference>}
\bibliography{IEEEabrv,<bibliography>}
\bibliographystyle{IEEEtran}
\end{document}
"#;

macro_rules! ok(
    ($result:expr) => (match $result {
        Ok(result) => result,
        Err(error) => raise!(error),
    });
);

macro_rules! raise(
    ($error:expr) => (return Err(Box::new($error)));
    ($($arg:tt)*) => (raise!(format!($($arg)*)));
);

pub type Error = Box<Display>;
pub type Result<T> = std::result::Result<T, Error>;

fn main() {
    start().unwrap_or_else(|error| fail(error));
}

fn start() -> Result<()> {
    let arguments = match arguments::parse(std::env::args()) {
        Ok(arguments) => arguments,
        Err(error) => raise!(error),
    };

    if arguments.get::<bool>("help").unwrap_or(false) {
        help();
    }

    let root = ok!(Directory::new("cite"));

    let bibliography = match arguments.get::<String>("bib") {
        Some(bibliography) => bibliography,
        _ => try!(create_bibliography(&root)),
    };
    let reference = match arguments.get::<String>("ref") {
        Some(reference) => reference,
        _ => raise!("a reference name is required"),
    };

    match arguments.get::<String>("tex") {
        Some(ref template) => {
            let mut file = ok!(File::open(template));
            let mut template = String::new();
            ok!(file.read_to_string(&mut template));
            process(&template, &bibliography, &reference, &root)
        },
        _ => {
            process(TEMPLATE, &bibliography, &reference, &root)
        },
    }
}

fn process(template: &str, bibliography: &str, reference: &str, root: &Path) -> Result<()> {
    macro_rules! run(
        ($program:expr, $argument:expr) => ({
            let mut command = Command::new($program);
            command.arg($argument).current_dir(&root);
            let output = match command.output() {
                Ok(output) => output,
                Err(error) => raise!(format!("`{}` has failed: {}", $program, error)),
            };
            if !output.status.success() {
                let _ = stdout().write_all(&output.stdout);
                let _ = stderr().write_all(&output.stderr);
                raise!(format!("`{}` has failed", $program));
            }
        });
    );

    {
        let mut map = HashMap::new();
        map.insert("<bibliography>", bibliography);
        map.insert("<reference>", reference);
        let tex = replace(template, &map);

        let mut file = ok!(File::create(root.join("paper.tex")));
        ok!(file.write_all(tex.as_bytes()));
    }

    run!("latex", "paper.tex");
    run!("bibtex", "paper");
    run!("latex", "paper.tex");
    run!("latex", "paper.tex");
    run!("dvipdf", "paper.dvi");
    run!("pdftotext", "paper.pdf");

    let mut buffer = Vec::new();
    {
        let mut file = ok!(File::open(root.join("paper.txt")));
        ok!(file.read_to_end(&mut buffer));
    }

    let content = String::from_utf8_lossy(&buffer);
    println!("{}", content.trim());

    Ok(())
}

fn create_bibliography(root: &Path) -> Result<String> {
    println!("Paste a bibliography content and press Ctrl-D:");
    let mut content = String::new();
    ok!(stdin().read_to_string(&mut content));

    let mut file = ok!(File::create(root.join("paper.bib")));
    ok!(file.write_all(content.as_bytes()));

    Ok(String::from("paper.bib"))
}

fn replace(text: &str, map: &HashMap<&str, &str>) -> String {
    let mut text = text.to_string();
    for (key, value) in map {
        text = text.replace(key, value);
    }
    text
}

fn help() -> ! {
    println!("{}", USAGE.trim());
    std::process::exit(0);
}

fn fail(error: Error) -> ! {
    let message = format!("Error: {}.\n{}", &*error, USAGE);
    let _ = stderr().write_all(message.as_bytes());
    std::process::exit(1);
}
<|endoftext|>


<commit_before>use std::fmt;
use std::io::{self, Read, Write, Cursor};
use std::net::SocketAddr;
use std::sync::mpsc::Sender;

use net::{NetworkStream, NetworkConnector, ContextVerifier};

pub struct MockStream {
    pub read: Cursor<Vec<u8>>,
    pub write: Vec<u8>,
}

impl Clone for MockStream {
    fn clone(&self) -> MockStream {
        MockStream {
            read: Cursor::new(self.read.get_ref().clone()),
            write: self.write.clone()
        }
    }
}

impl fmt::Debug for MockStream {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MockStream {{ read: {:?}, write: {:?} }}", self.read.get_ref(), self.write)
    }
}

impl PartialEq for MockStream {
    fn eq(&self, other: &MockStream) -> bool {
        self.read.get_ref() == other.read.get_ref() && self.write == other.write
    }
}

impl MockStream {
    pub fn new() -> MockStream {
        MockStream {
            read: Cursor::new(vec![]),
            write: vec![],
        }
    }

    pub fn with_input(input: &[u8]) -> MockStream {
        MockStream {
            read: Cursor::new(input.to_vec()),
            write: vec![]
        }
    }
}

impl Read for MockStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.read.read(buf)
    }
}

impl Write for MockStream {
    fn write(&mut self, msg: &[u8]) -> io::Result<usize> {
        Write::write(&mut self.write, msg)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl NetworkStream for MockStream {
    fn peer_addr(&mut self) -> io::Result<SocketAddr> {
        Ok("127.0.0.1:1337".parse().unwrap())
    }
}

pub struct MockConnector;

impl NetworkConnector for MockConnector {
    type Stream = MockStream;

    fn connect(&self, _host: &str, _port: u16, _scheme: &str) -> ::Result<MockStream> {
        Ok(MockStream::new())
    }

    fn set_ssl_verifier(&mut self, _verifier: ContextVerifier) {
        // pass
    }
}

/// A mock implementation of the `NetworkConnector` trait that keeps track of all calls to its
/// methods by sending corresponding messages onto a channel.
///
/// Otherwise, it behaves the same as `MockConnector`.
pub struct ChannelMockConnector {
    calls: Sender<String>,
}

impl ChannelMockConnector {
    pub fn new(calls: Sender<String>) -> ChannelMockConnector {
        ChannelMockConnector { calls: calls }
    }
}

impl NetworkConnector for ChannelMockConnector {
    type Stream = MockStream;
    #[inline]
    fn connect(&mut self, _host: &str, _port: u16, _scheme: &str)
            -> ::Result<MockStream> {
        self.calls.send("connect".into()).unwrap();
        Ok(MockStream::new())
    }

    #[inline]
    fn set_ssl_verifier(&mut self, _verifier: ContextVerifier) {
        self.calls.send("set_ssl_verifier".into()).unwrap();
    }
}

/// new connectors must be created if you wish to intercept requests.
macro_rules! mock_connector (
    ($name:ident {
        $($url:expr => $res:expr)*
    }) => (

        struct $name;

        impl ::net::NetworkConnector for $name {
            type Stream = ::mock::MockStream;
            fn connect(&self, host: &str, port: u16, scheme: &str) -> $crate::Result<::mock::MockStream> {
                use std::collections::HashMap;
                use std::io::Cursor;
                debug!("MockStream::connect({:?}, {:?}, {:?})", host, port, scheme);
                let mut map = HashMap::new();
                $(map.insert($url, $res);)*

                let key = format!("{}://{}", scheme, host);
                // ignore port for now
                match map.get(&*key) {
                    Some(res) => Ok($crate::mock::MockStream {
                        write: vec![],
                        read: Cursor::new(res.to_string().into_bytes()),
                    }),
                    None => panic!("{:?} doesn't know url {}", stringify!($name), key)
                }
            }

            fn set_ssl_verifier(&mut self, _verifier: ::net::ContextVerifier) {
                // pass
            }
        }

    )
);

<commit_msg>fix(mock): adjust ChannelMockConnector connect method to compile<commit_after>use std::fmt;
use std::io::{self, Read, Write, Cursor};
use std::net::SocketAddr;
use std::sync::mpsc::Sender;

use net::{NetworkStream, NetworkConnector, ContextVerifier};

pub struct MockStream {
    pub read: Cursor<Vec<u8>>,
    pub write: Vec<u8>,
}

impl Clone for MockStream {
    fn clone(&self) -> MockStream {
        MockStream {
            read: Cursor::new(self.read.get_ref().clone()),
            write: self.write.clone()
        }
    }
}

impl fmt::Debug for MockStream {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MockStream {{ read: {:?}, write: {:?} }}", self.read.get_ref(), self.write)
    }
}

impl PartialEq for MockStream {
    fn eq(&self, other: &MockStream) -> bool {
        self.read.get_ref() == other.read.get_ref() && self.write == other.write
    }
}

impl MockStream {
    pub fn new() -> MockStream {
        MockStream {
            read: Cursor::new(vec![]),
            write: vec![],
        }
    }

    pub fn with_input(input: &[u8]) -> MockStream {
        MockStream {
            read: Cursor::new(input.to_vec()),
            write: vec![]
        }
    }
}

impl Read for MockStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.read.read(buf)
    }
}

impl Write for MockStream {
    fn write(&mut self, msg: &[u8]) -> io::Result<usize> {
        Write::write(&mut self.write, msg)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl NetworkStream for MockStream {
    fn peer_addr(&mut self) -> io::Result<SocketAddr> {
        Ok("127.0.0.1:1337".parse().unwrap())
    }
}

pub struct MockConnector;

impl NetworkConnector for MockConnector {
    type Stream = MockStream;

    fn connect(&self, _host: &str, _port: u16, _scheme: &str) -> ::Result<MockStream> {
        Ok(MockStream::new())
    }

    fn set_ssl_verifier(&mut self, _verifier: ContextVerifier) {
        // pass
    }
}

/// A mock implementation of the `NetworkConnector` trait that keeps track of all calls to its
/// methods by sending corresponding messages onto a channel.
///
/// Otherwise, it behaves the same as `MockConnector`.
pub struct ChannelMockConnector {
    calls: Sender<String>,
}

impl ChannelMockConnector {
    pub fn new(calls: Sender<String>) -> ChannelMockConnector {
        ChannelMockConnector { calls: calls }
    }
}

impl NetworkConnector for ChannelMockConnector {
    type Stream = MockStream;
    #[inline]
    fn connect(&self, _host: &str, _port: u16, _scheme: &str)
            -> ::Result<MockStream> {
        self.calls.send("connect".into()).unwrap();
        Ok(MockStream::new())
    }

    #[inline]
    fn set_ssl_verifier(&mut self, _verifier: ContextVerifier) {
        self.calls.send("set_ssl_verifier".into()).unwrap();
    }
}

/// new connectors must be created if you wish to intercept requests.
macro_rules! mock_connector (
    ($name:ident {
        $($url:expr => $res:expr)*
    }) => (

        struct $name;

        impl ::net::NetworkConnector for $name {
            type Stream = ::mock::MockStream;
            fn connect(&self, host: &str, port: u16, scheme: &str) -> $crate::Result<::mock::MockStream> {
                use std::collections::HashMap;
                use std::io::Cursor;
                debug!("MockStream::connect({:?}, {:?}, {:?})", host, port, scheme);
                let mut map = HashMap::new();
                $(map.insert($url, $res);)*

                let key = format!("{}://{}", scheme, host);
                // ignore port for now
                match map.get(&*key) {
                    Some(res) => Ok($crate::mock::MockStream {
                        write: vec![],
                        read: Cursor::new(res.to_string().into_bytes()),
                    }),
                    None => panic!("{:?} doesn't know url {}", stringify!($name), key)
                }
            }

            fn set_ssl_verifier(&mut self, _verifier: ::net::ContextVerifier) {
                // pass
            }
        }

    )
);

<|endoftext|>


<commit_before>//!A raytracer.
#![feature(path, io)]
extern crate image;

use std::old_io::File;
use std::num::Float;

use point::Point3;
use vec::Vec3;

mod vec;
mod point;

#[derive(Copy)]
struct Ray3 {
    start: Point3,
    dir: Vec3
}

struct Intersection {
    time: f32,
    point: Point3,
    normal: Vec3
}

trait Scene {
    fn intersect(&self, ray: Ray3) -> Option<Intersection>;
}

struct Sphere {
    center: Point3,
    radius: f32
}

impl Scene for Sphere {
    fn intersect(&self, ray: Ray3) -> Option<Intersection> {
        let offset = ray.start - self.center;

        let a = ray.dir.mag2();
        let b = 2. * offset.dot(ray.dir);
        let c = offset.mag2() - self.radius*self.radius;

        let descrim = b*b - 4.*a*c;
        if descrim > 0. {
            let t1 = (-b - descrim.sqrt()) / (2. * a);
            let t2 = (-b + descrim.sqrt()) / (2. * a);
            if t1 > 0. {
                let p = ray.start + ray.dir * t1;
                let normal = p - self.center;
                Some(Intersection {
                    time: t1,
                    point: p,
                    normal: normal
                })
            } else if t2 > 0. {
                let p = ray.start + ray.dir * t2;
                let normal = p - self.center;
                Some(Intersection {
                    time: t2,
                    point: p,
                    normal: normal
                })
            } else {
                None
            }
        } else {
            None
        }
    }
}

struct Plane {
    origin: Point3,
    normal: Vec3
}

impl Scene for Plane {
    fn intersect(&self, ray: Ray3) -> Option<Intersection> {
        let divisor = ray.dir.dot(self.normal);
        if divisor == 0. {
            None
        } else {
            let offset = ray.start - self.origin;
            let time = -offset.dot(self.normal) / divisor;
            if time > 0. {
                Some(Intersection {
                    time: time,
                    point: ray.start + ray.dir * time,
                    normal: self.normal
                })
            } else {
                None
            }
        }
    }
}

impl<A: Scene, B: Scene> Scene for (A, B) {
    fn intersect(&self, ray: Ray3) -> Option<Intersection> {
        match self.0.intersect(ray) {
            Some(ai) => {
                match self.1.intersect(ray) {
                    Some(bi) => if ai.time < bi.time {
                        Some(ai)
                    } else {
                        Some(bi)
                    },
                    None => Some(ai)
                }
            },
            None => self.1.intersect(ray)
        }
    }
}

fn clamp(val: f32) -> f32 {
    if val > 1. {
        1.
    } else if val < 0. {
        0.
    } else {
        val
    }
}

fn main() {
    let scene = (
        (Sphere {
            center: Point3::new(1.2, 0.0, 5.0),
            radius: 0.3
        },
        Sphere {
            center: Point3::new(1.5, 0.0, 3.5),
            radius: 0.35
        }),
        (Plane {
            origin: Point3::new(0.0, 0.0, 8.0),
            normal: Vec3::new(2.0, 0.0, -1.0)
        },
        Plane {
            origin: Point3::new(0.0, 0.0, 8.0),
            normal: Vec3::new(-1.0, 0.0, -2.0)
        })
    );
    let light = Point3::new(1.0, -1.5, 0.5);

    let imgx = 800;
    let imgy = 800;

    let scalex = 4.0 / imgx as f32;
    let scaley = 4.0 / imgy as f32;

    // Create a new ImgBuf with width: imgx and height: imgy
    let mut imgbuf = image::ImageBuffer::new(imgx, imgy);

    // Iterate over the coordiantes and pixels of the image
    for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
        let cy = -(y as f32 * scaley - 2.0);
        let cx = x as f32 * scalex - 2.0;

        let ray = Ray3 {
            start: Point3::new(0., 0., -8.0),
            dir: Vec3::new(cx, cy, 8.0)
        };

        let value: f32 = match scene.intersect(ray) {
            Some(intersection) => {
                let light_dir = light - intersection.point;
                let light_strength = 10.0 / light_dir.mag2();
                let scale = (intersection.normal.mag2() * light_dir.mag2()).sqrt();
                clamp(light_strength * intersection.normal.dot(light_dir) / scale)
            },
            None => 0.
        };

        // Create an 8bit pixel of type Luma and value i
        // and assign in to the pixel at position (x, y)
        *pixel = image::Luma([(value*255.) as u8]);
    }

    // Save the image as “out.png”
    let ref mut fout = File::create(&Path::new("out.png")).unwrap();

    // We must indicate the image’s color type and what format to save as
    let _ = image::ImageLuma8(imgbuf).save(fout, image::PNG);
}
<commit_msg>Added light visibility checking and an eplsilon<commit_after>//!A raytracer.
#![feature(path, io)]
extern crate image;

use std::old_io::File;
use std::num::Float;

use point::Point3;
use vec::Vec3;

mod vec;
mod point;

const EPS: f32 = 0.00005;

#[derive(Copy)]
struct Ray3 {
    start: Point3,
    dir: Vec3
}

struct Intersection {
    time: f32,
    point: Point3,
    normal: Vec3
}

trait Scene {
    fn intersect(&self, ray: Ray3) -> Option<Intersection>;
}

struct Sphere {
    center: Point3,
    radius: f32
}

impl Scene for Sphere {
    fn intersect(&self, ray: Ray3) -> Option<Intersection> {
        let offset = ray.start - self.center;

        let a = ray.dir.mag2();
        let b = 2. * offset.dot(ray.dir);
        let c = offset.mag2() - self.radius*self.radius;

        let descrim = b*b - 4.*a*c;
        if descrim > 0. {
            let t1 = (-b - descrim.sqrt()) / (2. * a);
            let t2 = (-b + descrim.sqrt()) / (2. * a);
            if t1 > EPS {
                let p = ray.start + ray.dir * t1;
                let normal = p - self.center;
                Some(Intersection {
                    time: t1,
                    point: p,
                    normal: normal
                })
            } else if t2 > EPS {
                let p = ray.start + ray.dir * t2;
                let normal = p - self.center;
                Some(Intersection {
                    time: t2,
                    point: p,
                    normal: normal
                })
            } else {
                None
            }
        } else {
            None
        }
    }
}

struct Plane {
    origin: Point3,
    normal: Vec3
}

impl Scene for Plane {
    fn intersect(&self, ray: Ray3) -> Option<Intersection> {
        let divisor = ray.dir.dot(self.normal);
        if divisor == 0. {
            None
        } else {
            let offset = ray.start - self.origin;
            let time = -offset.dot(self.normal) / divisor;
            if time > EPS {
                Some(Intersection {
                    time: time,
                    point: ray.start + ray.dir * time,
                    normal: self.normal
                })
            } else {
                None
            }
        }
    }
}

impl<A: Scene, B: Scene> Scene for (A, B) {
    fn intersect(&self, ray: Ray3) -> Option<Intersection> {
        match self.0.intersect(ray) {
            Some(ai) => {
                match self.1.intersect(ray) {
                    Some(bi) => if ai.time < bi.time {
                        Some(ai)
                    } else {
                        Some(bi)
                    },
                    None => Some(ai)
                }
            },
            None => self.1.intersect(ray)
        }
    }
}

fn clamp(val: f32) -> f32 {
    if val > 1. {
        1.
    } else if val < 0. {
        0.
    } else {
        val
    }
}

fn main() {
    let scene = (
        (Sphere {
            center: Point3::new(1.2, 0.0, 5.0),
            radius: 0.3
        },
        Sphere {
            center: Point3::new(1.5, 0.0, 3.5),
            radius: 0.35
        }),
        (Plane {
            origin: Point3::new(0.0, 0.0, 8.0),
            normal: Vec3::new(2.0, 0.0, -1.0)
        },
        Plane {
            origin: Point3::new(0.0, 0.0, 8.0),
            normal: Vec3::new(-1.0, 0.0, -2.0)
        })
    );
    let light = Point3::new(1.0, -1.5, 0.5);

    let imgx = 800;
    let imgy = 800;

    let scalex = 4.0 / imgx as f32;
    let scaley = 4.0 / imgy as f32;

    // Create a new ImgBuf with width: imgx and height: imgy
    let mut imgbuf = image::ImageBuffer::new(imgx, imgy);

    // Iterate over the coordiantes and pixels of the image
    for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
        let cy = -(y as f32 * scaley - 2.0);
        let cx = x as f32 * scalex - 2.0;

        let ray = Ray3 {
            start: Point3::new(0., 0., -8.0),
            dir: Vec3::new(cx, cy, 8.0)
        };

        let value: f32 = match scene.intersect(ray) {
            Some(intersection) => {
                let light_ray = Ray3 {
                    start: intersection.point,
                    dir: light - intersection.point
                };

                let can_see_light = match scene.intersect(light_ray) {
                    Some(light_intersection) => {
                        light_intersection.time > 1.
                    },
                    None => true
                };

                if can_see_light {
                    let light_strength = 10.0 / light_ray.dir.mag2();
                    let scale = (intersection.normal.mag2() * light_ray.dir.mag2()).sqrt();
                    clamp(light_strength * intersection.normal.dot(light_ray.dir) / scale)
                } else {
                    0.
                }
            },
            None => 0.
        };

        // Create an 8bit pixel of type Luma and value i
        // and assign in to the pixel at position (x, y)
        *pixel = image::Luma([(value*255.) as u8]);
    }

    // Save the image as “out.png”
    let ref mut fout = File::create(&Path::new("out.png")).unwrap();

    // We must indicate the image’s color type and what format to save as
    let _ = image::ImageLuma8(imgbuf).save(fout, image::PNG);
}
<|endoftext|>


<commit_before>use image::RgbaImage;
use rand::Rng;
use itertools::Itertools;

use utils::*;

pub fn encode_rgba<R: Rng>(source: &mut RgbaImage, payload: &[u8], mode: RgbaMode, mut rng: R)
{
    // number of pixels per byte
    let ppb = match mode
    {
        // 1 values per pixel = 8 pixels per byte
        RgbaMode::Alpha => 8,
        // 4 values per pixel = 2 pixels per byte
        RgbaMode::Each => 2,
    };

    for (pixels, byte) in source.pixels_mut() // iterate pixels mutably
        .chunks(ppb).into_iter()              // split them into ppb-size chunks
        .map(|ch| ch.collect::<Vec<_>>())     // make them vectors so we can check their lengths later
        .zip(payload.iter().map(|x| *x))      // give each chunk a byte
    {
        // if the pixels don't fit exactly into their chunks,
        // the last chunk will be short. we won't use that chunk
        // (making sure the payload fits into the image is not
        // this functions job!)
        if pixels.len() != ppb
        {
            return;
        }

        match mode
        {
            RgbaMode::Alpha =>
            {
                for (i, px) in pixels.into_iter().enumerate()
                {
                    // a true, or 1 bit
                    if get_bit(byte, i as u8)
                    {
                        // even = 0 bit, so it needs to be changed
                        if px.data[3] % 2 == 0
                        {
                            // special case: if it's zero, we have to go up
                            if px.data[3] == 0
                            {
                                px.data[3] = 1;
                            }
                            else
                            {
                                if rng.gen()
                                {
                                    px.data[3] += 1;
                                }
                                else
                                {
                                    px.data[3] -= 1;
                                }
                            }
                        }
                    }
                    // a false, or 0 bit
                    else
                    {
                        // odd = 1 bit, so it needs to be changed
                        if px.data[3] % 2 == 1
                        {
                            // special case: if it's 255, we have to go down
                            if px.data[3] == 255
                            {
                                px.data[3] = 254;
                            }
                            else
                            {
                                if rng.gen()
                                {
                                    px.data[3] += 1;
                                }
                                else
                                {
                                    px.data[3] -= 1;
                                }
                            }
                        }
                    }
                }
            },
            RgbaMode::Each =>
            {
                unimplemented!()
            },
        }
    }
}

pub fn decode_rgba(source: &RgbaImage, mode: RgbaMode) -> Vec<u8>
{
    // pixels per byte
    let ppb = match mode
    {
        // one value per pixel = 8 pixels per byte
        RgbaMode::Alpha => 8,
        // four values per pixel = 2 pixels per byte
        RgbaMode::Each => 2,
    };

    let mut buf = Vec::new();

    for pixels in source.pixels()         // iterate pixels
        .chunks(ppb).into_iter()          // split into ppb-sized chunks
        .map(|ch| ch.collect::<Vec<_>>()) // make them vectors so we can check their lengths
    {
        // only decode while we have enough data
        if pixels.len() != ppb
        {
            break;
        }

        match mode
        {
            RgbaMode::Alpha =>
            {
                let mut byte = 0u8;

                for (i, px) in pixels.into_iter().enumerate()
                {
                    byte = set_bit(byte, i as u8, px.data[3] % 2 == 1);
                }

                buf.push(byte)
            },
            RgbaMode::Each =>
            {
                unimplemented!()
            }
        }
    }

    buf

}

/// The encoding/decoding mode
#[derive(Copy, Clone)]
pub enum RgbaMode
{
    /// encode in alpha even/odd
    Alpha,
    /// encode in each field even/odd
    Each,
}

use std::default::Default;

impl Default for RgbaMode
{
    fn default() -> RgbaMode
    {
        RgbaMode::Alpha
    }
}

#[cfg(test)]
mod test
{
    use image::{ImageBuffer, Rgba};
    use rand::StdRng;

    use super::*;

    #[test]
    fn alpha()
    {
        let mut image = ImageBuffer::from_pixel(
            25,
            8,
            Rgba
            {
                data: [127u8; 4],
            });

        let payload = vec![
            1,2, 3, 4, 5, 6, 7, 8, 9, 10,
            11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
            21, 22, 23, 24, 25
        ];

        let rng = StdRng::new().unwrap();

        encode_rgba(&mut image, &payload, RgbaMode::Alpha, rng);

        let dec = decode_rgba(&image, RgbaMode::Alpha);

        assert_eq!(payload, dec);
    }
}
<commit_msg>Implemented rgba each encoding<commit_after>use image::RgbaImage;
use rand::Rng;
use itertools::Itertools;

use utils::*;

pub fn encode_rgba<R: Rng>(source: &mut RgbaImage, payload: &[u8], mode: RgbaMode, mut rng: R)
{
    // number of pixels per byte
    let ppb = match mode
    {
        // 1 values per pixel = 8 pixels per byte
        RgbaMode::Alpha => 8,
        // 4 values per pixel = 2 pixels per byte
        RgbaMode::Each => 2,
    };

    for (mut pixels, byte) in source.pixels_mut() // iterate pixels mutably
        .chunks(ppb).into_iter()              // split them into ppb-size chunks
        .map(|ch| ch.collect::<Vec<_>>())     // make them vectors so we can check their lengths later
        .zip(payload.iter().map(|x| *x))      // give each chunk a byte
    {
        // if the pixels don't fit exactly into their chunks,
        // the last chunk will be short. we won't use that chunk
        // (making sure the payload fits into the image is not
        // this functions job!)
        if pixels.len() != ppb
        {
            return;
        }

        match mode
        {
            RgbaMode::Alpha =>
            {
                for (i, px) in pixels.into_iter().enumerate()
                {
                    // a true, or 1 bit
                    if get_bit(byte, i as u8)
                    {
                        // even = 0 bit, so it needs to be changed
                        if px.data[3] % 2 == 0
                        {
                            // special case: if it's zero, we have to go up
                            if px.data[3] == 0
                            {
                                px.data[3] = 1;
                            }
                            else
                            {
                                if rng.gen()
                                {
                                    px.data[3] += 1;
                                }
                                else
                                {
                                    px.data[3] -= 1;
                                }
                            }
                        }
                    }
                    // a false, or 0 bit
                    else
                    {
                        // odd = 1 bit, so it needs to be changed
                        if px.data[3] % 2 == 1
                        {
                            // special case: if it's 255, we have to go down
                            if px.data[3] == 255
                            {
                                px.data[3] = 254;
                            }
                            else
                            {
                                if rng.gen()
                                {
                                    px.data[3] += 1;
                                }
                                else
                                {
                                    px.data[3] -= 1;
                                }
                            }
                        }
                    }
                }
            },
            RgbaMode::Each =>
            {
                for i in 0..8
                {
                    let val = if i < 4
                    {
                        &mut pixels[0].data[i]
                    }
                    else
                    {
                        &mut pixels[1].data[i - 4]
                    };

                    if get_bit(byte, i as u8)
                    {
                        // even = 0 bit, so it needs to be changed
                        if *val % 2 == 0
                        {
                            // special case: if it's zero, we have to go up
                            if *val == 0
                            {
                                *val = 1;
                            }
                            else
                            {
                                if rng.gen()
                                {
                                    *val += 1;
                                }
                                else
                                {
                                    *val -= 1;
                                }
                            }
                        }
                    }
                    // a false, or 0 bit
                    else
                    {
                        // odd = 1 bit, so it needs to be changed
                        if *val % 2 == 1
                        {
                            // special case: if it's 255, we have to go down
                            if *val == 255
                            {
                                *val = 254;
                            }
                            else
                            {
                                if rng.gen()
                                {
                                    *val += 1;
                                }
                                else
                                {
                                    *val -= 1;
                                }
                            }
                        }
                    }
                }
            },
        }
    }
}

pub fn decode_rgba(source: &RgbaImage, mode: RgbaMode) -> Vec<u8>
{
    // pixels per byte
    let ppb = match mode
    {
        // one value per pixel = 8 pixels per byte
        RgbaMode::Alpha => 8,
        // four values per pixel = 2 pixels per byte
        RgbaMode::Each => 2,
    };

    let mut buf = Vec::new();

    for pixels in source.pixels()         // iterate pixels
        .chunks(ppb).into_iter()          // split into ppb-sized chunks
        .map(|ch| ch.collect::<Vec<_>>()) // make them vectors so we can check their lengths
    {
        // only decode while we have enough data
        if pixels.len() != ppb
        {
            break;
        }

        match mode
        {
            RgbaMode::Alpha =>
            {
                let mut byte = 0u8;

                for (i, px) in pixels.into_iter().enumerate()
                {
                    byte = set_bit(byte, i as u8, px.data[3] % 2 == 1);
                }

                buf.push(byte)
            },
            RgbaMode::Each =>
            {
                unimplemented!()
            }
        }
    }

    buf

}

/// The encoding/decoding mode
#[derive(Copy, Clone)]
pub enum RgbaMode
{
    /// encode in alpha even/odd
    Alpha,
    /// encode in each field even/odd
    Each,
}

use std::default::Default;

impl Default for RgbaMode
{
    fn default() -> RgbaMode
    {
        RgbaMode::Alpha
    }
}

#[cfg(test)]
mod test
{
    use image::{ImageBuffer, Rgba};
    use rand::StdRng;

    use super::*;

    #[test]
    fn alpha()
    {
        let mut image = ImageBuffer::from_pixel(
            25,
            8,
            Rgba
            {
                data: [127u8; 4],
            });

        let payload = vec![
            1,2, 3, 4, 5, 6, 7, 8, 9, 10,
            11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
            21, 22, 23, 24, 25
        ];

        let rng = StdRng::new().unwrap();

        encode_rgba(&mut image, &payload, RgbaMode::Alpha, rng);

        let dec = decode_rgba(&image, RgbaMode::Alpha);

        assert_eq!(payload, dec);
    }
}
<|endoftext|>