<commit_before>use std::env;
use std::fs::File;
use std::io::Read;
extern crate syn;
use syn::*;

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_c_abi(abi: &Option<Abi>) -> bool {
    abi == &Some(Abi::Named(String::from("C")))
}

fn map_path(p: &Path) -> String {
    let l = p.segments[0].ident.to_string();
    match l.as_ref() {
        "usize" => "size_t".to_string(),
        "u8" => "uint8_t".to_string(),
        "u32" => "uint32_t".to_string(),
        "f32" => "float".to_string(),
        _ => l,
    }
}

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

fn map_ty(ty: &Ty) -> String {
    match ty {
        &Ty::Path(_, ref p) => map_path(p),
        &Ty::Ptr(ref p) => format!("{}*", map_ty(&p.ty)),
        &Ty::Rptr(_, ref mut_ty) => format!("{}*", map_mut_ty(mut_ty)),
        _ => format!("unknown {:?}", ty),
    }

}

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

fn map_pat(pat: &Pat) -> String {
    match pat {
        &Pat::Ident(_, ref ident, _) => ident.to_string(),
        _ => format!("unknown {:?}", pat),
    }

}

fn map_arg(f: &FnArg) -> String {
    match f {
        &FnArg::Captured(ref pat, ref ty) => format!("{} {}", map_ty(ty), map_pat(pat)),
        _ => "unknown".to_string(),
    }
}

fn main() {
    let p = env::args().nth(1).unwrap();
    let mut s = String::new();
    let mut f = File::open(p).unwrap();
    f.read_to_string(&mut s).unwrap();
    let krate = syn::parse_crate(&s).unwrap();
    for item in krate.items {
        match item.node {
            ItemKind::Fn(decl, _unsafe, _const, abi, _generic, _block) => {
                if has_no_mangle(&item.attrs) && is_c_abi(&abi) {
                    println!("WR_INLINE {}\n{}({})\n{};\n",
                             map_return_type(&decl.output),
                             item.ident,
                             decl.inputs
                                 .iter()
                                 .map(map_arg)
                                 .collect::<Vec<_>>()
                                 .join(", "),
                             wr_func_body(&item.attrs));
                }
            }
            _ => {}
        }
    }

}
<commit_msg>Support c_void*<commit_after>use std::env;
use std::fs::File;
use std::io::Read;
extern crate syn;
use syn::*;

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_c_abi(abi: &Option<Abi>) -> bool {
    abi == &Some(Abi::Named(String::from("C")))
}

fn map_path(p: &Path) -> String {
    let l = p.segments[0].ident.to_string();
    match l.as_ref() {
        "usize" => "size_t".to_string(),
        "u8" => "uint8_t".to_string(),
        "u32" => "uint32_t".to_string(),
        "f32" => "float".to_string(),
        "c_void" => "void".to_string(),
        _ => l,
    }
}

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

fn map_ty(ty: &Ty) -> String {
    match ty {
        &Ty::Path(_, ref p) => map_path(p),
        &Ty::Ptr(ref p) => format!("{}*", map_ty(&p.ty)),
        &Ty::Rptr(_, ref mut_ty) => format!("{}*", map_mut_ty(mut_ty)),
        _ => format!("unknown {:?}", ty),
    }

}

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

fn map_pat(pat: &Pat) -> String {
    match pat {
        &Pat::Ident(_, ref ident, _) => ident.to_string(),
        _ => format!("unknown {:?}", pat),
    }

}

fn map_arg(f: &FnArg) -> String {
    match f {
        &FnArg::Captured(ref pat, ref ty) => format!("{} {}", map_ty(ty), map_pat(pat)),
        _ => "unknown".to_string(),
    }
}

fn main() {
    let p = env::args().nth(1).unwrap();
    let mut s = String::new();
    let mut f = File::open(p).unwrap();
    f.read_to_string(&mut s).unwrap();
    let krate = syn::parse_crate(&s).unwrap();
    for item in krate.items {
        match item.node {
            ItemKind::Fn(decl, _unsafe, _const, abi, _generic, _block) => {
                if has_no_mangle(&item.attrs) && is_c_abi(&abi) {
                    println!("WR_INLINE {}\n{}({})\n{};\n",
                             map_return_type(&decl.output),
                             item.ident,
                             decl.inputs
                                 .iter()
                                 .map(map_arg)
                                 .collect::<Vec<_>>()
                                 .join(", "),
                             wr_func_body(&item.attrs));
                }
            }
            _ => {}
        }
    }

}
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::io::Read;
extern crate syn;
use syn::*;

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_c_abi(abi: &Option<Abi>) -> bool {
    abi == &Some(Abi::Named(String::from("C")))
}

fn map_path(p: &Path) -> String {
    let l = p.segments[0].ident.to_string();
    match l.as_ref() {
        "usize" => "size_t".to_string(),
        "u8" => "uint8_t".to_string(),
        "u32" => "uint32_t".to_string(),
        "f32" => "float".to_string(),
        "c_void" => "void".to_string(),
        _ => l,
    }
}

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

fn map_ty(ty: &Ty) -> String {
    match ty {
        &Ty::Path(_, ref p) => map_path(p),
        &Ty::Ptr(ref p) => format!("{}*", map_ty(&p.ty)),
        &Ty::Rptr(_, ref mut_ty) => format!("{}*", map_mut_ty(mut_ty)),
        _ => format!("unknown {:?}", ty),
    }

}

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

fn map_pat(pat: &Pat) -> String {
    match pat {
        &Pat::Ident(_, ref ident, _) => ident.to_string(),
        _ => format!("unknown {:?}", pat),
    }

}

fn map_arg(f: &FnArg) -> String {
    match f {
        &FnArg::Captured(ref pat, ref ty) => format!("{} {}", map_ty(ty), map_pat(pat)),
        _ => "unknown".to_string(),
    }
}

fn main() {
    let p = env::args().nth(1).unwrap();
    let mut s = String::new();
    let mut f = File::open(p).unwrap();
    f.read_to_string(&mut s).unwrap();
    let krate = syn::parse_crate(&s).unwrap();
    for item in krate.items {
        match item.node {
            ItemKind::Fn(decl, _unsafe, _const, abi, _generic, _block) => {
                if has_no_mangle(&item.attrs) && is_c_abi(&abi) {
                    println!("WR_INLINE {}\n{}({})\n{};\n",
                             map_return_type(&decl.output),
                             item.ident,
                             decl.inputs
                                 .iter()
                                 .map(map_arg)
                                 .collect::<Vec<_>>()
                                 .join(", "),
                             wr_func_body(&item.attrs));
                }
            }
            _ => {}
        }
    }

}
<commit_msg>Add struct conversion<commit_after>use std::env;
use std::fs::File;
use std::io::Read;
extern crate syn;
use syn::*;

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_c_abi(abi: &Option<Abi>) -> bool {
    abi == &Some(Abi::Named(String::from("C")))
}

fn map_path(p: &Path) -> String {
    let l = p.segments[0].ident.to_string();
    match l.as_ref() {
        "usize" => "size_t".to_string(),
        "u8" => "uint8_t".to_string(),
        "u32" => "uint32_t".to_string(),
        "f32" => "float".to_string(),
        "c_void" => "void".to_string(),
        _ => l,
    }
}

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

fn map_ty(ty: &Ty) -> String {
    match ty {
        &Ty::Path(_, ref p) => map_path(p),
        &Ty::Ptr(ref p) => format!("{}*", map_ty(&p.ty)),
        &Ty::Rptr(_, ref mut_ty) => format!("{}*", map_mut_ty(mut_ty)),
        _ => format!("unknown {:?}", ty),
    }

}

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

fn map_pat(pat: &Pat) -> String {
    match pat {
        &Pat::Ident(_, ref ident, _) => ident.to_string(),
        _ => format!("unknown {:?}", pat),
    }

}

fn map_arg(f: &FnArg) -> String {
    match f {
        &FnArg::Captured(ref pat, ref ty) => format!("{} {}", map_ty(ty), map_pat(pat)),
        _ => "unknown".to_string(),
    }
}

fn map_field(f: &Field) -> String {
    let mut ret = String::from("  ");
    ret.push_str(&map_ty(&f.ty));
    ret.push(' ');
    ret.push_str(&f.ident.as_ref().expect("Struct fields must have idents").to_string());
    ret.push_str(";\n");
    ret
}

fn main() {
    let p = env::args().nth(1).unwrap();
    let mut s = String::new();
    let mut f = File::open(p).unwrap();
    f.read_to_string(&mut s).unwrap();
    let krate = syn::parse_crate(&s).unwrap();
    for item in krate.items {
        match item.node {
            ItemKind::Fn(decl, _unsafe, _const, abi, _generic, _block) => {
                if has_no_mangle(&item.attrs) && is_c_abi(&abi) {
                    println!("WR_INLINE {}\n{}({})\n{};\n",
                             map_return_type(&decl.output),
                             item.ident,
                             decl.inputs
                                 .iter()
                                 .map(map_arg)
                                 .collect::<Vec<_>>()
                                 .join(", "),
                             wr_func_body(&item.attrs));
                }
            }
            ItemKind::Struct(variant, _generics) => {
                if is_repr_c(&item.attrs) {
                    if let VariantData::Struct(fields) = variant {
                        println!("struct {} {{\n{}}};\n",
                                 item.ident,
                                 fields
                                     .iter()
                                     .map(map_field)
                                     .collect::<String>());
                    }
                }
            }
            _ => {}
        }
    }

}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
#[macro_use]
extern crate lazy_static;

extern crate libc;
extern crate scmp;
extern crate tempdir;

use std::fs;
use std::env;
use std::ffi::OsStr;
use std::ffi::CString;
use std::io::Error;
use std::os::raw::c_void;
use std::os::unix::process::CommandExt;
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use scmp::*;

unsafe fn allow_syscall(ctx : *mut c_void, nr : u32) {
    assert!(seccomp_rule_add_array(ctx, SCMP_ACT_ALLOW, nr as i32, 0, std::ptr::null()) == 0);
}

