<commit_before>//! Debugger commands
use std::convert::From;
use std::char;

use debugger::Debugger;

use synacor::{SynCpu, Data, Operation};

/// The commands runnable by the debugger
#[derive(Debug, PartialEq, Eq)]
pub enum Command {
    Registers,
    Help,
    Unknown,
    Step,
    Run,
    Quit,
    Breakpoint,
    Memory,
    Restart,
    Disassemble,
    DumpMemory,
    SetRegister,
    PrintStack,
}

impl<'a> From<&'a str> for Command {
    fn from(s: &'a str) -> Command {
        match s {
            "q" | "quit" => Command::Quit,
            "h" | "?" | "help" => Command::Help,
            "s" | "step" => Command::Step,
            "r" | "registers" => Command::Registers,
            "c" | "run" => Command::Run,
            "bp" | "breakpoint" => Command::Breakpoint,
            "m" | "memory" => Command::Memory,
            "restart" => Command::Restart,
            "list" | "l" => Command::Disassemble,
            "dump" => Command::DumpMemory,
            "set" => Command::SetRegister,
            "ps" | "stack" => Command::PrintStack,
            _ => Command::Unknown,
        }
    }
}

impl Command {
    pub fn execute(&self, dbg: &mut Debugger, args: &[&str]) {
        use self::Command::*;
        match *self {
            Help => {
                println!("The following commands are available. Short forms are listed\
                          in brackets after the long form. Options, if any are listed\
                          after the short forms");
                println!("\thelp (h, ?)               - Print this message");
                println!("\tstep (s) [n]              - Step through n instructions (default = 1)");
                println!("\tregisters (r)             - Print the registers");
                println!("\trun (c)                   - Run execution until a breakpoint is hit or the CPU halts.");
                println!("\tbreakpoint (bp)           - Set, unset, or list breakpoints.");
                println!("\tmemory (m) [lines] [addr] - Print 20 lines of 8 16-bit entries from RAM, starting at addr. Default lines = 10, default addr = pc");
                println!("\trestart                   - Restart the program.");
                println!("\tlist (l) [n] [addr]       - Disassemble the next n instructions, starting at addr. (default n = 10, addr = pc)");
                println!("\tdump [file]               - Dump the full contents of RAM to the specified file.");
            },
            Step => {
                let times = if args.is_empty() {
                    1
                } else if let Ok(n) = args[0].parse::<usize>() {
                    n
                } else {
                    println!("Usage: step [n] - n is an optional integer (default: 1), the number of steps to take.");
                    return;
                };

                for _ in 0..times {
                    println!(" [0x{:0>4x}]: {}",
                             dbg.cpu.pc,
                             dbg.cpu.peek_op());
                    dbg.cpu.step();
                }

            },
            Run => {
                dbg.cpu.run();
            },
            Registers => {
                println!("r0 = 0x{:0>4x}, r1 = 0x{:0>4x}, r2 = 0x{:0>4x}, r3 = 0x{:0>4x}",
                         dbg.cpu.data.registers[0],
                         dbg.cpu.data.registers[1],
                         dbg.cpu.data.registers[2],
                         dbg.cpu.data.registers[3]);
                println!("r4 = 0x{:0>4x}, r5 = 0x{:0>4x}, r6 = 0x{:0>4x}, r7 = 0x{:0>4x}",
                         dbg.cpu.data.registers[4],
                         dbg.cpu.data.registers[5],
                         dbg.cpu.data.registers[6],
                         dbg.cpu.data.registers[7]);
            },
            Breakpoint => {
                let usage = "breakpoint list         - Lists all breakpoints.\n\
                             breakpoint set [addr]   - Set a breakpoint at the given address.\n\
                             breakpoint unset [addr] - Unset the breakpoint at the given address.";
                if args.is_empty() {
                    println!("{}", usage);
                    return;
                }

                match args[0] {
                    "list" => {
                        println!("Set breakpoints:");
                        for addr in dbg.breakpoints.iter() {
                            println!("\t0x{:0>4x}", addr);
                        }
                    },
                    "set" => {
                        let addrs = (&args[1..]).iter()
                            .map(|addr| if addr.starts_with("0x") {
                                usize::from_str_radix(&addr[2..], 16)
                            } else {
                                usize::from_str_radix(addr, 16)
                            })
                            .filter(|addr| addr.is_ok())
                            .map(|addr| addr.unwrap());

                        for addr in addrs {
                            if Operation::is_valid(addr, &dbg.cpu.data.ram) {
                                dbg.cpu.data.ram[addr] |= 0xcc00;
                                dbg.breakpoints.insert(addr);
                                println!("Added breakpoint at 0x{:0>4x}", addr);
                            } else {
                                println!("Address 0x{:0>4x} is not a valid instruction",
                                         addr);
                            }
                        }
                    },
                    "unset" => {
                        let addrs = (&args[1..]).iter()
                            .map(|addr| if addr.starts_with("0x") {
                                usize::from_str_radix(&addr[2..], 16)
                            } else {
                                usize::from_str_radix(addr, 16)
                            })
                            .filter(|addr| addr.is_ok())
                            .map(|addr| addr.unwrap());

                        for addr in addrs {
                            if dbg.breakpoints.contains(&addr) {
                                dbg.breakpoints.remove(&addr);
                                dbg.cpu.data.ram[addr] &= 0x00ff;
                                println!("Breakpoint 0x{:0>4x} removed", addr);
                            } else {
                                println!("Address 0x{:0>4x} is not a breakpoint.",
                                         addr);
                            }
                        }
                    },
                    _ => {
                        println!("{}", usage);
                        return;
                    }
                }
            },
            Memory => {
                let start = if let Some(n) = args.get(0).and_then(|word| {
                    if word.starts_with("0x") {
                        usize::from_str_radix(&word[2..], 16).ok()
                    } else {
                        usize::from_str_radix(word, 16).ok()
                    }
                }) {
                    n
                } else {
                    dbg.cpu.pc as usize
                };

                let lines = if let Some(l) = args.get(1).and_then(|x| x.parse().ok()) {
                    l
                } else {
                    10
                };

                println!("addr  0000 1111 2222 3333 4444 5555 6666 7777  01234567");
                println!("-----|----|----|----|----|----|----|----|----||--------|");
                for j in 0..lines {
                    if start + 8*j > dbg.cpu.data.ram.len() {
                        break;
                    }
                    let mut hexs = String::new();
                    let mut printable = String::new();

                    print!("{:0>4x}: ", start + 8*j);

                    for i in 0..8 {
                        let offset = start + i + 8*j;
                        if offset >= dbg.cpu.data.ram.len() {
                            hexs.push_str("END!");
                            break;
                        }
                        let val = dbg.cpu.data.ram[offset];
                        if let Some(c) = char::from_u32(val as u32) {
                            if c.is_alphanumeric() {
                                printable.push(c);
                            } else {
                                printable.push('.');
                            }
                        } else {
                            printable.push('.');
                        }

                        hexs.push_str(&format!("{:0>4x} ", val));
                    }
                    println!("{:40} {}", hexs, printable);
                }
            },
            Restart => {
                let data = Data::from_bin(&dbg.original_binary).unwrap();
                dbg.cpu = SynCpu::new(data);
                dbg.cpu.stdin_buf = dbg.original_replay.clone();
            },
            Disassemble => {
                let n = if let Some(num) = args.get(0).and_then(|x| x.parse().ok()) {
                    num
                } else {
                    10
                };

                let mut pc = if let Some(num) = args.get(1).and_then(|x| x.parse().ok()) {
                    num
                } else {
                    dbg.cpu.pc
                };

                for _ in 0..n {
                    use synacor::Instruction::*;

                    let instr = dbg.cpu.peek_op_at(pc);
                    println!("0x{:0>4x}: {}", pc, instr);

                    pc += match instr.instr() {
                        Halt | Ret => 1,
                        Jmp(_) | Call(_) => 2,
                        Jt(_,_) | Jf(_,_) => 3,
                        x => x.size()
                    };
                }
            },
            DumpMemory => {
                use std::fs::File;
                use byteorder::{LittleEndian, WriteBytesExt};

                let mut fname = String::new();
                for word in args {
                    fname.push_str(word);
                }

                if fname.is_empty() {
                    println!("Please specify a file name for the output");
                    return;
                }

                let file = File::create(fname);
                if let Err(e) = file {
                    println!("Failed to create output file: {}", e);
                } else {
                    let mut file = file.unwrap();

                    for entry in dbg.cpu.data.ram.iter() {
                        file.write_u16::<LittleEndian>(*entry).unwrap();
                    }
                }
            },
            SetRegister => {
                let reg_num = if let Some(val) = args.get(0)
                    .and_then(|x| x.parse::<usize>().ok()) {
                        if val < 8 {
                            val
                        } else {
                            println!("Register number must be between 0 and 7");
                            return;
                        }
                    } else {
                        println!("Register number must be between 0 and 7");
                        return;
                    };

                let val = if let Some(val) = args.get(1)
                    .and_then(|x| x.parse::<u16>().ok()) {
                        val
                    } else {
                        println!("Register value must be a 16-bit unsigned integer.");
                        return;
                    };

                dbg.cpu.data.registers[reg_num] = val;
            },
            PrintStack => {
                println!("Stack contents: ");
                for (i, val) in dbg.cpu.data.stack.iter().enumerate() {
                    println!("\t[{}]: 0x{:0>4x}", i, val);
                }
            },
            Quit | Unknown => {}
        }
    }
}

<commit_msg>Added a debugger jump command<commit_after>//! Debugger commands
use std::collections::HashSet;
use std::convert::From;
use std::char;
use std::u16;

use debugger::Debugger;

use synacor::{SynCpu, Data, Operation};

/// The commands runnable by the debugger
#[derive(Debug, PartialEq, Eq)]
pub enum Command {
    Registers,
    Help,
    Unknown,
    Step,
    Run,
    Quit,
    Breakpoint,
    Memory,
    Restart,
    Disassemble,
    DumpMemory,
    SetRegister,
    PrintStack,
    Jump
}

impl<'a> From<&'a str> for Command {
    fn from(s: &'a str) -> Command {
        match s {
            "q" | "quit" => Command::Quit,
            "h" | "?" | "help" => Command::Help,
            "s" | "step" => Command::Step,
            "r" | "registers" => Command::Registers,
            "c" | "run" => Command::Run,
            "bp" | "breakpoint" => Command::Breakpoint,
            "m" | "memory" => Command::Memory,
            "restart" => Command::Restart,
            "list" | "l" => Command::Disassemble,
            "dump" => Command::DumpMemory,
            "set" => Command::SetRegister,
            "ps" | "stack" => Command::PrintStack,
            "jump" => Command::Jump,
            _ => Command::Unknown,
        }
    }
}

impl Command {
    pub fn execute(&self, dbg: &mut Debugger, args: &[&str]) {
        use self::Command::*;
        match *self {
            Help => {
                println!("The following commands are available. Short forms are listed \
                          in brackets after the long form. Options, if any are listed \
                          after the short forms");
                println!("\thelp (h, ?)               - Print this message");
                println!("\tstep (s) [n]              - Step through n instructions (default = 1)");
                println!("\tregisters (r)             - Print the registers");
                println!("\trun (c)                   - Run execution until a breakpoint is hit or the CPU halts.");
                println!("\tbreakpoint (bp)           - Set, unset, or list breakpoints.");
                println!("\tmemory (m) [lines] [addr] - Print 20 lines of 8 16-bit entries from RAM, starting at addr. Default lines = 10, default addr = pc");
                println!("\trestart                   - Restart the program.");
                println!("\tlist (l) [n] [addr]       - Disassemble the next n instructions, starting at addr. (default n = 10, addr = pc)");
                println!("\tdump [file]               - Dump the full contents of RAM to the specified file.");
                println!("\tset [n] [value]           - Set register n to the given (decimal) value.");
                println!("\tstack (ps)                - Print the contents of the stack.");
                println!("\tjump [addr]               - Set the programme counter to the given address (in hexadecimal).");
            },
            Step => {
                let times = if args.is_empty() {
                    1
                } else if let Ok(n) = args[0].parse::<usize>() {
                    n
                } else {
                    println!("Usage: step [n] - n is an optional integer (default: 1), the number of steps to take.");
                    return;
                };

                for _ in 0..times {
                    println!(" [0x{:0>4x}]: {}",
                             dbg.cpu.pc,
                             dbg.cpu.peek_op());
                    dbg.cpu.step();
                }

            },
            Run => {
                dbg.cpu.run();
            },
            Registers => {
                println!("r0 = 0x{:0>4x}, r1 = 0x{:0>4x}, r2 = 0x{:0>4x}, r3 = 0x{:0>4x}",
                         dbg.cpu.data.registers[0],
                         dbg.cpu.data.registers[1],
                         dbg.cpu.data.registers[2],
                         dbg.cpu.data.registers[3]);
                println!("r4 = 0x{:0>4x}, r5 = 0x{:0>4x}, r6 = 0x{:0>4x}, r7 = 0x{:0>4x}",
                         dbg.cpu.data.registers[4],
                         dbg.cpu.data.registers[5],
                         dbg.cpu.data.registers[6],
                         dbg.cpu.data.registers[7]);
            },
            Breakpoint => {
                let usage = "breakpoint list         - Lists all breakpoints.\n\
                             breakpoint set [addr]   - Set a breakpoint at the given address.\n\
                             breakpoint unset [addr] - Unset the breakpoint at the given address.";
                if args.is_empty() {
                    println!("{}", usage);
                    return;
                }

                match args[0] {
                    "list" => {
                        println!("Set breakpoints:");
                        for addr in dbg.breakpoints.iter() {
                            println!("\t0x{:0>4x}", addr);
                        }
                    },
                    "set" => {
                        let addrs = (&args[1..]).iter()
                            .map(|addr| if addr.starts_with("0x") {
                                usize::from_str_radix(&addr[2..], 16)
                            } else {
                                usize::from_str_radix(addr, 16)
                            })
                            .filter(|addr| addr.is_ok())
                            .map(|addr| addr.unwrap());

                        for addr in addrs {
                            if Operation::is_valid(addr, &dbg.cpu.data.ram) {
                                dbg.cpu.data.ram[addr] |= 0xcc00;
                                dbg.breakpoints.insert(addr);
                                println!("Added breakpoint at 0x{:0>4x}", addr);
                            } else {
                                println!("Address 0x{:0>4x} is not a valid instruction",
                                         addr);
                            }
                        }
                    },
                    "unset" => {
                        let addrs = (&args[1..]).iter()
                            .map(|addr| if addr.starts_with("0x") {
                                usize::from_str_radix(&addr[2..], 16)
                            } else {
                                usize::from_str_radix(addr, 16)
                            })
                            .filter(|addr| addr.is_ok())
                            .map(|addr| addr.unwrap());

                        for addr in addrs {
                            if dbg.breakpoints.contains(&addr) {
                                dbg.breakpoints.remove(&addr);
                                dbg.cpu.data.ram[addr] &= 0x00ff;
                                println!("Breakpoint 0x{:0>4x} removed", addr);
                            } else {
                                println!("Address 0x{:0>4x} is not a breakpoint.",
                                         addr);
                            }
                        }
                    },
                    _ => {
                        println!("{}", usage);
                        return;
                    }
                }
            },
            Memory => {
                let start = if let Some(n) = args.get(0).and_then(|word| {
                    if word.starts_with("0x") {
                        usize::from_str_radix(&word[2..], 16).ok()
                    } else {
                        usize::from_str_radix(word, 16).ok()
                    }
                }) {
                    n
                } else {
                    dbg.cpu.pc as usize
                };

                let lines = if let Some(l) = args.get(1).and_then(|x| x.parse().ok()) {
                    l
                } else {
                    10
                };

                println!("addr  0000 1111 2222 3333 4444 5555 6666 7777  01234567");
                println!("-----|----|----|----|----|----|----|----|----||--------|");
                for j in 0..lines {
                    if start + 8*j > dbg.cpu.data.ram.len() {
                        break;
                    }
                    let mut hexs = String::new();
                    let mut printable = String::new();

                    print!("{:0>4x}: ", start + 8*j);

                    for i in 0..8 {
                        let offset = start + i + 8*j;
                        if offset >= dbg.cpu.data.ram.len() {
                            hexs.push_str("END!");
                            break;
                        }
                        let val = dbg.cpu.data.ram[offset];
                        if let Some(c) = char::from_u32(val as u32) {
                            if c.is_alphanumeric() {
                                printable.push(c);
                            } else {
                                printable.push('.');
                            }
                        } else {
                            printable.push('.');
                        }

                        hexs.push_str(&format!("{:0>4x} ", val));
                    }
                    println!("{:40} {}", hexs, printable);
                }
            },
            Restart => {
                let data = Data::from_bin(&dbg.original_binary).unwrap();
                dbg.cpu = SynCpu::new(data);
                dbg.cpu.stdin_buf = dbg.original_replay.clone();
                dbg.breakpoints = HashSet::new();
            },
            Disassemble => {
                let n = if let Some(num) = args.get(0).and_then(|x| x.parse().ok()) {
                    num
                } else {
                    10
                };

                let mut pc = if let Some(num) = args.get(1).and_then(|x| x.parse().ok()) {
                    num
                } else {
                    dbg.cpu.pc
                };

                for _ in 0..n {
                    use synacor::Instruction::*;

                    let instr = dbg.cpu.peek_op_at(pc);
                    println!("0x{:0>4x}: {}", pc, instr);

                    pc += match instr.instr() {
                        Halt | Ret => 1,
                        Jmp(_) | Call(_) => 2,
                        Jt(_,_) | Jf(_,_) => 3,
                        x => x.size()
                    };
                }
            },
            DumpMemory => {
                use std::fs::File;
                use byteorder::{LittleEndian, WriteBytesExt};

                let mut fname = String::new();
                for word in args {
                    fname.push_str(word);
                }

                if fname.is_empty() {
                    println!("Please specify a file name for the output");
                    return;
                }

                let file = File::create(fname);
                if let Err(e) = file {
                    println!("Failed to create output file: {}", e);
                } else {
                    let mut file = file.unwrap();

                    for entry in dbg.cpu.data.ram.iter() {
                        file.write_u16::<LittleEndian>(*entry).unwrap();
                    }
                }
            },
            SetRegister => {
                let reg_num = if let Some(val) = args.get(0)
                    .and_then(|x| x.parse::<usize>().ok()) {
                        if val < 8 {
                            val
                        } else {
                            println!("Register number must be between 0 and 7");
                            return;
                        }
                    } else {
                        println!("Register number must be between 0 and 7");
                        return;
                    };

                let val = if let Some(val) = args.get(1)
                    .and_then(|x| x.parse::<u16>().ok()) {
                        val
                    } else {
                        println!("Register value must be a 16-bit unsigned integer.");
                        return;
                    };

                dbg.cpu.data.registers[reg_num] = val;
            },
            PrintStack => {
                println!("Stack contents: ");
                for (i, val) in dbg.cpu.data.stack.iter().enumerate() {
                    println!("\t[{}]: 0x{:0>4x}", i, val);
                }
            },
            Jump => {
                let offset = if let Some(val) = args.get(0)
                    .and_then(|x| if x.starts_with("0x") {
                        u16::from_str_radix(&x[2..], 16).ok()
                    }else {
                        u16::from_str_radix(x, 16).ok()
                    }) {
                        val
                    } else {
                        println!("Jump target must be a valid 16-bit hexadecimal unsigned integer.");
                        return;
                    };

                dbg.cpu.pc = offset;
            }
            Quit | Unknown => {}
        }
    }
}