fn setup_seccomp() -> Result<(), Error> {
    unsafe {
        let ctx0 = seccomp_init(SCMP_ACT_TRAP);
        assert!(!ctx0.is_null());
        allow_syscall(ctx0, __NR_execve);
        allow_syscall(ctx0, __NR_brk);
        allow_syscall(ctx0, __NR_access);
        allow_syscall(ctx0, __NR_mmap);
        allow_syscall(ctx0, __NR_open);
        allow_syscall(ctx0, __NR_read);
        allow_syscall(ctx0, __NR_write);
        allow_syscall(ctx0, __NR_stat);
        allow_syscall(ctx0, __NR_fstat);
        allow_syscall(ctx0, __NR_close);
        allow_syscall(ctx0, __NR_mprotect);
        allow_syscall(ctx0, __NR_arch_prctl);
        allow_syscall(ctx0, __NR_munmap);
        allow_syscall(ctx0, __NR_set_tid_address);
        allow_syscall(ctx0, __NR_set_robust_list);
        allow_syscall(ctx0, __NR_rt_sigaction);
        allow_syscall(ctx0, __NR_rt_sigprocmask);
        allow_syscall(ctx0, __NR_getrlimit);
        allow_syscall(ctx0, __NR_statfs);
        allow_syscall(ctx0, __NR_fcntl);
        allow_syscall(ctx0, __NR_geteuid);
        allow_syscall(ctx0, __NR_umask);
        allow_syscall(ctx0, __NR_pipe);
        allow_syscall(ctx0, __NR_clone);
        allow_syscall(ctx0, __NR_wait4);
        allow_syscall(ctx0, __NR_exit_group);
        allow_syscall(ctx0, __NR_dup);
        allow_syscall(ctx0, __NR_ioctl);
        allow_syscall(ctx0, __NR_getpid);
        allow_syscall(ctx0, __NR_gettid);
        allow_syscall(ctx0, __NR_tgkill);
        allow_syscall(ctx0, __NR_rt_sigreturn);
        allow_syscall(ctx0, __NR_socket);
        allow_syscall(ctx0, __NR_connect);
        allow_syscall(ctx0, __NR_lseek);
        allow_syscall(ctx0, __NR_openat);
        allow_syscall(ctx0, __NR_unlinkat);
        allow_syscall(ctx0, __NR_utimensat);
        allow_syscall(ctx0, __NR_lstat);
        allow_syscall(ctx0, __NR_fchmod);
        allow_syscall(ctx0, __NR_unlink);
        allow_syscall(ctx0, __NR_utime);
        allow_syscall(ctx0, __NR_futex);
        allow_syscall(ctx0, __NR_chmod);
        allow_syscall(ctx0, __NR_getuid);
        allow_syscall(ctx0, __NR_getgid);
        allow_syscall(ctx0, __NR_getppid);
        allow_syscall(ctx0, __NR_getcwd);
        allow_syscall(ctx0, __NR_getegid);
        allow_syscall(ctx0, __NR_getdents);
        allow_syscall(ctx0, __NR_readlink);
        allow_syscall(ctx0, __NR_mkdirat);
        allow_syscall(ctx0, __NR_mkdir);
        assert!(seccomp_load(ctx0) == 0);
    }
    return Ok(());
}

const RENAME_NOREPLACE : u64 = 1;

fn path_to_cstring(path : &Path) -> CString {
    return CString::new(path.as_os_str().as_bytes()).unwrap();
}

fn rename_noreplace(path0 : &Path, path1 : &Path) -> Result<(), Error> {
    unsafe {
        if libc::syscall(__NR_renameat2 as i64, libc::AT_FDCWD, path_to_cstring(path0).as_ptr(), libc::AT_FDCWD, path_to_cstring(path1).as_ptr(), RENAME_NOREPLACE, 0) == 0 {
            return Ok(());
        } else {
            return Err(Error::last_os_error());
        }
    }
}

fn rename_or_suffix(path0 : &Path, path1 : &Path) -> Result<PathBuf, Error> {
    let rv = rename_noreplace(path0, path1);
    if let Err(err) = rv {
        if err.raw_os_error().expect("Error fails to wrap errno") != libc::EEXIST {
            return Err(err);
        }
        for suffix in 1.. {
            let mut builder = path1.as_os_str().to_os_string();
            builder.push(format!(".{}", suffix));
            let rv = rename_noreplace(path0, Path::new(&builder));
            if let Err(err) = rv {
                if err.raw_os_error().expect("Error fails to wrap errno") != libc::EEXIST {
                    return Err(err);
                }
                continue;
            }
            return Ok(Path::new(&builder).to_path_buf());
        }
        return Ok(PathBuf::new()); // XXX Unreachable
    } else {
        return Ok(path1.to_path_buf());
    }
}

struct ArchiveType {
    extensions: Vec<&'static str>,
    extract_cmd: Vec<&'static str>,
}

lazy_static! {
    static ref ARCHIVE_TYPES : Vec<ArchiveType> = vec![
        ArchiveType {
            extensions: vec![
                ".tgz",
                ".tar.gz",
                ".tar.Z",
                ".tbz2",
                ".tar.bz2",
                ".tlz",
                ".tar.lz",
                ".tar.lzma",
                ".tar.lzo",
                ".tar.xz",
            ],
            extract_cmd: vec!["tar", "-xf"],
        },
        ArchiveType {
            extensions: vec![
                ".zip",
            ],
            extract_cmd: vec!["unzip", "--"],
        },
        ArchiveType {
            extensions: vec![
                ".part1.rar",
                ".rar",
            ],
            extract_cmd: vec!["unrar", "x", "--"],
        },
        ArchiveType {
            extensions: vec![
                ".7z",
            ],
            extract_cmd: vec!["7z", "x", "--"],
        },
    ];
}

fn main() {
    let matches = clap_app!(myapp =>
        (@arg ARCHIVE: +required ... "Archives to extract")
    ).get_matches();

    let mut found = false;

    for arch in matches.values_of_os("ARCHIVE").unwrap() {
        let arch = Path::new(arch);
        let arch_bytes = arch.as_os_str().as_bytes();
        println!("Extract {:?}", arch);
        for at in ARCHIVE_TYPES.iter() {
            for &ext in &at.extensions {
                let ext_bytes = ext.as_bytes();
                if !arch_bytes.ends_with(ext_bytes) {
                    continue;
                }
                found = true;

                let noext : &OsStr = OsStrExt::from_bytes(&arch_bytes[0..arch_bytes.len()-ext_bytes.len()]);
                let stripped =
                    if let Some(noext) = Path::new(noext).file_name() {
                        noext
                    } else {
                        OsStr::new("extracted")
                    };
                let cmd = at.extract_cmd[0];
                let tmpdir = tempdir::TempDir::new_in(
                    env::current_dir().expect("Unable to get the current directory"),
                    stripped.to_string_lossy().to_mut().as_str()).expect("Unable to create temporary directory");
                let status = Command::new(cmd)
                    .args(&at.extract_cmd[1..])
                    .arg(&arch)
                    .current_dir(&tmpdir)
                    .before_exec(setup_seccomp)
                    .status()
                    .expect(format!("Failed to launch {}", cmd).as_str());
                assert!(status.success(), format!("{} wasn't successful", cmd));
                let extracted_path = tmpdir.into_path();
                let mut dir_list = fs::read_dir(&extracted_path).expect("Unable to read the extraction directory");
                if let Some(path) = dir_list.next() {
                    let path = path.expect("Unable to iterate the extraction directory");
                    if let Some(path1) = dir_list.next() {
                        path1.expect("Unable to iterate the extraction directory");
                        let newname = rename_or_suffix(&extracted_path, Path::new(stripped)).expect("Failed to rename");
                        println!("Extracted to {:?}", newname);
                    } else {
                        let newname = rename_or_suffix(&path.path(), Path::new(stripped)).expect("Failed to rename");
                        println!("Extracted to {:?}", newname);
                        fs::remove_dir(&extracted_path).expect("Failed to remove empty extraction directory");
                    }
                } else {
                    println!("No files were extracted");
                }
                break;
            }
        }
        if !found {
            println!("Can't handle {:?}", arch);
        }
    }
}

<commit_msg>Canonicalize the archive path<commit_after>#[macro_use]
extern crate clap;
#[macro_use]
extern crate lazy_static;

extern crate libc;
extern crate scmp;
extern crate tempdir;

use std::fs;
use std::env;
use std::ffi::OsStr;
use std::ffi::CString;
use std::io::Error;
use std::os::raw::c_void;
use std::os::unix::process::CommandExt;
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use scmp::*;

unsafe fn allow_syscall(ctx : *mut c_void, nr : u32) {
    assert!(seccomp_rule_add_array(ctx, SCMP_ACT_ALLOW, nr as i32, 0, std::ptr::null()) == 0);
}

fn setup_seccomp() -> Result<(), Error> {
    unsafe {
        let ctx0 = seccomp_init(SCMP_ACT_TRAP);
        assert!(!ctx0.is_null());
        allow_syscall(ctx0, __NR_execve);
        allow_syscall(ctx0, __NR_brk);
        allow_syscall(ctx0, __NR_access);
        allow_syscall(ctx0, __NR_mmap);
        allow_syscall(ctx0, __NR_open);
        allow_syscall(ctx0, __NR_read);
        allow_syscall(ctx0, __NR_write);
        allow_syscall(ctx0, __NR_stat);
        allow_syscall(ctx0, __NR_fstat);
        allow_syscall(ctx0, __NR_close);
        allow_syscall(ctx0, __NR_mprotect);
        allow_syscall(ctx0, __NR_arch_prctl);
        allow_syscall(ctx0, __NR_munmap);
        allow_syscall(ctx0, __NR_set_tid_address);
        allow_syscall(ctx0, __NR_set_robust_list);
        allow_syscall(ctx0, __NR_rt_sigaction);
        allow_syscall(ctx0, __NR_rt_sigprocmask);
        allow_syscall(ctx0, __NR_getrlimit);
        allow_syscall(ctx0, __NR_statfs);
        allow_syscall(ctx0, __NR_fcntl);
        allow_syscall(ctx0, __NR_geteuid);
        allow_syscall(ctx0, __NR_umask);
        allow_syscall(ctx0, __NR_pipe);
        allow_syscall(ctx0, __NR_clone);
        allow_syscall(ctx0, __NR_wait4);
        allow_syscall(ctx0, __NR_exit_group);
        allow_syscall(ctx0, __NR_dup);
        allow_syscall(ctx0, __NR_ioctl);
        allow_syscall(ctx0, __NR_getpid);
        allow_syscall(ctx0, __NR_gettid);
        allow_syscall(ctx0, __NR_tgkill);
        allow_syscall(ctx0, __NR_rt_sigreturn);
        allow_syscall(ctx0, __NR_socket);
        allow_syscall(ctx0, __NR_connect);
        allow_syscall(ctx0, __NR_lseek);
        allow_syscall(ctx0, __NR_openat);
        allow_syscall(ctx0, __NR_unlinkat);
        allow_syscall(ctx0, __NR_utimensat);
        allow_syscall(ctx0, __NR_lstat);
        allow_syscall(ctx0, __NR_fchmod);
        allow_syscall(ctx0, __NR_unlink);
        allow_syscall(ctx0, __NR_utime);
        allow_syscall(ctx0, __NR_futex);
        allow_syscall(ctx0, __NR_chmod);
        allow_syscall(ctx0, __NR_getuid);
        allow_syscall(ctx0, __NR_getgid);
        allow_syscall(ctx0, __NR_getppid);
        allow_syscall(ctx0, __NR_getcwd);
        allow_syscall(ctx0, __NR_getegid);
        allow_syscall(ctx0, __NR_getdents);
        allow_syscall(ctx0, __NR_readlink);
        allow_syscall(ctx0, __NR_mkdirat);
        allow_syscall(ctx0, __NR_mkdir);
        assert!(seccomp_load(ctx0) == 0);
    }
    return Ok(());
}