<|endoftext|>


<commit_before>//! To run a LOGO program, run:
//!     cargo run --example logo_interpreter -- my_logo_program.txt

extern crate turtle;

use turtle::Turtle;
use std::env;
use std::fs::File;
use std::io::{BufRead, BufReader};

fn main() {
    let mut turtle = Turtle::new();

    let args: Vec<String> = env::args().collect();

    if args.len() != 2 {
        eprintln!("No file provided");
        std::process::exit(1);
    }

    let path = &args[1];
    let file = File::open(path).expect("Could not open provided program");
    let mut reader = BufReader::new(file);
    loop {
        let mut buffer = String::new();
        let read_bytes = reader
            .read_line(&mut buffer)
            .expect("Unable read input file");
        if read_bytes == 0 {
            // Reached EOF, stop interpreter
            break;
        }

        let cmd_args = buffer.split_whitespace();
        handle_command(&mut turtle, cmd_args);
    }
}

fn handle_command<'a, A: Iterator<Item = &'a str>>(turtle: &mut Turtle, mut args: A) {
    while let Some(command) = args.next() {
        match command {
            "fd" | "forward" => {
                let distance = parse_distance(
                    args.next()
                        .expect("Expected a distance value after fd/forward command"),
                );
                turtle.forward(distance);
            },
            "bk" | "back" => {
                let distance = parse_distance(
                    args.next()
                        .expect("Expect a distance value after bk/back command"),
                );
                turtle.backward(distance);
            },
            "lt" | "left" => {
                let distance = parse_distance(
                    args.next()
                        .expect("Expect a distance value after lt/left command"),
                );
                turtle.left(distance);
            },
            "rt" | "right" => {
                let distance = parse_distance(
                    args.next()
                        .expect("Expect a distance value after rt/right command"),
                );
                turtle.right(distance);
            },
            _ => unimplemented!("Use of invalid or unsupported LOGO command"),
        }
    }
}

fn parse_distance(s: &str) -> f64 {
    let dist: f64 = s.parse().expect("Not a valide number");
    dist
}
<commit_msg>Simple REPL added<commit_after>//! To run a LOGO program, run:
//!     cargo run --example logo_interpreter -- my_logo_program.txt

extern crate turtle;

use turtle::Turtle;
use std::env;
use std::fs::File;
use std::io::{self, BufRead, BufReader};

fn main() {
    let mut turtle = Turtle::new();

    let args: Vec<String> = env::args().collect();

    if args.len() != 2 {
        println!("Interactive LOGO Mode.\nType the commands in stdin.\nPress '^C' (cmd/ctrl+C) to exit");
        let stdin = io::stdin();
        let mut reader = BufReader::new(stdin);
        loop {
            let mut buffer = String::new();
            let _ = reader
                .read_line(&mut buffer)
                .expect("Unable read input from stdin");
                let cmd_args = buffer.split_whitespace();
                handle_command(&mut turtle, cmd_args);
        }
    }

    let path = &args[1];
    let file = File::open(path).expect("Could not open provided program");
    let mut reader = BufReader::new(file);
    loop {
        let mut buffer = String::new();
        let read_bytes = reader
            .read_line(&mut buffer)
            .expect("Unable read input file");
        if read_bytes == 0 {
            // Reached EOF, stop interpreter
            break;
        }

        let cmd_args = buffer.split_whitespace();
        handle_command(&mut turtle, cmd_args);
    }
}

fn handle_command<'a, A: Iterator<Item = &'a str>>(turtle: &mut Turtle, mut args: A) {
    while let Some(command) = args.next() {
        match command {
            "fd" | "forward" => {
                let distance = parse_distance(
                    args.next()
                        .expect("Expected a distance value after fd/forward command"),
                );
                turtle.forward(distance);
            },
            "bk" | "back" => {
                let distance = parse_distance(
                    args.next()
                        .expect("Expect a distance value after bk/back command"),
                );
                turtle.backward(distance);
            },
            "lt" | "left" => {
                let distance = parse_distance(
                    args.next()
                        .expect("Expect a distance value after lt/left command"),
                );
                turtle.left(distance);
            },
            "rt" | "right" => {
                let distance = parse_distance(
                    args.next()
                        .expect("Expect a distance value after rt/right command"),
                );
                turtle.right(distance);
            },
            _ => unimplemented!("Use of invalid or unsupported LOGO command"),
        }
    }
}

fn parse_distance(s: &str) -> f64 {
    let dist: f64 = s.parse().expect("Not a valide number");
    dist
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate stdweb;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;

use std::cell::RefCell;
use std::rc::Rc;

use stdweb::unstable::TryInto;
use stdweb::web::{
    IEventTarget,
    IElement,
    IHtmlElement,
    INode,
    HtmlElement,
    Element,
    document,
    window
};

use stdweb::web::event::{
    IEvent,
    IKeyboardEvent,
    DoubleClickEvent,
    ClickEvent,
    KeyPressEvent,
    ChangeEvent,
    BlurEvent,
    HashChangeEvent
};

use stdweb::web::html_element::InputElement;

// Shamelessly stolen from webplatform's TodoMVC example.
macro_rules! enclose {
    ( ($( $x:ident ),*) $y:expr ) => {
        {
            $(let $x = $x.clone();)*
            $y
        }
    };
}

#[derive(Clone, Serialize, Deserialize)]
struct Todo {
    title: String,
    completed: bool
}

#[derive(Serialize, Deserialize)]
struct State {
    todo_list: Vec< Todo >
}

impl State {
    fn new() -> Self {
        State {
            todo_list: Vec::new()
        }
    }
}

type StateRef = Rc< RefCell< State > >;

fn start_editing( state: &StateRef, index: usize, li: &HtmlElement, label: &Element ) {
    li.class_list().add( "editing" );

    let edit: InputElement = document().create_element( "input" ).try_into().unwrap();
    edit.class_list().add( "edit" );
    edit.set_value( label.inner_text() );
    edit.add_event_listener( enclose!( (edit) move |event: KeyPressEvent| {
        if event.key() == "Enter" {
            edit.blur();
        }
    }));

    edit.add_event_listener( enclose!( (state, li, edit) move |_: BlurEvent| {
        li.class_list().remove( "editing" );
        li.remove_child( &edit ).unwrap();
        state.borrow_mut().todo_list[ index ].title = edit.value().into_string().unwrap();
        update_dom( &state );
    }));

    li.append_child( &edit );
    edit.focus();
}

fn create_entry( state: &StateRef, index: usize, text: &str ) -> HtmlElement {
    let li: HtmlElement = document().create_element( "li" ).try_into().unwrap();
    let div = document().create_element( "div" );
    let checkbox: InputElement = document().create_element( "input" ).try_into().unwrap();
    let label = document().create_element( "label" );
    let button = document().create_element( "button" );

    div.class_list().add( "view" );

    checkbox.class_list().add( "toggle" );
    checkbox.set_kind( "checkbox" );
    checkbox.add_event_listener( enclose!( (state, checkbox) move |_: ChangeEvent| {
        let checked: bool = js!( return @{&checkbox}.checked; ).try_into().unwrap();
        state.borrow_mut().todo_list[ index ].completed = checked;
        update_dom( &state );
    }));

    label.append_child( &document().create_text_node( text ) );
    label.add_event_listener( enclose!( (state, li, label) move |_: DoubleClickEvent| {
        start_editing( &state, index, &li, &label );
    }));

    button.class_list().add( "destroy" );
    button.add_event_listener( enclose!( (state) move |_: ClickEvent| {
        state.borrow_mut().todo_list.remove( index );
        update_dom( &state );
    }));

    li.append_child( &div );
    div.append_child( &checkbox );
    div.append_child( &label );
    div.append_child( &button );

    li
}

fn update_dom( state: &StateRef ) {
    // Ideally you'd use some kind of DOM diffing here;
    // since it's supposed to be a simple example we opt
    // for the nuclear option and just rebuild everything
    // from scratch.

    fn only_active( todo: &Todo ) -> bool { todo.completed == false }
    fn only_completed( todo: &Todo ) -> bool { todo.completed == true }
    fn all( _: &Todo ) -> bool { true }

    // See which filter we're supposed to use based on the URL.
    let hash = document().location().unwrap().hash();
    let filter = match hash.as_str() {
        "#/active" => only_active,
        "#/completed" => only_completed,
        _ => all
    };

    let filter_anchor_selector = match hash.as_str() {
        "#/active" | "#/completed" => hash.as_str(),
        _ => "#/"
    };

    // Select the filter "button".
    let filter_anchors = document().query_selector_all( ".filters a" );
    for anchor in &filter_anchors {
        let anchor: Element = anchor.try_into().unwrap();
        anchor.class_list().remove( "selected" );
    }

    let filter_anchor_selector = format!( ".filters a[href='{}']", filter_anchor_selector );
    let selected_anchor: Element = document().query_selector( filter_anchor_selector.as_str() ).unwrap().try_into().unwrap();
    selected_anchor.class_list().add( "selected" );

    // Clear previous entries in the list.
    let list = document().query_selector( ".todo-list" ).unwrap();
    while let Some( child ) = list.first_child() {
        list.remove_child( &child ).unwrap();
    }

    // Fill out the list.
    let state_borrow = state.borrow();
    for (index, todo) in state_borrow.todo_list.iter().enumerate().filter( |&(_, todo)| filter( todo ) ) {
        let entry_node = create_entry( state, index, todo.title.as_str() );
        if todo.completed {
            entry_node.class_list().add( "completed" );
            let checkbox = entry_node.query_selector( "input[type='checkbox']" ).unwrap();
            js!( @{checkbox}.checked = true; );
        }
        list.append_child( &entry_node );
    }

    // Display the amount of active TODOs lefs.
    let items_left = state_borrow.todo_list.iter().filter( |todo| {
        todo.completed == false
    }).count();

    let counter_display = document().query_selector( ".todo-count" ).unwrap();
    if items_left == 1 {
        counter_display.set_text_content( "1 item left" );
    } else {
        counter_display.set_text_content( format!( "{} items left", items_left ).as_str() );
    }

    // Hide the list if we don't have any TODOs.
    let main = document().query_selector( ".main" ).unwrap();
    if state_borrow.todo_list.is_empty() {
        js!( @{main}.style = "display: none;" );
    } else {
        js!( @{main}.style = "display: block;" );
    }

    // Save the state into local storage.
    let state_json = serde_json::to_string( &*state_borrow ).unwrap();
    window().local_storage().insert( "state", state_json.as_str() );
}

fn main() {
    stdweb::initialize();

    let state = window().local_storage().get( "state" ).and_then( |state_json| {
        serde_json::from_str( state_json.as_str() ).ok()
    }).unwrap_or_else( State::new );
    let state = Rc::new( RefCell::new( state ) );

    let title_entry: InputElement = document().query_selector( ".new-todo" ).unwrap().try_into().unwrap();
    title_entry.add_event_listener( enclose!( (state, title_entry) move |event: KeyPressEvent| {
        if event.key() == "Enter" {
            event.prevent_default();

            let title: String = title_entry.value().try_into().unwrap();
            if title.is_empty() == false {
                state.borrow_mut().todo_list.push( Todo {
                    title: title,
                    completed: false
                });

                title_entry.set_value( "" );
                update_dom( &state );
            }
        }
    }));

    let clear_completed = document().query_selector( ".clear-completed" ).unwrap();
    clear_completed.add_event_listener( enclose!( (state) move |_: ClickEvent| {
        state.borrow_mut().todo_list.retain( |todo| todo.completed == false );
        update_dom( &state );
    }));

    window().add_event_listener( enclose!( (state) move |_: HashChangeEvent| {
        update_dom( &state );
    }));

    update_dom( &state );
    stdweb::event_loop();
}
<commit_msg>Fix `todomvc` example<commit_after>#[macro_use]
extern crate stdweb;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;

use std::cell::RefCell;
use std::rc::Rc;

use stdweb::unstable::TryInto;
use stdweb::web::{
    IEventTarget,
    IElement,
    IHtmlElement,
    INode,
    IParentNode,
    HtmlElement,
    Element,
    document,
    window
};

use stdweb::web::event::{
    IEvent,
    IKeyboardEvent,
    DoubleClickEvent,
    ClickEvent,
    KeyPressEvent,
    ChangeEvent,
    BlurEvent,
    HashChangeEvent
};

use stdweb::web::html_element::InputElement;

// Shamelessly stolen from webplatform's TodoMVC example.
macro_rules! enclose {
    ( ($( $x:ident ),*) $y:expr ) => {
        {
            $(let $x = $x.clone();)*
            $y
        }
    };
}

#[derive(Clone, Serialize, Deserialize)]
struct Todo {
    title: String,
    completed: bool
}

#[derive(Serialize, Deserialize)]
struct State {
    todo_list: Vec< Todo >
}

impl State {
    fn new() -> Self {
        State {
            todo_list: Vec::new()
        }
    }
}

type StateRef = Rc< RefCell< State > >;

fn start_editing( state: &StateRef, index: usize, li: &HtmlElement, label: &HtmlElement ) {
    li.class_list().add( "editing" ).unwrap();

    let edit: InputElement = document().create_element( "input" ).unwrap().try_into().unwrap();
    edit.class_list().add( "edit" ).unwrap();
    edit.set_value( label.inner_text() );
    edit.add_event_listener( enclose!( (edit) move |event: KeyPressEvent| {
        if event.key() == "Enter" {
            edit.blur();
        }
    }));

    edit.add_event_listener( enclose!( (state, li, edit) move |_: BlurEvent| {
        li.class_list().remove( "editing" ).unwrap();
        li.remove_child( &edit ).unwrap();
        state.borrow_mut().todo_list[ index ].title = edit.value().into_string().unwrap();
        update_dom( &state );
    }));

    li.append_child( &edit );
    edit.focus();
}

fn create_entry( state: &StateRef, index: usize, text: &str ) -> HtmlElement {
    let li: HtmlElement = document().create_element( "li" ).unwrap().try_into().unwrap();
    let div = document().create_element( "div" ).unwrap();
    let checkbox: InputElement = document().create_element( "input" ).unwrap().try_into().unwrap();
    let label: HtmlElement = document().create_element( "label" ).unwrap().try_into().unwrap();
    let button = document().create_element( "button" ).unwrap();

    div.class_list().add( "view" ).unwrap();

    checkbox.class_list().add( "toggle" ).unwrap();
    checkbox.set_kind( "checkbox" );
    checkbox.add_event_listener( enclose!( (state, checkbox) move |_: ChangeEvent| {
        let checked: bool = js!( return @{&checkbox}.checked; ).try_into().unwrap();
        state.borrow_mut().todo_list[ index ].completed = checked;
        update_dom( &state );
    }));

    label.append_child( &document().create_text_node( text ) );
    label.add_event_listener( enclose!( (state, li, label) move |_: DoubleClickEvent| {
        start_editing( &state, index, &li, &label );
    }));

    button.class_list().add( "destroy" ).unwrap();
    button.add_event_listener( enclose!( (state) move |_: ClickEvent| {
        state.borrow_mut().todo_list.remove( index );
        update_dom( &state );
    }));

    li.append_child( &div );
    div.append_child( &checkbox );
    div.append_child( &label );
    div.append_child( &button );

    li
}

fn update_dom( state: &StateRef ) {
    // Ideally you'd use some kind of DOM diffing here;
    // since it's supposed to be a simple example we opt
    // for the nuclear option and just rebuild everything
    // from scratch.

    fn only_active( todo: &Todo ) -> bool { todo.completed == false }
    fn only_completed( todo: &Todo ) -> bool { todo.completed == true }
    fn all( _: &Todo ) -> bool { true }

    // See which filter we're supposed to use based on the URL.
    let hash = document().location().unwrap().hash().unwrap();
    let filter = match hash.as_str() {
        "#/active" => only_active,
        "#/completed" => only_completed,
        _ => all
    };

    let filter_anchor_selector = match hash.as_str() {
        "#/active" | "#/completed" => hash.as_str(),
        _ => "#/"
    };

    // Select the filter "button".
    let filter_anchors = document().query_selector_all( ".filters a" ).unwrap();
    for anchor in &filter_anchors {
        let anchor: Element = anchor.try_into().unwrap();
        anchor.class_list().remove( "selected" ).unwrap();
    }

    let filter_anchor_selector = format!( ".filters a[href='{}']", filter_anchor_selector );
    let selected_anchor: Element = document().query_selector( filter_anchor_selector.as_str() ).unwrap().unwrap().try_into().unwrap();
    selected_anchor.class_list().add( "selected" ).unwrap();

    // Clear previous entries in the list.
    let list = document().query_selector( ".todo-list" ).unwrap().unwrap();
    while let Some( child ) = list.first_child() {
        list.remove_child( &child ).unwrap();
    }

    // Fill out the list.
    let state_borrow = state.borrow();
    for (index, todo) in state_borrow.todo_list.iter().enumerate().filter( |&(_, todo)| filter( todo ) ) {
        let entry_node = create_entry( state, index, todo.title.as_str() );
        if todo.completed {
            entry_node.class_list().add( "completed" ).unwrap();
            let checkbox = entry_node.query_selector( "input[type='checkbox']" ).unwrap();
            js!( @{checkbox}.checked = true; );
        }
        list.append_child( &entry_node );
    }

    // Display the amount of active TODOs lefs.
    let items_left = state_borrow.todo_list.iter().filter( |todo| {
        todo.completed == false
    }).count();

    let counter_display = document().query_selector( ".todo-count" ).unwrap().unwrap();
    if items_left == 1 {
        counter_display.set_text_content( "1 item left" );
    } else {
        counter_display.set_text_content( format!( "{} items left", items_left ).as_str() );
    }

    // Hide the list if we don't have any TODOs.
    let main = document().query_selector( ".main" ).unwrap();
    if state_borrow.todo_list.is_empty() {
        js!( @{main}.style = "display: none;" );
    } else {
        js!( @{main}.style = "display: block;" );
    }

    // Save the state into local storage.
    let state_json = serde_json::to_string( &*state_borrow ).unwrap();
    window().local_storage().insert( "state", state_json.as_str() ).unwrap();
}

fn main() {
    stdweb::initialize();

    let state = window().local_storage().get( "state" ).and_then( |state_json| {
        serde_json::from_str( state_json.as_str() ).ok()
    }).unwrap_or_else( State::new );
    let state = Rc::new( RefCell::new( state ) );

    let title_entry: InputElement = document().query_selector( ".new-todo" ).unwrap().unwrap().try_into().unwrap();
    title_entry.add_event_listener( enclose!( (state, title_entry) move |event: KeyPressEvent| {
        if event.key() == "Enter" {
            event.prevent_default();

            let title: String = title_entry.value().try_into().unwrap();
            if title.is_empty() == false {
                state.borrow_mut().todo_list.push( Todo {
                    title: title,
                    completed: false
                });

                title_entry.set_value( "" );
                update_dom( &state );
            }
        }
    }));

    let clear_completed = document().query_selector( ".clear-completed" ).unwrap().unwrap();
    clear_completed.add_event_listener( enclose!( (state) move |_: ClickEvent| {
        state.borrow_mut().todo_list.retain( |todo| todo.completed == false );
        update_dom( &state );
    }));

    window().add_event_listener( enclose!( (state) move |_: HashChangeEvent| {
        update_dom( &state );
    }));

    update_dom( &state );
    stdweb::event_loop();
}
<|endoftext|>


<commit_before>//! Algorithm module for executing Algorithmia algorithms
//!
//! # Examples
//!
//! ```no_run
//! use algorithmia::Algorithmia;
//! use algorithmia::algo::{Algorithm, AlgoOutput, Version};
//!
//! // Initialize with an API key
//! let client = Algorithmia::client("111112222233333444445555566");
//! let moving_avg = client.algo("timeseries", "SimpleMovingAverage", Version::Minor(0,1));
//!
//! // Run the algorithm using a type safe decoding of the output to Vec<int>
//! //   since this algorithm outputs results as a JSON array of integers
//! let input = (vec![0,1,2,3,15,4,5,6,7], 3);
//! let output: AlgoOutput<Vec<f64>> = moving_avg.pipe(&input).unwrap();
//! println!("Completed in {} seconds with result: {:?}", output.metadata.duration, output.result);
//! ```

extern crate hyper;

use Algorithmia;
use hyper::Url;
use rustc_serialize::{json, Decodable, Encodable};
use std::io::Read;
use hyper::header::ContentType;
use hyper::mime::{Mime, TopLevel, SubLevel};
use super::result::{AlgoResult, JsonResult, AlgoOutput};

static ALGORITHM_BASE_PATH: &'static str = "v1/algo";

/// Algorithmia algorithm
pub struct Algorithm {
    pub path: String,
    client: Algorithmia,
}

impl Algorithm {
    pub fn new(client: Algorithmia, algo_uri: &str) -> Algorithm {
        let path = match algo_uri {
            p if p.starts_with("algo://") => &p[7..],
            p if p.starts_with("/") => &p[1..],
            p => p,
        };

        Algorithm {
            client: client,
            path: path.to_string(),
        }
    }

    /// Get the API Endpoint URL for this Algorithm
    pub fn to_url(&self) -> Url {
        let url_string = format!("{}/{}/{}", self.client.base_url, ALGORITHM_BASE_PATH, self.path);
        Url::parse(&url_string).unwrap()
    }

    /// Get the Algorithmia algo URI for this Algorithm
    pub fn to_algo_uri(&self) -> String {
        format!("algo://{}", self.path)
    }

    /// Execute an algorithm with typed JSON response decoding
    ///
    /// input_data must be JSON-encodable
    ///     use `#[derive(RustcEncodable)]` for complex input
    ///
    /// You must explicitly specify the output type `T`
    ///     `pipe` will attempt to decode the response into AlgoOutput<T>
    ///
    /// If decoding fails, it will attempt to decode into `ApiError`
    ///     and if that fails, it will error with `DecoderErrorWithContext`
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # use algorithmia::{Algorithmia, AlgorithmiaError};
    /// # use algorithmia::algo::{Algorithm, AlgoOutput, Version};
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let moving_avg = client.algo("timeseries", "SimpleMovingAverage", Version::Minor(0,1));
    /// let input = (vec![0,1,2,3,15,4,5,6,7], 3);
    /// match moving_avg.pipe(&input) {
    ///     Ok(out) => {
    ///         let myVal: AlgoOutput<Vec<f64>> = out;
    ///         println!("{:?}", myVal.result);
    ///     },
    ///     Err(e) => println!("ERROR: {:?}", e),
    /// };
    /// ```
    pub fn pipe<D, E>(&self, input_data: &E) -> AlgoResult<D>
            where D: Decodable,
                  E: Encodable {
        let raw_input = try!(json::encode(input_data));
        let res_json = try!(self.pipe_json(&raw_input, Mime(TopLevel::Application, SubLevel::Json, vec![])));

        Algorithmia::decode_to_result::<AlgoOutput<D>>(res_json)
    }

    /// pipeute an algorithm with with string input and receive the raw JSON response
    ///
    /// `pipe` provides a JSON encoding/decoding wrapper around this method
    ///
    /// TODO: Consider using byte slice input and output instead of strings
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # use algorithmia::Algorithmia;
    /// # use algorithmia::algo::{Algorithm, Version};
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let minmax  = client.algo("codeb34v3r", "FindMinMax", Version::Minor(0,1));
    ///
    /// let output = match minmax.pipe_json("[2,3,4]", "application/json".parse().unwrap()) {
    ///    Ok(result) => result,
    ///    Err(why) => panic!("{:?}", why),
    /// };
    pub fn pipe_json(&self, input_data: &str, content_type: Mime) -> JsonResult {
        let http_client = self.client.http_client();
        let req = http_client.post(self.to_url())
            .header(ContentType(content_type))
            .body(input_data);

        let mut res = try!(req.send());
        let mut res_string = String::new();
        try!(res.read_to_string(&mut res_string));
        Ok(res_string)
    }

}

#[cfg(test)]
mod tests {
    use Algorithmia;
    use algo::version::Version;

    fn mock_client() -> Algorithmia { Algorithmia::client("") }

    #[test]
    fn test_algo_without_version_to_url() {
        let mock_client = mock_client();
        let algorithm = mock_client.algo_from_str("/anowell/Pinky");
        assert_eq!(algorithm.to_url().serialize(), format!("{}/v1/algo/anowell/Pinky", algorithm.client.base_url));
    }

    #[test]
    fn test_algo_without_prefix_to_url() {
        let mock_client = mock_client();
        let algorithm = mock_client.algo_from_str("anowell/Pinky/0.1.0");
        assert_eq!(algorithm.to_url().serialize(), format!("{}/v1/algo/anowell/Pinky/0.1.0", algorithm.client.base_url));
    }

    #[test]
    fn test_algo_with_prefix_to_url() {
        let mock_client = mock_client();
        let algorithm = mock_client.algo_from_str("algo://anowell/Pinky/0.1");
        assert_eq!(algorithm.to_url().serialize(), format!("{}/v1/algo/anowell/Pinky/0.1", algorithm.client.base_url));
    }

    #[test]
    fn test_algo_typesafe_to_url() {
        let mock_client = mock_client();
        let algorithm = mock_client.algo("anowell", "Pinky", Version::Hash("abcdef123456"));
        assert_eq!(algorithm.to_url().serialize(), format!("{}/v1/algo/anowell/Pinky/abcdef123456", algorithm.client.base_url));
    }
}
<commit_msg>pipe_json renamed back to pipe_raw<commit_after>//! Algorithm module for executing Algorithmia algorithms
//!
//! # Examples
//!
//! ```no_run
//! use algorithmia::Algorithmia;
//! use algorithmia::algo::{Algorithm, AlgoOutput, Version};
//!
//! // Initialize with an API key
//! let client = Algorithmia::client("111112222233333444445555566");
//! let moving_avg = client.algo("timeseries", "SimpleMovingAverage", Version::Minor(0,1));
//!
//! // Run the algorithm using a type safe decoding of the output to Vec<int>
//! //   since this algorithm outputs results as a JSON array of integers
//! let input = (vec![0,1,2,3,15,4,5,6,7], 3);
//! let output: AlgoOutput<Vec<f64>> = moving_avg.pipe(&input).unwrap();
//! println!("Completed in {} seconds with result: {:?}", output.metadata.duration, output.result);
//! ```

extern crate hyper;

use Algorithmia;
use hyper::Url;
use rustc_serialize::{json, Decodable, Encodable};
use std::io::Read;
use hyper::header::ContentType;
use hyper::mime::{Mime, TopLevel, SubLevel};
use super::result::{AlgoResult, JsonResult, AlgoOutput};

static ALGORITHM_BASE_PATH: &'static str = "v1/algo";

/// Algorithmia algorithm
pub struct Algorithm {
    pub path: String,
    client: Algorithmia,
}

impl Algorithm {
    pub fn new(client: Algorithmia, algo_uri: &str) -> Algorithm {
        let path = match algo_uri {
            p if p.starts_with("algo://") => &p[7..],
            p if p.starts_with("/") => &p[1..],
            p => p,
        };

        Algorithm {
            client: client,
            path: path.to_string(),
        }
    }

    /// Get the API Endpoint URL for this Algorithm
    pub fn to_url(&self) -> Url {
        let url_string = format!("{}/{}/{}", self.client.base_url, ALGORITHM_BASE_PATH, self.path);
        Url::parse(&url_string).unwrap()
    }

    /// Get the Algorithmia algo URI for this Algorithm
    pub fn to_algo_uri(&self) -> String {
        format!("algo://{}", self.path)
    }

    /// Execute an algorithm with typed JSON response decoding
    ///
    /// input_data must be JSON-encodable
    ///     use `#[derive(RustcEncodable)]` for complex input
    ///
    /// You must explicitly specify the output type `T`
    ///     `pipe` will attempt to decode the response into AlgoOutput<T>
    ///
    /// If decoding fails, it will attempt to decode into `ApiError`
    ///     and if that fails, it will error with `DecoderErrorWithContext`
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # use algorithmia::{Algorithmia, AlgorithmiaError};
    /// # use algorithmia::algo::{Algorithm, AlgoOutput, Version};
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let moving_avg = client.algo("timeseries", "SimpleMovingAverage", Version::Minor(0,1));
    /// let input = (vec![0,1,2,3,15,4,5,6,7], 3);
    /// match moving_avg.pipe(&input) {
    ///     Ok(out) => {
    ///         let myVal: AlgoOutput<Vec<f64>> = out;
    ///         println!("{:?}", myVal.result);
    ///     },
    ///     Err(e) => println!("ERROR: {:?}", e),
    /// };
    /// ```
    pub fn pipe<D, E>(&self, input_data: &E) -> AlgoResult<D>
            where D: Decodable,
                  E: Encodable {
        let raw_input = try!(json::encode(input_data));
        let res_json = try!(self.pipe_raw(&raw_input, Mime(TopLevel::Application, SubLevel::Json, vec![])));

        Algorithmia::decode_to_result::<AlgoOutput<D>>(res_json)
    }

    /// pipeute an algorithm with with string input and receive the raw JSON response
    ///
    /// `pipe` provides a JSON encoding/decoding wrapper around this method
    ///
    /// TODO: Consider using byte slice input and output instead of strings
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # use algorithmia::Algorithmia;
    /// # use algorithmia::algo::{Algorithm, Version};
    /// let client = Algorithmia::client("111112222233333444445555566");
    /// let minmax  = client.algo("codeb34v3r", "FindMinMax", Version::Minor(0,1));
    ///
    /// let output = match minmax.pipe_raw("[2,3,4]", "application/json".parse().unwrap()) {
    ///    Ok(result) => result,
    ///    Err(why) => panic!("{:?}", why),
    /// };
    pub fn pipe_raw(&self, input_data: &str, content_type: Mime) -> JsonResult {
        let http_client = self.client.http_client();
        let req = http_client.post(self.to_url())
            .header(ContentType(content_type))
            .body(input_data);

        let mut res = try!(req.send());
        let mut res_string = String::new();
        try!(res.read_to_string(&mut res_string));
        Ok(res_string)
    }

}

#[cfg(test)]
mod tests {
    use Algorithmia;
    use algo::version::Version;

    fn mock_client() -> Algorithmia { Algorithmia::client("") }

    #[test]
    fn test_algo_without_version_to_url() {
        let mock_client = mock_client();
        let algorithm = mock_client.algo_from_str("/anowell/Pinky");
        assert_eq!(algorithm.to_url().serialize(), format!("{}/v1/algo/anowell/Pinky", algorithm.client.base_url));
    }

    #[test]
    fn test_algo_without_prefix_to_url() {
        let mock_client = mock_client();
        let algorithm = mock_client.algo_from_str("anowell/Pinky/0.1.0");
        assert_eq!(algorithm.to_url().serialize(), format!("{}/v1/algo/anowell/Pinky/0.1.0", algorithm.client.base_url));
    }

    #[test]
    fn test_algo_with_prefix_to_url() {
        let mock_client = mock_client();
        let algorithm = mock_client.algo_from_str("algo://anowell/Pinky/0.1");
        assert_eq!(algorithm.to_url().serialize(), format!("{}/v1/algo/anowell/Pinky/0.1", algorithm.client.base_url));
    }

    #[test]
    fn test_algo_typesafe_to_url() {
        let mock_client = mock_client();
        let algorithm = mock_client.algo("anowell", "Pinky", Version::Hash("abcdef123456"));
        assert_eq!(algorithm.to_url().serialize(), format!("{}/v1/algo/anowell/Pinky/abcdef123456", algorithm.client.base_url));
    }
}
<|endoftext|>


<commit_before>use cargo::core::resolver::ResolveError;
use cargo::core::{compiler::CompileMode, Workspace};
use cargo::ops::{self, CompileOptions};
use cargo::util::{config::Config, errors::ManifestError};

use crate::support::project;

/// Tests inclusion of a `ManifestError` pointing to a member manifest
/// when that manifest fails to deserialize.
#[test]
fn toml_deserialize_manifest_error() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [project]
            name = "foo"
            version = "0.1.0"
            authors = []

            [dependencies]
            bar = { path = "bar" }

            [workspace]
        "#,
        )
        .file("src/main.rs", "fn main() {}")
        .file(
            "bar/Cargo.toml",
            r#"
            [project]
            name = "bar"
            version = "0.1.0"
            authors = []

            [dependencies]
            foobar == "0.55"
        "#,
        )
        .file("bar/src/main.rs", "fn main() {}")
        .build();

    let root_manifest_path = p.root().join("Cargo.toml");
    let member_manifest_path = p.root().join("bar").join("Cargo.toml");

    let error = Workspace::new(&root_manifest_path, &Config::default().unwrap()).unwrap_err();
    eprintln!("{:?}", error);

    let manifest_err: &ManifestError = error.downcast_ref().expect("Not a ManifestError");
    assert_eq!(manifest_err.manifest_path(), &root_manifest_path);

    let causes: Vec<_> = manifest_err.manifest_causes().collect();
    assert_eq!(causes.len(), 1, "{:?}", causes);
    assert_eq!(causes[0].manifest_path(), &member_manifest_path);
}