const RENAME_NOREPLACE : u64 = 1;

fn path_to_cstring(path : &Path) -> CString {
    return CString::new(path.as_os_str().as_bytes()).unwrap();
}

fn rename_noreplace(path0 : &Path, path1 : &Path) -> Result<(), Error> {
    unsafe {
        if libc::syscall(__NR_renameat2 as i64, libc::AT_FDCWD, path_to_cstring(path0).as_ptr(), libc::AT_FDCWD, path_to_cstring(path1).as_ptr(), RENAME_NOREPLACE, 0) == 0 {
            return Ok(());
        } else {
            return Err(Error::last_os_error());
        }
    }
}

fn rename_or_suffix(path0 : &Path, path1 : &Path) -> Result<PathBuf, Error> {
    let rv = rename_noreplace(path0, path1);
    if let Err(err) = rv {
        if err.raw_os_error().expect("Error fails to wrap errno") != libc::EEXIST {
            return Err(err);
        }
        for suffix in 1.. {
            let mut builder = path1.as_os_str().to_os_string();
            builder.push(format!(".{}", suffix));
            let rv = rename_noreplace(path0, Path::new(&builder));
            if let Err(err) = rv {
                if err.raw_os_error().expect("Error fails to wrap errno") != libc::EEXIST {
                    return Err(err);
                }
                continue;
            }
            return Ok(Path::new(&builder).to_path_buf());
        }
        return Ok(PathBuf::new()); // XXX Unreachable
    } else {
        return Ok(path1.to_path_buf());
    }
}

struct ArchiveType {
    extensions: Vec<&'static str>,
    extract_cmd: Vec<&'static str>,
}

lazy_static! {
    static ref ARCHIVE_TYPES : Vec<ArchiveType> = vec![
        ArchiveType {
            extensions: vec![
                ".tgz",
                ".tar.gz",
                ".tar.Z",
                ".tbz2",
                ".tar.bz2",
                ".tlz",
                ".tar.lz",
                ".tar.lzma",
                ".tar.lzo",
                ".tar.xz",
            ],
            extract_cmd: vec!["tar", "-xf"],
        },
        ArchiveType {
            extensions: vec![
                ".zip",
            ],
            extract_cmd: vec!["unzip", "--"],
        },
        ArchiveType {
            extensions: vec![
                ".part1.rar",
                ".rar",
            ],
            extract_cmd: vec!["unrar", "x", "--"],
        },
        ArchiveType {
            extensions: vec![
                ".7z",
            ],
            extract_cmd: vec!["7z", "x", "--"],
        },
    ];
}

fn main() {
    let matches = clap_app!(myapp =>
        (@arg ARCHIVE: +required ... "Archives to extract")
    ).get_matches();

    let mut found = false;

    for arch in matches.values_of_os("ARCHIVE").unwrap() {
        let arch = Path::new(arch);
        let arch_bytes = arch.as_os_str().as_bytes();
        println!("Extract {:?}", arch);
        for at in ARCHIVE_TYPES.iter() {
            for &ext in &at.extensions {
                let ext_bytes = ext.as_bytes();
                if !arch_bytes.ends_with(ext_bytes) {
                    continue;
                }
                found = true;

                let noext : &OsStr = OsStrExt::from_bytes(&arch_bytes[0..arch_bytes.len()-ext_bytes.len()]);
                let stripped =
                    if let Some(noext) = Path::new(noext).file_name() {
                        noext
                    } else {
                        OsStr::new("extracted")
                    };
                let cmd = at.extract_cmd[0];
                let tmpdir = tempdir::TempDir::new_in(
                    env::current_dir().expect("Unable to get the current directory"),
                    stripped.to_string_lossy().to_mut().as_str()).expect("Unable to create temporary directory");
                let status = Command::new(cmd)
                    .args(&at.extract_cmd[1..])
                    .arg(fs::canonicalize(&arch).expect("Unable to find archive"))
                    .current_dir(&tmpdir)
                    .before_exec(setup_seccomp)
                    .status()
                    .expect(format!("Failed to launch {}", cmd).as_str());
                assert!(status.success(), format!("{} wasn't successful", cmd));
                let extracted_path = tmpdir.into_path();
                let mut dir_list = fs::read_dir(&extracted_path).expect("Unable to read the extraction directory");
                if let Some(path) = dir_list.next() {
                    let path = path.expect("Unable to iterate the extraction directory");
                    if let Some(path1) = dir_list.next() {
                        path1.expect("Unable to iterate the extraction directory");
                        let newname = rename_or_suffix(&extracted_path, Path::new(stripped)).expect("Failed to rename");
                        println!("Extracted to {:?}", newname);
                    } else {
                        let newname = rename_or_suffix(&path.path(), Path::new(stripped)).expect("Failed to rename");
                        println!("Extracted to {:?}", newname);
                        fs::remove_dir(&extracted_path).expect("Failed to remove empty extraction directory");
                    }
                } else {
                    println!("No files were extracted");
                }
                break;
            }
        }
        if !found {
            println!("Can't handle {:?}", arch);
        }
    }
}

<|endoftext|>


<commit_before>//! A simple program that recursively changes the mode of all directories or
//! files to the given mode under the given directory. The following child
//! process will be executed and waited on, and it's exit code returned
//! `sh -c "find PATH -type TYPE -exec chmod MODE {} \;"`.
use std::env;
use std::io;
use std::io::Write;
use std::path::Path;
use std::process;
use std::process::Command;

// Successful execution
const ESUCCESS: i32 = 0x00;
// Usage error
const EUSAGE: i32 = 0x01;

// Shell arguments (compatibility wrapper)
const SHELL_ARGS: &'static [&'static str] = &[
    "sh", "-c"
];
// Chmod arguments (recursive typed chmod)
const CHMOD_ARGS: &'static [&'static str] = &[
    "find", "-type", "-exec", "chmod", "{}", "\\;"
];

// The program name
const NAME: &'static str = "chmodrt";
// The program usage
const USAGE: &'static str = "\
Usage: chmodrt TYPE MODE PATH\n\nTypes:
  -d  Change the mode of directories
  -f  Change the mode of files";

// Prepends the program name to the given message
macro_rules! formatsys {
    ($fmt:expr) => (format!(concat!("{}: ", $fmt), NAME));
    ($fmt:expr, $($arg:tt)*) => (format!(concat!("{}: ", $fmt), NAME, $($arg)*));
}

// Writes a formatted system message to the standard error
macro_rules! sys {
    ($fmt:expr) => (write!(&mut ::std::io::stderr(), "{}", formatsys!($fmt)));
    ($fmt:expr, $($arg:tt)*) => (write!(&mut ::std::io::stderr(), "{}", formatsys!($fmt, $($arg)*)));
}

// Writes a formatted system message to the standard error with a new line
macro_rules! sysln {
    ($fmt:expr) => (sys!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (sys!(concat!($fmt, "\n"), $($arg)*));
}

fn main() {
    process::exit(chmodrt(env::args().collect()));
}

fn chmodrt(args: Vec<String>) -> i32 {

    // Enforce correct usage
    if args.len() != 4 {
        println!("{}", USAGE);
        return EUSAGE;
    }

    // Check if the type is not a directory or a file
    if args[1].as_str() == "-d" || args[1].as_str() == "-f" {} else {
        sysln!("unknown type: '{}'", args[1]).unwrap();
        return EUSAGE;
    }

    // Authorize absolute paths
    if Path::new(args[3].as_str()).has_root() {
        let stdin_err = formatsys!("cannot read from stdin");
        loop {
            // The input buffer must be reset with every pass
            let mut input = String::new();

            // Print a confirmation prompt and wait for input
            sys!("path is absolute - continue? [y/n] ").unwrap();
            io::stdin().read_line(&mut input).expect(stdin_err.as_str());

            // Normalize the input for comparison
            input = input.trim().to_lowercase();
            let normal = input.as_str();

            // The response must be 'y' or 'n'
            if normal == "n" {
                sysln!("abort").unwrap();
                return ESUCCESS;
            } else if normal == "y" {
                break;
            }
        }
    }

    // Construct the child process and error messages
    let find_command = format!("{} {} {} {} {} {} {} {} {}",
            CHMOD_ARGS[0], args[3], CHMOD_ARGS[1], args[1].trim_left_matches("-"),
            CHMOD_ARGS[2], CHMOD_ARGS[3], args[2], CHMOD_ARGS[4], CHMOD_ARGS[5]);
    let child_exec_err = formatsys!("failed to execute the child process: `{}`", SHELL_ARGS[0]);
    let child_wait_err = formatsys!("failed to wait on the child process: `{}`", SHELL_ARGS[0]);

    // Execute and wait on the child process
    let child = Command::new(SHELL_ARGS[0])
            .arg(SHELL_ARGS[1])
            .arg(find_command.as_str())
            .spawn().expect(child_exec_err.as_str())
            .wait().expect(child_wait_err.as_str());

    // Return the child exit code if it exists
    match child.code() {
        None => return ESUCCESS,
        Some(code) => return code,
    }
}
<commit_msg>Added an exit code<commit_after>//! A simple program that recursively changes the mode of all directories or
//! files to the given mode under the given directory. The following child
//! process will be executed and waited on, and it's exit code returned
//! `sh -c "find PATH -type TYPE -exec chmod MODE {} \;"`.
use std::env;
use std::io;
use std::io::Write;
use std::path::Path;
use std::process;
use std::process::Command;

// Successful execution
const ESUCCESS: i32 = 0x00;
// No exit code found
const ENOEXIT: i32 = 0x01;
// Invalid usage
const EUSAGE: i32 = 0x02;

// Shell arguments (compatibility wrapper)
const SHELL_ARGS: &'static [&'static str] = &[
    "sh", "-c"
];
// Chmod arguments (recursive typed chmod)
const CHMOD_ARGS: &'static [&'static str] = &[
    "find", "-type", "-exec", "chmod", "{}", "\\;"
];

// The program name
const NAME: &'static str = "chmodrt";
// The program usage
const USAGE: &'static str = "\
Usage: chmodrt TYPE MODE PATH\n\nTypes:
  -d  Change the mode of directories
  -f  Change the mode of files";