/// Tests inclusion of a `ManifestError` pointing to a member manifest
/// when that manifest has an invalid dependency path.
#[test]
fn member_manifest_path_io_error() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [project]
            name = "foo"
            version = "0.1.0"
            authors = []

            [dependencies]
            bar = { path = "bar" }

            [workspace]
        "#,
        )
        .file("src/main.rs", "fn main() {}")
        .file(
            "bar/Cargo.toml",
            r#"
            [project]
            name = "bar"
            version = "0.1.0"
            authors = []

            [dependencies]
            foobar = { path = "nosuch" }
        "#,
        )
        .file("bar/src/main.rs", "fn main() {}")
        .build();

    let root_manifest_path = p.root().join("Cargo.toml");
    let member_manifest_path = p.root().join("bar").join("Cargo.toml");
    let missing_manifest_path = p.root().join("bar").join("nosuch").join("Cargo.toml");

    let error = Workspace::new(&root_manifest_path, &Config::default().unwrap()).unwrap_err();
    eprintln!("{:?}", error);

    let manifest_err: &ManifestError = error.downcast_ref().expect("Not a ManifestError");
    assert_eq!(manifest_err.manifest_path(), &root_manifest_path);

    let causes: Vec<_> = manifest_err.manifest_causes().collect();
    assert_eq!(causes.len(), 2, "{:?}", causes);
    assert_eq!(causes[0].manifest_path(), &member_manifest_path);
    assert_eq!(causes[1].manifest_path(), &missing_manifest_path);
}

/// Tests dependency version errors provide which package failed via a `ResolveError`.
#[test]
fn member_manifest_version_error() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [project]
            name = "foo"
            version = "0.1.0"
            authors = []

            [dependencies]
            bar = { path = "bar" }

            [workspace]
        "#,
        )
        .file("src/main.rs", "fn main() {}")
        .file(
            "bar/Cargo.toml",
            r#"
            [project]
            name = "bar"
            version = "0.1.0"
            authors = []

            [dependencies]
            i-dont-exist = "0.55"
        "#,
        )
        .file("bar/src/main.rs", "fn main() {}")
        .build();

    let config = Config::default().unwrap();
    let ws = Workspace::new(&p.root().join("Cargo.toml"), &config).unwrap();
    let compile_options = CompileOptions::new(&config, CompileMode::Build).unwrap();
    let member_bar = ws.members().find(|m| &*m.name() == "bar").unwrap();

    let error = ops::compile(&ws, &compile_options).map(|_| ()).unwrap_err();
    eprintln!("{:?}", error);

    let resolve_err: &ResolveError = error.downcast_ref().expect("Not a ResolveError");
    let package_path = resolve_err.package_path();
    assert_eq!(package_path.len(), 1, "package_path: {:?}", package_path);
    assert_eq!(package_path[0], member_bar.package_id());
}
<commit_msg>Auto merge of #6799 - ehuss:fix-member_manifest_version_error-network, r=alexcrichton<commit_after>use cargo::core::resolver::ResolveError;
use cargo::core::{compiler::CompileMode, Shell, Workspace};
use cargo::ops::{self, CompileOptions};
use cargo::util::{config::Config, errors::ManifestError};