// Prepends the program name to the given message
macro_rules! formatsys {
    ($fmt:expr) => (format!(concat!("{}: ", $fmt), NAME));
    ($fmt:expr, $($arg:tt)*) => (format!(concat!("{}: ", $fmt), NAME, $($arg)*));
}

// Writes a formatted system message to the standard error
macro_rules! sys {
    ($fmt:expr) => (write!(&mut ::std::io::stderr(), "{}", formatsys!($fmt)));
    ($fmt:expr, $($arg:tt)*) => (write!(&mut ::std::io::stderr(), "{}", formatsys!($fmt, $($arg)*)));
}

// Writes a formatted system message to the standard error with a new line
macro_rules! sysln {
    ($fmt:expr) => (sys!(concat!($fmt, "\n")));
    ($fmt:expr, $($arg:tt)*) => (sys!(concat!($fmt, "\n"), $($arg)*));
}

fn main() {
    process::exit(chmodrt(env::args().collect()));
}

fn chmodrt(args: Vec<String>) -> i32 {

    // Enforce correct usage
    if args.len() != 4 {
        println!("{}", USAGE);
        return EUSAGE;
    }

    // Check if the type is not a directory or a file
    if args[1].as_str() == "-d" || args[1].as_str() == "-f" {} else {
        sysln!("unknown type: '{}'", args[1]).unwrap();
        return EUSAGE;
    }

    // Authorize absolute paths
    if Path::new(args[3].as_str()).has_root() {
        let stdin_err = formatsys!("cannot read from stdin");
        loop {
            // The input buffer must be reset with every pass
            let mut input = String::new();

            // Print a confirmation prompt and wait for input
            sys!("path is absolute - continue? [y/n] ").unwrap();
            io::stdin().read_line(&mut input).expect(stdin_err.as_str());

            // Normalize the input for comparison
            input = input.trim().to_lowercase();
            let normal = input.as_str();

            // The response must be 'y' or 'n'
            if normal == "n" {
                sysln!("abort").unwrap();
                return ESUCCESS;
            } else if normal == "y" {
                break;
            }
        }
    }

    // Construct the child process and error messages
    let find_command = format!("{} {} {} {} {} {} {} {} {}",
            CHMOD_ARGS[0], args[3], CHMOD_ARGS[1], args[1].trim_left_matches("-"),
            CHMOD_ARGS[2], CHMOD_ARGS[3], args[2], CHMOD_ARGS[4], CHMOD_ARGS[5]);
    let child_exec_err = formatsys!("failed to execute the child process: `{}`", SHELL_ARGS[0]);
    let child_wait_err = formatsys!("failed to wait on the child process: `{}`", SHELL_ARGS[0]);

    // Execute and wait on the child process
    let child = Command::new(SHELL_ARGS[0])
            .arg(SHELL_ARGS[1])
            .arg(find_command.as_str())
            .spawn().expect(child_exec_err.as_str())
            .wait().expect(child_wait_err.as_str());

    // Return the child exit code if it exists
    match child.code() {
        None => return ENOEXIT,
        Some(code) => return code,
    }
}
<|endoftext|>


<commit_before>extern mod extra;
extern mod http_client;

use extra::json;
use extra::net::url::Url;
use extra::net::url;
//use extra::serialize::{Decodable, Encodable};

use std::hashmap::HashMap;
use std::str;
use std::result::{Ok, Err};

use http_client::uv_http_request;
use http_client::StatusCode;

pub struct RepoResponse {
    rawJson: ~[~str]
}

impl RepoResponse {
    fn add(&mut self, data: ~str) {
        self.rawJson.push(data)
    }
}

/* https://github.com/huonw/isrustfastyet/blob/fce8777e289eb874a94242dbd07803248d320d12/mem/process.rs
#[deriving(Encodable)]
struct Repo {
    id: uint,
    name: ~str,
    full_name: ~str
}
*/

fn readJson(json: json::Json) {
    match json {
        json::List(l) => {
            println(fmt!("Got %? items", l.len()));
            //for l.consume_iter().advance |repo| {
            for l.iter().advance |repo| {
                println(fmt!("repo=%?\n\n", repo));

                        //x.find_copy(~"name");
                        //let d: Repo = Decodable::decode(&mut json::Decoder(json));
                        //println(fmt!("%?\n", repo.contains_key(~"git_commits_url")));

                    /*json::Json.Object(orepo) => {
                        println(fmt!("%?\n", orepo.contains_key(~"git_commits_url")));
                    }*/

                /*
                match repo {
                    json::Object(repo) => {

                    },
                    _ => {
                        fail!("We expected a list of objects");
                    }
                }*/
            }

            println("A list of Objects, perhaps")
        }
        _ => {
            println("ERROR: Unrecognized JSON format")
        }
    }
}

fn main() {

    // http://ozten.com/psto/
    // https://api.github.com/repositories
    let u: Url = url::from_str("http://ozten.com/random/sample.json").get();
    let mut request = uv_http_request(u);

    let res = @mut RepoResponse{rawJson: ~[]};

    do request.begin |event| {
        match event {
            http_client::Error(e) => {
                println(fmt!("Ouch... error %?", e));
            },
            http_client::Status(s) =>
                match s {
                    // TODO wait... how did I break how match works here
                    // I should need the pattern guard.
                    StatusOK if s == StatusOK => {
                        println(fmt!("Status %?", s));
                        match json::from_str(res.rawJson.concat()) {
                            Ok(json) => {
                                readJson(json);
                            }
                            Err(e) => {
                                println(fmt!("Error parsing JSON %?", e));
                                fail!("Can't read JSON");
                            }
                        }
                    }
                    StatusFound if s == StatusFound => {
                        println(fmt!("Redirected? %?", s));
                    }
                    StatusUnknown => {
                        println(fmt!("hmmm status is unknown %?", s));
                        fail!("No JSON of Repositiories");
                    }
                },

            http_client::Payload(p) => {
                let data = p.take();
                res.rawJson.push(str::from_bytes(data));
            }
        }
    }

    // Problem #2 How to output parts of JSON after parsing
    // I think this is working...
    match json::from_str("{\"ham\": \"bone\"}") {
        Ok(obj) => {
            match obj {
                json::Object(o) => {
                    //println(fmt!("Payload! %?", o.get(& ~"ham")))
                }
                _ => { println("Skipping") }
            }

        }
        Err(e) => {
            println("Error")
        }
    }

    // HashMap play - One type of Json is Object which is a
    // type over HashMap<~str, Json>
    let mut h: HashMap<~str, ~str> = HashMap::new();
    h.insert(~"foo", ~"bar");
    h.get(& ~"foo");

    let mut a:~[~str] = ~[];
    a.push(~"Hello");
    a.push(~" World");
    //println(a.concat());
}<commit_msg>Incrementally figuring out JSON API<commit_after>extern mod extra;
extern mod http_client;

use extra::json;
use extra::net::url::Url;
use extra::net::url;
//use extra::serialize::{Decodable, Encodable};

use std::hashmap::HashMap;
use std::str;
use std::result::{Ok, Err};

use http_client::uv_http_request;
use http_client::StatusCode;

pub struct RepoResponse {
    rawJson: ~[~str]
}

impl RepoResponse {
    fn add(&mut self, data: ~str) {
        self.rawJson.push(data)
    }
}

/* https://github.com/huonw/isrustfastyet/blob/fce8777e289eb874a94242dbd07803248d320d12/mem/process.rs
#[deriving(Encodable)]
struct Repo {
    id: uint,
    name: ~str,
    full_name: ~str
}
*/

fn handleRepo(repo: & json::Json) {
    println(fmt!("decoded: %?\n", json::Decoder(copy *repo).read_str(~"name")));
}

fn readJson(json: json::Json) {
    match json {
        json::List(l) => {
            println(fmt!("Got %? items", l.len()));
            //for l.consume_iter().advance |repo| {
            for l.iter().advance |repo| {
                println(fmt!("repo=%?\n\n", repo));
                handleRepo(repo)

                        //x.find_copy(~"name");
                        //let d: Repo = Decodable::decode(&mut json::Decoder(json));
                        //println(fmt!("%?\n", repo.contains_key(~"git_commits_url")));

                    /*json::Json.Object(orepo) => {
                        println(fmt!("%?\n", orepo.contains_key(~"git_commits_url")));
                    }*/

                /*
                match repo {
                    json::Object(repo) => {

                    },
                    _ => {
                        fail!("We expected a list of objects");
                    }
                }*/
            }

            println("A list of Objects, perhaps")
        }
        _ => {
            println("ERROR: Unrecognized JSON format")
        }
    }
}

fn main() {

    // http://ozten.com/psto/
    // https://api.github.com/repositories
    let u: Url = url::from_str("http://ozten.com/random/sample.json").get();
    let mut request = uv_http_request(u);

    let res = @mut RepoResponse{rawJson: ~[]};

    do request.begin |event| {
        match event {
            http_client::Error(e) => {
                println(fmt!("Ouch... error %?", e));
            },
            http_client::Status(s) =>
                match s {
                    // TODO wait... how did I break how match works here
                    // I should need the pattern guard.
                    StatusOK if s == StatusOK => {
                        println(fmt!("Status %?", s));
                        match json::from_str(res.rawJson.concat()) {
                            Ok(json) => {
                                readJson(json);
                            }
                            Err(e) => {
                                println(fmt!("Error parsing JSON %?", e));
                                fail!("Can't read JSON");
                            }
                        }
                    }
                    StatusFound if s == StatusFound => {
                        println(fmt!("Redirected? %?", s));
                    }
                    StatusUnknown => {
                        println(fmt!("hmmm status is unknown %?", s));
                        fail!("No JSON of Repositiories");
                    }
                },

            http_client::Payload(p) => {
                let data = p.take();
                res.rawJson.push(str::from_bytes(data));
            }
        }
    }

    // Problem #2 How to output parts of JSON after parsing
    // I think this is working...
    match json::from_str("{\"ham\": \"bone\"}") {
        Ok(obj) => {
            match obj {
                json::Object(o) => {
                    //println(fmt!("Payload! %?", o.get(& ~"ham")))
                }
                _ => { println("Skipping") }
            }

        }
        Err(e) => {
            println("Error")
        }
    }

    // HashMap play - One type of Json is Object which is a
    // type over HashMap<~str, Json>
    let mut h: HashMap<~str, ~str> = HashMap::new();
    h.insert(~"foo", ~"bar");
    h.get(& ~"foo");

    let mut a:~[~str] = ~[];
    a.push(~"Hello");
    a.push(~" World");
    //println(a.concat());
}<|endoftext|>


<commit_before>#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

#[macro_use]
extern crate clap;
extern crate requests;
extern crate serde;
extern crate serde_json;

use std::fmt;
use clap::{App, SubCommand, AppSettings};
mod crates;

const CARGO: &'static str = "cargo";

fn report(krate: crates::Reply) {

}

fn query(krate: &str) -> Option<crates::Reply> {
    let response = requests::get(&format!("http://crates.io/api/v1/crates/{}", krate)).unwrap();
    //println!("{:?}", response.json().unwrap());
    let reply = response.from_json::<crates::Reply>().unwrap();
    println!("{:?}", reply.krate);
    Some(reply)
}

fn debug<T>(item: &T) where T: fmt::Debug {
    println!("{:?}", item);
}

fn main() {

    let matches = App::new(CARGO)
                      .bin_name(CARGO)
                      //.author(crate_author!())
                      .version(crate_version!())
                      .about("Querys registry for crates details")
                      .setting(AppSettings::GlobalVersion)
                      .setting(AppSettings::VersionlessSubcommands)
                      .setting(AppSettings::SubcommandRequired)
                      .setting(AppSettings::ArgRequiredElseHelp)
                      .subcommand(SubCommand::with_name("info")
                                      .setting(AppSettings::ArgRequiredElseHelp)
                                      .setting(AppSettings::TrailingVarArg)
                                      .arg_from_usage("<crate>... 'crate to query'"))
                      .get_matches();

    if let Some(crates) = matches.subcommand_matches("info")
                                  .and_then(|m| m.values_of("crate")) {

        for krate in crates {
            debug(&krate);
            query(krate);
        }
    }
}
<commit_msg>Print crate data<commit_after>#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

#[macro_use]
extern crate clap;
extern crate requests;
extern crate serde;
extern crate serde_json;

use std::fmt;
use clap::{App, SubCommand, AppSettings};
mod crates;

const CARGO: &'static str = "cargo";

fn report(reply: crates::Reply) {
    println!("{}", reply.krate);
}

fn query(krate: &str) -> Option<crates::Reply> {
    let response = requests::get(&format!("http://crates.io/api/v1/crates/{}", krate)).unwrap();
    //println!("{:?}", response.json().unwrap());
    let reply = response.from_json::<crates::Reply>().unwrap();
    println!("{:#?}", reply.krate);
    Some(reply)
}

fn debug<T>(item: &T) where T: fmt::Debug {
    println!("{:#?}", item);
}