use crate::support::install::cargo_home;
use crate::support::project;
use crate::support::registry;

/// Tests inclusion of a `ManifestError` pointing to a member manifest
/// when that manifest fails to deserialize.
#[test]
fn toml_deserialize_manifest_error() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [project]
            name = "foo"
            version = "0.1.0"
            authors = []

            [dependencies]
            bar = { path = "bar" }

            [workspace]
        "#,
        )
        .file("src/main.rs", "fn main() {}")
        .file(
            "bar/Cargo.toml",
            r#"
            [project]
            name = "bar"
            version = "0.1.0"
            authors = []

            [dependencies]
            foobar == "0.55"
        "#,
        )
        .file("bar/src/main.rs", "fn main() {}")
        .build();

    let root_manifest_path = p.root().join("Cargo.toml");
    let member_manifest_path = p.root().join("bar").join("Cargo.toml");

    let error = Workspace::new(&root_manifest_path, &Config::default().unwrap()).unwrap_err();
    eprintln!("{:?}", error);

    let manifest_err: &ManifestError = error.downcast_ref().expect("Not a ManifestError");
    assert_eq!(manifest_err.manifest_path(), &root_manifest_path);

    let causes: Vec<_> = manifest_err.manifest_causes().collect();
    assert_eq!(causes.len(), 1, "{:?}", causes);
    assert_eq!(causes[0].manifest_path(), &member_manifest_path);
}