fn main() {

    let matches = App::new(CARGO)
                      .bin_name(CARGO)
                      //.author(crate_author!())
                      .version(crate_version!())
                      .about("Querys registry for crates details")
                      .setting(AppSettings::GlobalVersion)
                      .setting(AppSettings::VersionlessSubcommands)
                      .setting(AppSettings::SubcommandRequired)
                      .setting(AppSettings::ArgRequiredElseHelp)
                      .subcommand(SubCommand::with_name("info")
                                      .setting(AppSettings::ArgRequiredElseHelp)
                                      .setting(AppSettings::TrailingVarArg)
                                      .arg_from_usage("<crate>... 'crate to query'"))
                      .get_matches();

    if let Some(crates) = matches.subcommand_matches("info")
                                  .and_then(|m| m.values_of("crate")) {

        for krate in crates {
            debug(&krate);
            query(krate).map(report);
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

extern crate bencode;

use bencode::{Decodable, Decoder, DecodeError};

enum Info {
    Single,
    Multiple,
}

impl Decodable for Info {
    fn decode(_: &mut Decoder) -> Result<Info, DecodeError> {
        Ok(Info::Single)
    }
}

struct MetaInfo {
    info: Info,
}

impl Decodable for MetaInfo {
    fn decode(d: &mut Decoder) -> Result<MetaInfo, DecodeError> {
        d.read_struct(|d| {
            Ok(MetaInfo{
                info: try!(d.read_field("info"))
            })
        })
    }
}

fn main() {
    println!("hello");
}
<commit_msg>add basic decode example. decoding is done in place so bencode order matters<commit_after>#![allow(dead_code)]

extern crate bencode;

use bencode::{Decodable, Decoder, DecodeError};
use std::fs::File;
use std::io::{self, Read, Write};

struct SingleFile {
    length: i64,
    name: String,
    piece_length: usize,
    //pieces: Vec<u8>,
}
impl Decodable for SingleFile {
    fn decode(d: &mut Decoder) -> Result<SingleFile, DecodeError> {
        d.read_struct(|d| {
            Ok(SingleFile{
                length: try!(d.read_field("length")),
                name: try!(d.read_field("name")),
                piece_length: try!(d.read_field("piece length")),
                //pieces: try!(d.read_field("pieces")),
            })
        })
    }
}

struct MetaInfo {
    pub announce: String,
    pub created_by: String,
    pub comment: String,
    pub encoding: String,
    info: SingleFile,
}

fn read_string_with_default(d: &mut Decoder, field_name: &'static str, default: &'static str) -> String {
    match d.read_field(field_name) {
        Ok(field) => field,
        Err(_) => default.to_string(),
    }
}

impl Decodable for MetaInfo {
    fn decode(d: &mut Decoder) -> Result<MetaInfo, DecodeError> {
        d.read_struct(|d| {
            Ok(MetaInfo{
                announce: try!(d.read_field("announce")),
                comment: try!(d.read_field("comment")),
                created_by: read_string_with_default(d, "created by", ""),
                encoding: try!(d.read_field("encoding")),
                info: try!(d.read_field("info")),
            })
        })
    }
}

fn main() {
    let mut file = File::open("harry.torrent").expect("error opening file");
    let mut buf = Vec::new();
    let _ = file.read_to_end(&mut buf);
    let meta_info = bencode::decode::<MetaInfo>(&buf).unwrap();
    println!("GET {}", meta_info.announce);
    println!("name {}", meta_info.info.name);
    println!("total len {}", meta_info.info.length);
    println!("piece len {}", meta_info.info.piece_length);
    println!("created by {}", meta_info.created_by);
    println!("comment {}", meta_info.comment);
    println!("encoding {}", meta_info.encoding);
}
<|endoftext|>


<commit_before>#![allow(unused_must_use)]

mod irc;
mod vn64c;
mod demc;

#[macro_use]
extern crate regex;
extern crate toml;
extern crate time;

use std::fs::File;
use std::io::Read;

use regex::Regex;

use time::Duration;

use vn64c::{Controller, ButtonName};
use demc::DemC;
use demc::TimedInputCommand;
use vn64c::InputCommand;

const CONFIG_FILE_PATH: &'static str = "tppm.toml";
const VJOY_DEVICE_NUMBER: u8 = 1;
const IMPLICIT_CHAIN_DELAY: u32 = 500;

// Parse the TPPM toml configuration file; return the server, password, nick, and channel
fn parse_config_file() -> (String, String, String, String) {
    let mut config_file = File::open(CONFIG_FILE_PATH).unwrap();
    let mut config_string = String::new();
    config_file.read_to_string(&mut config_string);

    //@todo understand this generics magic
    let toml_tree: toml::Value = config_string.parse().unwrap();

    let server = String::from(toml_tree.lookup("irc.server").unwrap().as_str().unwrap());
    let pass = String::from(toml_tree.lookup("irc.pass").unwrap().as_str().unwrap());
    let nick = String::from(toml_tree.lookup("irc.nick").unwrap().as_str().unwrap());
    let channel = String::from(toml_tree.lookup("irc.channel").unwrap().as_str().unwrap());

    (server, pass, nick, channel)
}

// Attempt to parse an IRC message into a list of controller commands
//@todo just use a custom state machine rather than regex, this has to be insanely slow
//@todo this function is huge
fn parse_irc_message(msg: &String, re: &Regex) -> Option<Vec<TimedInputCommand>> {
    let mut last_cap_end = None;
    let mut cumulative_delay: u32 = 0;
    let mut last_command: Option<TimedInputCommand> = None;
    let mut cap_start_zero = false;
    let mut final_cap_end: usize = 0;
    let mut res: Vec<TimedInputCommand> = Vec::new();

    for cap in re.captures_iter(&msg.to_lowercase()) {
        let (cap_start, cap_end) = cap.pos(0).unwrap();

        // Raise a flag if this capture starts at the first string position - after iterating over all captures, we'll
        // make sure it was raised, and if it wasn't, we didn't parse a valid command message
        if cap_start == 0 {
            cap_start_zero = true;
        }

        // Make sure that all captures are continuous; that we're parsing commands and only commands
        // eg. we don't want "hahah" to parse as two "a" commands
        if let Some(last_cap_end) = last_cap_end {
            if last_cap_end != cap_start {
                return None;
            }
        }

        // Store the last capture's ending position - after iterating over all captures, we'll make sure the last one
        // ended
        final_cap_end = cap_end;

        // Our regex should match on exactly one of three groups: "joystick", "button", or "delay"
        if let Some(_) = cap.name("joystick") {
            match last_command {
                Some(command) => match command.command {
                    InputCommand::Joystick{direction: _, strength: _} => {
                        cumulative_delay += command.duration.num_milliseconds() as u32;
                        cumulative_delay += 17;
                    },
                    InputCommand::Button{name: _, value: _} => { cumulative_delay += IMPLICIT_CHAIN_DELAY }
                },
                None =>  ()
            }
            // joystick command - should have one, two, or four groups:
            // "joystick_strength" (optional)
            // "joystick_direction" (mandatory)
            // "joystick_duration" (optional),
            // "joystick_duration_units" (optional; must be present if joystick_duration is)
            let mut joystick_strength: f32 = 1.0;
            let mut joystick_direction: u16 = 0;
            let mut joystick_duration: u32 = 500;
            if let Some(jscap) = cap.name("joystick_strength") {
                let strength_u8: u8 = jscap.parse().unwrap();
                joystick_strength = strength_u8 as f32 / 100.0;
            }
            if let Some(jdcap) = cap.name("joystick_direction") {
                match jdcap {
                    "up" => { joystick_direction = 90; },
                    "down" => { joystick_direction = 270; },
                    "left" => { joystick_direction = 180; },
                    "right" => { joystick_direction = 0; },
                    _ => ()
                }
            } else {
                return None;
            }
            if let Some(jdcap) = cap.name("joystick_duration") {
                joystick_duration = jdcap.parse().unwrap();
                if let Some(jdcap_units) = cap.name("joystick_duration_units") {
                    if jdcap_units == "s" {
                        joystick_duration *= 1000;
                    }
                } else {
                    return None;
                }
            }

            // treat joystick commands with strength <0%, >100% or duration >5s as invalid
            if joystick_strength > 1.0 || joystick_strength < 0.0 || joystick_duration > 5000 {
                return None;
            }

            let time_now = time::get_time();
            let command = TimedInputCommand { start_time: time_now + time::Duration::milliseconds(cumulative_delay as i64),
                                                             duration: time::Duration::milliseconds(joystick_duration as i64),
                                                             command: InputCommand::Joystick { direction: joystick_direction,
                                                                                strength: joystick_strength} };
            res.push(command);

            last_command = Some(command.clone());
        } else if let Some(bcap) = cap.name("button") {
            match last_command {
                Some(command) => match command.command {
                    InputCommand::Joystick{direction: _, strength: _} => {
                        cumulative_delay += command.duration.num_milliseconds() as u32;
                    },
                    InputCommand::Button{name: _, value: _} => { cumulative_delay += IMPLICIT_CHAIN_DELAY }
                },
                None =>  ()
            }
            // button command - should have one or three groups:
            // "button_name" (mandatory)
            // "button_duration" (optional),
            // "button_duration_units" (optional; must be present if joystick_duration is)
            println!("button command: {:?}", bcap);

            let mut button_name;
            let mut button_duration: u32 = 167;

            if let Some(bncap) = cap.name("button_name") {
                button_name = match bncap {
                    "a" => ButtonName::A,
                    "b" => ButtonName::B,
                    "z" => ButtonName::Z,
                    "l" => ButtonName::L,
                    "r" => ButtonName::R,
                    "start" => ButtonName::Start,
                    "cup" => ButtonName::Cup,
                    "cdown" => ButtonName::Cdown,
                    "cleft" => ButtonName::Cleft,
                    "cright" => ButtonName::Cright,
                    "dup" => ButtonName::Dup,
                    "ddown" => ButtonName::Ddown,
                    "dleft" => ButtonName::Dleft,
                    "dright" => ButtonName::Dright,
                    _ => return None
                };
            } else {
                return None;
            }

            if let Some(bdcap) = cap.name("button_duration") {
                button_duration = bdcap.parse().unwrap();
                if let Some(bdcap_units) = cap.name("button_duration_units") {
                    if bdcap_units == "s" {
                        button_duration *= 1000;
                    }
                } else {
                    return None;
                }
            }

            let time_now = time::get_time();
            let command = TimedInputCommand { start_time: time_now + Duration::milliseconds(cumulative_delay as i64),
                                              duration: time::Duration::milliseconds(button_duration as i64),
                                              command: InputCommand::Button { name: button_name, value: true } };
            res.push(command);

            last_command = Some(command.clone());
        } else if let Some(dcap) = cap.name("delay") {
            // delay command - only one argument, the delay to insert
            println!("delay command: {:?}", dcap);
            match dcap {
                "+" => { cumulative_delay += 17; },
                "!" => { cumulative_delay += 217; },
                _ => { return None; }
            }
            last_command = None
        }

        last_cap_end = Some(cap_end);
    }

    if final_cap_end != msg.len() {
        return None;
    }

    if cap_start_zero != true {
        return None;
    }

    return Some(res);
}

fn main() {
    // Parse our configuration file
    let (server, pass, nick, channel) = parse_config_file();

    // Initialize a democratized virtual N64 controller
    let controller = Controller::new(VJOY_DEVICE_NUMBER).unwrap();
    let dem_controller = DemC::new(controller);

    // Start our IRC connection
    let irc_connection = irc::IrcConnection::spawn(server, pass, nick, channel).unwrap();

    // Our regex for parsing IRC messages - this is here so that it need not be instantiated every
    // time we handle an IRC message
    let re = Regex::new(r"\s*((?P<joystick>((?P<joystick_strength>[:digit:]+)%\s*)?(?P<joystick_direction>up|down|left|right)(\s*(?P<joystick_duration>[:digit:]+)(?P<joystick_duration_units>s|ms))?)|(?P<button>((?P<button_name>start|cup|cdown|cleft|cright|dup|ddown|dleft|dright|a|b|z|l|r)(\s*(?P<button_duration>[:digit:]+)(?P<button_duration_units>s|ms))?))|(?P<delay>[\+!]))\s*").unwrap();

    // Poll the IRC connection and handle its messages forever
    loop {
        match irc_connection.receive_privmsg() {
            Ok(msg_vec) => {
                //@todo remove this 1 hardcode (which is there to ignore the channel name parameter)
                match msg_vec.get(1) {
                    Some(string) => {
                        if let Some(cmds) = parse_irc_message(string, &re) {
                            for &cmd in cmds.iter() {
                                dem_controller.add_command(cmd);
                            }
                        }
                    },
                    _ => ()
                }
            },
            _ => ()
        }
    }
}
<commit_msg>Transition more smoothly between commands<commit_after>#![allow(unused_must_use)]

mod irc;
mod vn64c;
mod demc;

#[macro_use]
extern crate regex;
extern crate toml;
extern crate time;

use std::fs::File;
use std::io::Read;

use regex::Regex;

use time::Duration;

use vn64c::{Controller, ButtonName};
use demc::DemC;
use demc::TimedInputCommand;
use vn64c::InputCommand;

const CONFIG_FILE_PATH: &'static str = "tppm.toml";
const VJOY_DEVICE_NUMBER: u8 = 1;
const IMPLICIT_CHAIN_DELAY: u32 = 500;

// Parse the TPPM toml configuration file; return the server, password, nick, and channel
fn parse_config_file() -> (String, String, String, String) {
    let mut config_file = File::open(CONFIG_FILE_PATH).unwrap();
    let mut config_string = String::new();
    config_file.read_to_string(&mut config_string);

    //@todo understand this generics magic
    let toml_tree: toml::Value = config_string.parse().unwrap();

    let server = String::from(toml_tree.lookup("irc.server").unwrap().as_str().unwrap());
    let pass = String::from(toml_tree.lookup("irc.pass").unwrap().as_str().unwrap());
    let nick = String::from(toml_tree.lookup("irc.nick").unwrap().as_str().unwrap());
    let channel = String::from(toml_tree.lookup("irc.channel").unwrap().as_str().unwrap());

    (server, pass, nick, channel)
}

// Attempt to parse an IRC message into a list of controller commands
//@todo just use a custom state machine rather than regex, this has to be insanely slow
//@todo this function is huge
fn parse_irc_message(msg: &String, re: &Regex) -> Option<Vec<TimedInputCommand>> {
    let mut last_cap_end = None;
    let mut cumulative_delay: u32 = 0;
    let mut last_command: Option<TimedInputCommand> = None;
    let mut cap_start_zero = false;
    let mut final_cap_end: usize = 0;
    let mut res: Vec<TimedInputCommand> = Vec::new();

    for cap in re.captures_iter(&msg.to_lowercase()) {
        let (cap_start, cap_end) = cap.pos(0).unwrap();

        // Raise a flag if this capture starts at the first string position - after iterating over all captures, we'll
        // make sure it was raised, and if it wasn't, we didn't parse a valid command message
        if cap_start == 0 {
            cap_start_zero = true;
        }

        // Make sure that all captures are continuous; that we're parsing commands and only commands
        // eg. we don't want "hahah" to parse as two "a" commands
        if let Some(last_cap_end) = last_cap_end {
            if last_cap_end != cap_start {
                return None;
            }
        }

        // Store the last capture's ending position - after iterating over all captures, we'll make sure the last one
        // ended
        final_cap_end = cap_end;

        // Our regex should match on exactly one of three groups: "joystick", "button", or "delay"
        if let Some(_) = cap.name("joystick") {
            match last_command {
                Some(command) => match command.command {
                    InputCommand::Joystick{direction: _, strength: _} => {
                        cumulative_delay += command.duration.num_milliseconds() as u32;
                        cumulative_delay += 51;
                    },
                    InputCommand::Button{name: _, value: _} => { cumulative_delay += IMPLICIT_CHAIN_DELAY }
                },
                None =>  ()
            }
            // joystick command - should have one, two, or four groups:
            // "joystick_strength" (optional)
            // "joystick_direction" (mandatory)
            // "joystick_duration" (optional),
            // "joystick_duration_units" (optional; must be present if joystick_duration is)
            let mut joystick_strength: f32 = 1.0;
            let mut joystick_direction: u16 = 0;
            let mut joystick_duration: u32 = 500;
            if let Some(jscap) = cap.name("joystick_strength") {
                let strength_u8: u8 = jscap.parse().unwrap();
                joystick_strength = strength_u8 as f32 / 100.0;
            }
            if let Some(jdcap) = cap.name("joystick_direction") {
                match jdcap {
                    "up" => { joystick_direction = 90; },
                    "down" => { joystick_direction = 270; },
                    "left" => { joystick_direction = 180; },
                    "right" => { joystick_direction = 0; },
                    _ => ()
                }
            } else {
                return None;
            }
            if let Some(jdcap) = cap.name("joystick_duration") {
                joystick_duration = jdcap.parse().unwrap();
                if let Some(jdcap_units) = cap.name("joystick_duration_units") {
                    if jdcap_units == "s" {
                        joystick_duration *= 1000;
                    }
                } else {
                    return None;
                }
            }

            // treat joystick commands with strength <0%, >100% or duration >5s as invalid
            if joystick_strength > 1.0 || joystick_strength < 0.0 || joystick_duration > 5000 {
                return None;
            }

            let time_now = time::get_time();
            let command = TimedInputCommand { start_time: time_now + time::Duration::milliseconds(cumulative_delay as i64),
                                                             duration: time::Duration::milliseconds(joystick_duration as i64),
                                                             command: InputCommand::Joystick { direction: joystick_direction,
                                                                                strength: joystick_strength} };
            res.push(command);

            last_command = Some(command.clone());
        } else if let Some(bcap) = cap.name("button") {
            match last_command {
                Some(command) => match command.command {
                    InputCommand::Joystick{direction: _, strength: _} => {
                        cumulative_delay += command.duration.num_milliseconds() as u32;
                        if command.duration.num_milliseconds() >= 17 {
                            cumulative_delay -= 17;
                        }
                    },
                    InputCommand::Button{name: _, value: _} => { cumulative_delay += IMPLICIT_CHAIN_DELAY }
                },
                None =>  ()
            }
            // button command - should have one or three groups:
            // "button_name" (mandatory)
            // "button_duration" (optional),
            // "button_duration_units" (optional; must be present if joystick_duration is)
            println!("button command: {:?}", bcap);

            let mut button_name;
            let mut button_duration: u32 = 167;

            if let Some(bncap) = cap.name("button_name") {
                button_name = match bncap {
                    "a" => ButtonName::A,
                    "b" => ButtonName::B,
                    "z" => ButtonName::Z,
                    "l" => ButtonName::L,
                    "r" => ButtonName::R,
                    "start" => ButtonName::Start,
                    "cup" => ButtonName::Cup,
                    "cdown" => ButtonName::Cdown,
                    "cleft" => ButtonName::Cleft,
                    "cright" => ButtonName::Cright,
                    "dup" => ButtonName::Dup,
                    "ddown" => ButtonName::Ddown,
                    "dleft" => ButtonName::Dleft,
                    "dright" => ButtonName::Dright,
                    _ => return None
                };
            } else {
                return None;
            }

            if let Some(bdcap) = cap.name("button_duration") {
                button_duration = bdcap.parse().unwrap();
                if let Some(bdcap_units) = cap.name("button_duration_units") {
                    if bdcap_units == "s" {
                        button_duration *= 1000;
                    }
                } else {
                    return None;
                }
            }

            let time_now = time::get_time();
            let command = TimedInputCommand { start_time: time_now + Duration::milliseconds(cumulative_delay as i64),
                                              duration: time::Duration::milliseconds(button_duration as i64),
                                              command: InputCommand::Button { name: button_name, value: true } };
            res.push(command);

            last_command = Some(command.clone());
        } else if let Some(dcap) = cap.name("delay") {
            // delay command - only one argument, the delay to insert
            println!("delay command: {:?}", dcap);
            match dcap {
                "+" => { cumulative_delay += 17; },
                "!" => { cumulative_delay += 217; },
                _ => { return None; }
            }
            last_command = None
        }

        last_cap_end = Some(cap_end);
    }

    if final_cap_end != msg.len() {
        return None;
    }

    if cap_start_zero != true {
        return None;
    }

    return Some(res);
}

fn main() {
    // Parse our configuration file
    let (server, pass, nick, channel) = parse_config_file();

    // Initialize a democratized virtual N64 controller
    let controller = Controller::new(VJOY_DEVICE_NUMBER).unwrap();
    let dem_controller = DemC::new(controller);

    // Start our IRC connection
    let irc_connection = irc::IrcConnection::spawn(server, pass, nick, channel).unwrap();

    // Our regex for parsing IRC messages - this is here so that it need not be instantiated every
    // time we handle an IRC message
    let re = Regex::new(r"\s*((?P<joystick>((?P<joystick_strength>[:digit:]+)%\s*)?(?P<joystick_direction>up|down|left|right)(\s*(?P<joystick_duration>[:digit:]+)(?P<joystick_duration_units>s|ms))?)|(?P<button>((?P<button_name>start|cup|cdown|cleft|cright|dup|ddown|dleft|dright|a|b|z|l|r)(\s*(?P<button_duration>[:digit:]+)(?P<button_duration_units>s|ms))?))|(?P<delay>[\+!]))\s*").unwrap();

    // Poll the IRC connection and handle its messages forever
    loop {
        match irc_connection.receive_privmsg() {
            Ok(msg_vec) => {
                //@todo remove this 1 hardcode (which is there to ignore the channel name parameter)
                match msg_vec.get(1) {
                    Some(string) => {
                        if let Some(cmds) = parse_irc_message(string, &re) {
                            for &cmd in cmds.iter() {
                                dem_controller.add_command(cmd);
                            }
                        }
                    },
                    _ => ()
                }
            },
            _ => ()
        }
    }
}
<|endoftext|>


<commit_before>extern crate rand;

use std::string::String;
use std::collections::HashMap;
use std::vec::Vec;
use std::fs::{File};
use std::env;
use std::path::{Path};
use std::io::{self, BufReader, BufRead};
use std::iter;

use rand::{random, Closed01, Rng};
use rand::distributions::{IndependentSample, Range, Sample, Gamma};

type Bag = HashMap<usize, usize>;

fn load_bags<P: AsRef<Path>>(path: P) -> io::Result<(Vec<usize>, Vec<Bag>)> {
    let mut bags = Vec::new();
    let mut labels = Vec::new();
    let file = try!(File::open(path));
    let file = BufReader::new(file);
    for line in file.lines() {
        let line = line.unwrap();
        let mut iter = line.split_whitespace();
        let label = iter.next().unwrap().parse::<usize>().unwrap();
        let mut bag = Bag::new();
        for elm in iter {
            let mut iter = elm.split(':');
            let index = iter.next().unwrap().parse::<usize>().unwrap();
            let value = iter.next().unwrap().parse::<usize>().unwrap();
            bag.insert(index - 1, value);
        }
        labels.push(label);
        bags.push(bag);
    }
    Ok((labels, bags))
}

fn load_text_vocabulary<P: AsRef<Path>>(path: P) -> io::Result<Vec<String>> {
    let mut vocab = Vec::new();
    let file = try!(File::open(path));
    let file = BufReader::new(file);
    for line in file.lines() {
        let line = line.unwrap();
        vocab.push(line);
    }
    Ok(vocab)
}

#[derive(Clone)]
struct Categorical {
    prop: Vec<f64>,
}

impl Categorical {
    fn new(weights: Vec<f64>) -> Categorical {
        let sum: f64 = weights.iter().sum();
        let prop: Vec<f64> = weights.iter().map(|w| w / sum).collect();
        Categorical {
            prop: prop,
        }
    }
}

impl Sample<usize> for Categorical {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> usize {
        self.ind_sample(rng)
    }
}

impl IndependentSample<usize> for Categorical {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> usize {
        let Closed01(x) = random::<Closed01<f64>>();

        let mut sum = 0.0;
        let mut ret = self.prop.len() - 1;
        for (k, &p) in self.prop.iter().enumerate() {
            sum += p;
            if x <= sum {
                ret = k;
                break;
            }
        }
        ret
    }
}

#[derive(Clone)]
struct Dirichlet {
    alpha: Vec<f64>,
}

impl Dirichlet {
    fn new(alpha: Vec<f64>) -> Dirichlet {
        Dirichlet {
            alpha: alpha,
        }
    }
}

impl Sample<Vec<f64>> for Dirichlet {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Vec<f64> {
        self.ind_sample(rng)
    }
}

impl IndependentSample<Vec<f64>> for Dirichlet {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> Vec<f64> {
        let mut sum = 0.0;
        let mut xs = Vec::new();
        for &a in &self.alpha {
            let gamma = Gamma::new(a, 1.0);
            let y = gamma.ind_sample(rng);
            xs.push(y);
            sum += y;
        }
        for x in xs.iter_mut() {
            *x /= sum;
        }
        xs
    }
}

fn lda(num_topics: usize, dataset: Vec<Bag>, alpha: Vec<f64>, beta: Vec<f64>, burn_in: usize, num_samples: usize) {
    // Initialization
    let mut rng = rand::thread_rng();
    let topics = Range::new(0, num_topics);

    let vocab_size: usize = {
        let mut have_some = false;
        let mut max_index = 0;
        for bag in &dataset {
            for &index in bag.keys() {
                have_some = true;
                if index > max_index {
                    max_index = index;
                }
            }
        }
        if have_some {
            max_index + 1
        }
        else {
            0
        }
    };
    println!("K = {}", num_topics);
    println!("M = {}", &dataset.len());
    println!("V = {}", vocab_size);

    let mut w: Vec<Vec<usize>> = Vec::new();
    let mut z: Vec<Vec<usize>> = Vec::new();
    let mut z_samples: Vec<Vec<Vec<usize>>> = Vec::new();
    let mut theta: Vec<Vec<f64>> = Vec::new();
    let mut ndk: Vec<Vec<usize>> = Vec::new();
    for bag in &dataset {
        // w
        let mut w_d = Vec::new();
        for (&index, &count) in bag {
            for _ in 0..count {
                w_d.push(index);
            }
        }
        w.push(w_d);
        // z
        let mut z_d = Vec::new();
        let mut z_samples_d = Vec::new();
        for &count in bag.values() {
            for _ in 0..count {
                z_d.push(0);
                let zeros: Vec<usize> = iter::repeat(0).take(num_topics).collect();
                z_samples_d.push(zeros);
            }
        }
        let n_d = z_d.len();
        z.push(z_d);
        z_samples.push(z_samples_d);
        // theta
        let mut theta_d = Vec::with_capacity(num_topics);
        for _k in 0..num_topics {
            theta_d.push(1.0 / num_topics as f64);
        }
        theta.push(theta_d);
        // ndk
        let mut ndk_d = Vec::with_capacity(num_topics);
        ndk_d.push(n_d);
        for _k in 1..num_topics {
            ndk_d.push(0);
        }
        ndk.push(ndk_d);
    }
    println!("z = {:?}", z);
    println!("theta = {:?}", theta);
    println!("ndk = {:?}", ndk);

    let mut phi: Vec<Vec<f64>> = Vec::new();
    let mut nkv: Vec<Vec<usize>> = Vec::new();
    // phi
    for _k in 0..num_topics {
        let mut phi_k = Vec::new();
        for _v in 0..vocab_size {
            phi_k.push(1.0 / vocab_size as f64);
        }
        phi.push(phi_k);
    }
    // nkv
    let mut nkv_0 = Vec::new();
    for _v in 0..vocab_size {
        nkv_0.push(0);
    }
    for bag in &dataset {
        for (&index, &count) in bag {
            nkv_0[index] += count;
        }
    }
    nkv.push(nkv_0);
    for _k in 1..num_topics {
        let mut nkv_k = Vec::new();
        for _v in 0..vocab_size {
            nkv_k.push(0);
        }
        nkv.push(nkv_k);
    }
    println!("phi = {:?}", phi);
    println!("nkv = {:?}", nkv);

    // Sampling
    let mut rng = rand::thread_rng();
    for s in 0..(burn_in + num_samples) {
        for (d, w_d) in w.iter().enumerate() {
            for (i, &w_di) in w_d.iter().enumerate() {
                let v = w_di;
                // Sample z_di
                let mut weights: Vec<f64> = Vec::new();
                for k in 0..num_topics {
                    weights.push(theta[d][k] * phi[k][v]);
                }
                let cat = Categorical::new(weights);
                let old_z_di = z[d][i];
                let new_z_di = cat.ind_sample(&mut rng);
                z[d][i] = new_z_di;
                if s >= burn_in {
                    z_samples[d][i][new_z_di] += 1;
                }
                // Update ndk and nkv
                ndk[d][old_z_di] -= 1;
                ndk[d][new_z_di] += 1;
                nkv[old_z_di][v] -= 1;
                nkv[new_z_di][v] += 1;
            }
            // Sample theta_d
            let mut alpha_d: Vec<f64> = Vec::new();
            for k in 0..num_topics {
                alpha_d.push(ndk[d][k] as f64 + alpha[k]);
            }
            let dir = Dirichlet::new(alpha_d);
            theta[d] = dir.ind_sample(&mut rng);
        }
        for k in 0..num_topics {
            // Sample phi_k
            let mut beta_k: Vec<f64> = Vec::new();
            for v in 0..vocab_size {
                beta_k.push(nkv[k][v] as f64 + beta[v]);
            }
            let dir = Dirichlet::new(beta_k);
            phi[k] = dir.ind_sample(&mut rng);
        }
        // Evaluate the log-likelihood value for the current parameters
        let mut log_likelihood = 0.0;
        for k in 0..num_topics {
            for v in 0..vocab_size {
                log_likelihood += nkv[k][v] as f64 * f64::ln(phi[k][v]);
            }
        }
        println!("log_likelihood = {}", log_likelihood);
    }
    for (d, z_samples_d) in z_samples.iter().enumerate() {
        for (i, samples) in z_samples_d.iter().enumerate() {
            let mut sum = 0.0;
            for k in 0..num_topics {
                sum += samples[k] as f64;
            }
            println!("z[{}][{}] = ", d, i);
            for k in 0..num_topics {
                println!("{:.2}%", samples[k] as f64 / sum);
            }
        }
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let (labels, dataset) = load_bags(&args[1]).unwrap();
    let vocab: Option<Vec<String>> = if args.len() < 3 {
        None
    }
    else {
        Some(load_text_vocabulary(&args[2]).unwrap())
    };
    println!("{:?}", labels);
    println!("{:?}", dataset);
    println!("{:?}", vocab);

    let num_topics = 3;
    let alpha: Vec<f64> = iter::repeat(1.0).take(num_topics).collect();
    let beta: Vec<f64> = iter::repeat(1.0).take(vocab.unwrap().len()).collect();

    lda(num_topics, dataset, alpha, beta, 1000, 4000);
}
<commit_msg>Change the format of output<commit_after>extern crate rand;

use std::string::String;
use std::collections::HashMap;
use std::vec::Vec;
use std::fs::{File};
use std::env;
use std::path::{Path};
use std::io::{self, BufReader, BufRead};
use std::iter;

use rand::{random, Closed01, Rng};
use rand::distributions::{IndependentSample, Range, Sample, Gamma};

type Bag = HashMap<usize, usize>;

fn load_bags<P: AsRef<Path>>(path: P) -> io::Result<(Vec<usize>, Vec<Bag>)> {
    let mut bags = Vec::new();
    let mut labels = Vec::new();
    let file = try!(File::open(path));
    let file = BufReader::new(file);
    for line in file.lines() {
        let line = line.unwrap();
        let mut iter = line.split_whitespace();
        let label = iter.next().unwrap().parse::<usize>().unwrap();
        let mut bag = Bag::new();
        for elm in iter {
            let mut iter = elm.split(':');
            let index = iter.next().unwrap().parse::<usize>().unwrap();
            let value = iter.next().unwrap().parse::<usize>().unwrap();
            bag.insert(index - 1, value);
        }
        labels.push(label);
        bags.push(bag);
    }
    Ok((labels, bags))
}

fn load_text_vocabulary<P: AsRef<Path>>(path: P) -> io::Result<Vec<String>> {
    let mut vocab = Vec::new();
    let file = try!(File::open(path));
    let file = BufReader::new(file);
    for line in file.lines() {
        let line = line.unwrap();
        vocab.push(line);
    }
    Ok(vocab)
}

#[derive(Clone)]
struct Categorical {
    prop: Vec<f64>,
}

impl Categorical {
    fn new(weights: Vec<f64>) -> Categorical {
        let sum: f64 = weights.iter().sum();
        let prop: Vec<f64> = weights.iter().map(|w| w / sum).collect();
        Categorical {
            prop: prop,
        }
    }
}

impl Sample<usize> for Categorical {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> usize {
        self.ind_sample(rng)
    }
}

impl IndependentSample<usize> for Categorical {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> usize {
        let Closed01(x) = random::<Closed01<f64>>();

        let mut sum = 0.0;
        let mut ret = self.prop.len() - 1;
        for (k, &p) in self.prop.iter().enumerate() {
            sum += p;
            if x <= sum {
                ret = k;
                break;
            }
        }
        ret
    }
}

#[derive(Clone)]
struct Dirichlet {
    alpha: Vec<f64>,
}

impl Dirichlet {
    fn new(alpha: Vec<f64>) -> Dirichlet {
        Dirichlet {
            alpha: alpha,
        }
    }
}

impl Sample<Vec<f64>> for Dirichlet {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Vec<f64> {
        self.ind_sample(rng)
    }
}

impl IndependentSample<Vec<f64>> for Dirichlet {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> Vec<f64> {
        let mut sum = 0.0;
        let mut xs = Vec::new();
        for &a in &self.alpha {
            let gamma = Gamma::new(a, 1.0);
            let y = gamma.ind_sample(rng);
            xs.push(y);
            sum += y;
        }
        for x in xs.iter_mut() {
            *x /= sum;
        }
        xs
    }
}

fn lda(num_topics: usize, dataset: Vec<Bag>, alpha: Vec<f64>, beta: Vec<f64>, burn_in: usize, num_samples: usize) {
    // Initialization
    let mut rng = rand::thread_rng();
    let topics = Range::new(0, num_topics);

    let vocab_size: usize = {
        let mut have_some = false;
        let mut max_index = 0;
        for bag in &dataset {
            for &index in bag.keys() {
                have_some = true;
                if index > max_index {
                    max_index = index;
                }
            }
        }
        if have_some {
            max_index + 1
        }
        else {
            0
        }
    };
    println!("K = {}", num_topics);
    println!("M = {}", &dataset.len());
    println!("V = {}", vocab_size);

    let mut w: Vec<Vec<usize>> = Vec::new();
    let mut z: Vec<Vec<usize>> = Vec::new();
    let mut z_samples: Vec<Vec<Vec<usize>>> = Vec::new();
    let mut theta: Vec<Vec<f64>> = Vec::new();
    let mut ndk: Vec<Vec<usize>> = Vec::new();
    for bag in &dataset {
        // w
        let mut w_d = Vec::new();
        for (&index, &count) in bag {
            for _ in 0..count {
                w_d.push(index);
            }
        }
        w.push(w_d);
        // z
        let mut z_d = Vec::new();
        let mut z_samples_d = Vec::new();
        for &count in bag.values() {
            for _ in 0..count {
                z_d.push(0);
                let zeros: Vec<usize> = iter::repeat(0).take(num_topics).collect();
                z_samples_d.push(zeros);
            }
        }
        let n_d = z_d.len();
        z.push(z_d);
        z_samples.push(z_samples_d);
        // theta
        let mut theta_d = Vec::with_capacity(num_topics);
        for _k in 0..num_topics {
            theta_d.push(1.0 / num_topics as f64);
        }
        theta.push(theta_d);
        // ndk
        let mut ndk_d = Vec::with_capacity(num_topics);
        ndk_d.push(n_d);
        for _k in 1..num_topics {
            ndk_d.push(0);
        }
        ndk.push(ndk_d);
    }
    println!("z = {:?}", z);
    println!("theta = {:?}", theta);
    println!("ndk = {:?}", ndk);

    let mut phi: Vec<Vec<f64>> = Vec::new();
    let mut nkv: Vec<Vec<usize>> = Vec::new();
    // phi
    for _k in 0..num_topics {
        let mut phi_k = Vec::new();
        for _v in 0..vocab_size {
            phi_k.push(1.0 / vocab_size as f64);
        }
        phi.push(phi_k);
    }
    // nkv
    let mut nkv_0 = Vec::new();
    for _v in 0..vocab_size {
        nkv_0.push(0);
    }
    for bag in &dataset {
        for (&index, &count) in bag {
            nkv_0[index] += count;
        }
    }
    nkv.push(nkv_0);
    for _k in 1..num_topics {
        let mut nkv_k = Vec::new();
        for _v in 0..vocab_size {
            nkv_k.push(0);
        }
        nkv.push(nkv_k);
    }
    println!("phi = {:?}", phi);
    println!("nkv = {:?}", nkv);

    // Sampling
    let mut rng = rand::thread_rng();
    for s in 0..(burn_in + num_samples) {
        for (d, w_d) in w.iter().enumerate() {
            for (i, &w_di) in w_d.iter().enumerate() {
                let v = w_di;
                // Sample z_di
                let mut weights: Vec<f64> = Vec::new();
                for k in 0..num_topics {
                    weights.push(theta[d][k] * phi[k][v]);
                }
                let cat = Categorical::new(weights);
                let old_z_di = z[d][i];
                let new_z_di = cat.ind_sample(&mut rng);
                z[d][i] = new_z_di;
                if s >= burn_in {
                    z_samples[d][i][new_z_di] += 1;
                }
                // Update ndk and nkv
                ndk[d][old_z_di] -= 1;
                ndk[d][new_z_di] += 1;
                nkv[old_z_di][v] -= 1;
                nkv[new_z_di][v] += 1;
            }
            // Sample theta_d
            let mut alpha_d: Vec<f64> = Vec::new();
            for k in 0..num_topics {
                alpha_d.push(ndk[d][k] as f64 + alpha[k]);
            }
            let dir = Dirichlet::new(alpha_d);
            theta[d] = dir.ind_sample(&mut rng);
        }
        for k in 0..num_topics {
            // Sample phi_k
            let mut beta_k: Vec<f64> = Vec::new();
            for v in 0..vocab_size {
                beta_k.push(nkv[k][v] as f64 + beta[v]);
            }
            let dir = Dirichlet::new(beta_k);
            phi[k] = dir.ind_sample(&mut rng);
        }
        // Evaluate the log-likelihood value for the current parameters
        let mut log_likelihood = 0.0;
        for k in 0..num_topics {
            for v in 0..vocab_size {
                log_likelihood += nkv[k][v] as f64 * f64::ln(phi[k][v]);
            }
        }
        println!("log_likelihood = {}", log_likelihood);
    }
    for (d, z_samples_d) in z_samples.iter().enumerate() {
        for (i, samples) in z_samples_d.iter().enumerate() {
            let mut sum = 0.0;
            for k in 0..num_topics {
                sum += samples[k] as f64;
            }
            print!("z[{:3}][{:3}] = ", d, i);
            for k in 0..num_topics {
                print!("{:3}:{:.2} ", k, samples[k] as f64 / sum);
            }
            println!("");
        }
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let (labels, dataset) = load_bags(&args[1]).unwrap();
    let vocab: Option<Vec<String>> = if args.len() < 3 {
        None
    }
    else {
        Some(load_text_vocabulary(&args[2]).unwrap())
    };
    println!("{:?}", labels);
    println!("{:?}", dataset);
    println!("{:?}", vocab);

    let num_topics = 3;
    let alpha: Vec<f64> = iter::repeat(1.0).take(num_topics).collect();
    let beta: Vec<f64> = iter::repeat(1.0).take(vocab.unwrap().len()).collect();

    lda(num_topics, dataset, alpha, beta, 1000, 4000);
}
<|endoftext|>