/// Tests inclusion of a `ManifestError` pointing to a member manifest
/// when that manifest has an invalid dependency path.
#[test]
fn member_manifest_path_io_error() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [project]
            name = "foo"
            version = "0.1.0"
            authors = []

            [dependencies]
            bar = { path = "bar" }

            [workspace]
        "#,
        )
        .file("src/main.rs", "fn main() {}")
        .file(
            "bar/Cargo.toml",
            r#"
            [project]
            name = "bar"
            version = "0.1.0"
            authors = []

            [dependencies]
            foobar = { path = "nosuch" }
        "#,
        )
        .file("bar/src/main.rs", "fn main() {}")
        .build();

    let root_manifest_path = p.root().join("Cargo.toml");
    let member_manifest_path = p.root().join("bar").join("Cargo.toml");
    let missing_manifest_path = p.root().join("bar").join("nosuch").join("Cargo.toml");

    let error = Workspace::new(&root_manifest_path, &Config::default().unwrap()).unwrap_err();
    eprintln!("{:?}", error);

    let manifest_err: &ManifestError = error.downcast_ref().expect("Not a ManifestError");
    assert_eq!(manifest_err.manifest_path(), &root_manifest_path);

    let causes: Vec<_> = manifest_err.manifest_causes().collect();
    assert_eq!(causes.len(), 2, "{:?}", causes);
    assert_eq!(causes[0].manifest_path(), &member_manifest_path);
    assert_eq!(causes[1].manifest_path(), &missing_manifest_path);
}

/// Tests dependency version errors provide which package failed via a `ResolveError`.
#[test]
fn member_manifest_version_error() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [project]
            name = "foo"
            version = "0.1.0"
            authors = []

            [dependencies]
            bar = { path = "bar" }

            [workspace]
        "#,
        )
        .file("src/main.rs", "fn main() {}")
        .file(
            "bar/Cargo.toml",
            r#"
            [project]
            name = "bar"
            version = "0.1.0"
            authors = []

            [dependencies]
            i-dont-exist = "0.55"
        "#,
        )
        .file("bar/src/main.rs", "fn main() {}")
        .build();

    // Prevent this test from accessing the network by setting up .cargo/config.
    registry::init();
    let config = Config::new(Shell::new(), cargo_home(), cargo_home());
    let ws = Workspace::new(&p.root().join("Cargo.toml"), &config).unwrap();
    let compile_options = CompileOptions::new(&config, CompileMode::Build).unwrap();
    let member_bar = ws.members().find(|m| &*m.name() == "bar").unwrap();

    let error = ops::compile(&ws, &compile_options).map(|_| ()).unwrap_err();
    eprintln!("{:?}", error);

    let resolve_err: &ResolveError = error.downcast_ref().expect("Not a ResolveError");
    let package_path = resolve_err.package_path();
    assert_eq!(package_path.len(), 1, "package_path: {:?}", package_path);
    assert_eq!(package_path[0], member_bar.package_id());
}
<|endoftext|>


<commit_before>use super::MUT_RANGE_BOUND;
use crate::utils::{higher, path_to_local, span_lint};
use if_chain::if_chain;
use rustc_hir::{BindingAnnotation, Expr, HirId, Node, PatKind};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::source_map::Span;
use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};

pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) {
    if let Some(higher::Range {
        start: Some(start),
        end: Some(end),
        ..
    }) = higher::range(arg)
    {
        let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)];
        if mut_ids[0].is_some() || mut_ids[1].is_some() {
            let (span_low, span_high) = check_for_mutation(cx, body, &mut_ids);
            mut_warn_with_span(cx, span_low);
            mut_warn_with_span(cx, span_high);
        }
    }
}

fn mut_warn_with_span(cx: &LateContext<'_>, span: Option<Span>) {
    if let Some(sp) = span {
        span_lint(
            cx,
            MUT_RANGE_BOUND,
            sp,
            "attempt to mutate range bound within loop; note that the range of the loop is unchanged",
        );
    }
}

fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option<HirId> {
    if_chain! {
        if let Some(hir_id) = path_to_local(bound);
        if let Node::Binding(pat) = cx.tcx.hir().get(hir_id);
        if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind;
        then {
            return Some(hir_id);
        }
    }
    None
}

fn check_for_mutation<'tcx>(
    cx: &LateContext<'tcx>,
    body: &Expr<'_>,
    bound_ids: &[Option<HirId>],
) -> (Option<Span>, Option<Span>) {
    let mut delegate = MutatePairDelegate {
        cx,
        hir_id_low: bound_ids[0],
        hir_id_high: bound_ids[1],
        span_low: None,
        span_high: None,
    };
    cx.tcx.infer_ctxt().enter(|infcx| {
        ExprUseVisitor::new(
            &mut delegate,
            &infcx,
            body.hir_id.owner,
            cx.param_env,
            cx.typeck_results(),
        )
        .walk_expr(body);
    });
    delegate.mutation_span()
}

struct MutatePairDelegate<'a, 'tcx> {
    cx: &'a LateContext<'tcx>,
    hir_id_low: Option<HirId>,
    hir_id_high: Option<HirId>,
    span_low: Option<Span>,
    span_high: Option<Span>,
}

impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
    fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId, _: ConsumeMode) {}

    fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) {
        if let ty::BorrowKind::MutBorrow = bk {
            if let PlaceBase::Local(id) = cmt.place.base {
                if Some(id) == self.hir_id_low {
                    self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id))
                }
                if Some(id) == self.hir_id_high {
                    self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id))
                }
            }
        }
    }

    fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
        if let PlaceBase::Local(id) = cmt.place.base {
            if Some(id) == self.hir_id_low {
                self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id))
            }
            if Some(id) == self.hir_id_high {
                self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id))
            }
        }
    }
}

impl MutatePairDelegate<'_, '_> {
    fn mutation_span(&self) -> (Option<Span>, Option<Span>) {
        (self.span_low, self.span_high)
    }
}
<commit_msg>Fix error after rebase<commit_after>use super::MUT_RANGE_BOUND;
use crate::utils::{higher, path_to_local, span_lint};
use if_chain::if_chain;
use rustc_hir::{BindingAnnotation, Expr, HirId, Node, PatKind};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::LateContext;
use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty;
use rustc_span::source_map::Span;
use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};

pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) {
    if let Some(higher::Range {
        start: Some(start),
        end: Some(end),
        ..
    }) = higher::range(arg)
    {
        let mut_ids = vec![check_for_mutability(cx, start), check_for_mutability(cx, end)];
        if mut_ids[0].is_some() || mut_ids[1].is_some() {
            let (span_low, span_high) = check_for_mutation(cx, body, &mut_ids);
            mut_warn_with_span(cx, span_low);
            mut_warn_with_span(cx, span_high);
        }
    }
}

fn mut_warn_with_span(cx: &LateContext<'_>, span: Option<Span>) {
    if let Some(sp) = span {
        span_lint(
            cx,
            MUT_RANGE_BOUND,
            sp,
            "attempt to mutate range bound within loop; note that the range of the loop is unchanged",
        );
    }
}

fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option<HirId> {
    if_chain! {
        if let Some(hir_id) = path_to_local(bound);
        if let Node::Binding(pat) = cx.tcx.hir().get(hir_id);
        if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind;
        then {
            return Some(hir_id);
        }
    }
    None
}

fn check_for_mutation<'tcx>(
    cx: &LateContext<'tcx>,
    body: &Expr<'_>,
    bound_ids: &[Option<HirId>],
) -> (Option<Span>, Option<Span>) {
    let mut delegate = MutatePairDelegate {
        cx,
        hir_id_low: bound_ids[0],
        hir_id_high: bound_ids[1],
        span_low: None,
        span_high: None,
    };
    cx.tcx.infer_ctxt().enter(|infcx| {
        ExprUseVisitor::new(
            &mut delegate,
            &infcx,
            body.hir_id.owner,
            cx.param_env,
            cx.typeck_results(),
        )
        .walk_expr(body);
    });
    delegate.mutation_span()
}

struct MutatePairDelegate<'a, 'tcx> {
    cx: &'a LateContext<'tcx>,
    hir_id_low: Option<HirId>,
    hir_id_high: Option<HirId>,
    span_low: Option<Span>,
    span_high: Option<Span>,
}

impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
    fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId, _: ConsumeMode) {}

    fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) {
        if let ty::BorrowKind::MutBorrow = bk {
            if let PlaceBase::Local(id) = cmt.place.base {
                if Some(id) == self.hir_id_low {
                    self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id))
                }
                if Some(id) == self.hir_id_high {
                    self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id))
                }
            }
        }
    }

    fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
        if let PlaceBase::Local(id) = cmt.place.base {
            if Some(id) == self.hir_id_low {
                self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id))
            }
            if Some(id) == self.hir_id_high {
                self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id))
            }
        }
    }

    fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _:HirId) { }
}

impl MutatePairDelegate<'_, '_> {
    fn mutation_span(&self) -> (Option<Span>, Option<Span>) {
        (self.span_low, self.span_high)
    }
}
<|endoftext|>