<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::{stdin, File};
use extra::getopts;
use std::run::{Process, ProcessOptions};
use std::io::signal::{Listener, Interrupt};

struct Shell {
    cmd_prompt: ~str,
    cwd: Path
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            cwd:        os::getcwd()
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());
        let mut history: ~[~str] = ~[];

        loop {
            print!("[{}] {}", self.cwd.filename_display() ,self.cmd_prompt);
            io::stdio::flush();

            // Catches interrupt signal to prevent closing gash,
            // placing the listener outside of the loop broke the external command functionality
            let mut listener = Listener::new();
            listener.register(Interrupt);

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""      =>  { continue; }
                "history"   =>  { for i in range(0, history.len()) {
                                     println! ("{}: {}", i+1, history[i]);
                                    }
                                }
                "exit"  =>  { return; }
                "help"      =>  { println!("Why you askin' me?");}
                "cd"        =>  { self.run_cd(cmd_line)}
                _       =>  { self.run_cmdline(cmd_line); }
            }

            history.push(cmd_line.to_owned());
        }
    }

    fn run_cd(&mut self, cmd_line: &str){
        let argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 1 {
            let path_str: ~str = argv[1];
            let path = Path::new(path_str);
            if os::change_dir(&path) {
                self.cwd.push(path);
            }
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
        let program: ~str = argv.remove(0);
                self.run_cmd(program, argv);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {
        if self.cmd_exists(program) {
            if argv.contains(&~"&") {
                let background = true;
                let argv_bkgd = argv.slice(0, argv.len()-1);
                if argv_bkgd.contains(&~">"){
                    for i in range(0, argv_bkgd.len()){
                        if argv_bkgd[i] == ~">" {
                            self.redirect_right(program, argv_bkgd.slice(0, i), argv_bkgd[i+1], background);
                            break;
                        }
                    }
                }
                else if argv_bkgd.contains(&~"<"){
                    for i in range(0, argv_bkgd.len()){
                        if argv_bkgd[i] == ~"<" {
                            self.redirect_left(program, argv_bkgd.slice(0, i), argv_bkgd[i+1], background);
                            break;
                        }
                    }
                }
                else {
                    let process = Process::new(program, argv_bkgd, ProcessOptions{
                        env: None,
                        dir: None,
                        in_fd: Some(0),
                        out_fd: Some(1),
                        err_fd: Some(2)
                    });
                    spawn(proc () {
                        match process {
                            Some(mut process) => {
                                process.finish();
                            },
                            None       => { }
                        }
                    });
                }

            } else {
                let background = false;
                if argv.contains(&~">"){
                    for i in range(0, argv.len()){
                        if argv[i] == ~">" {
                            self.redirect_right(program, argv.slice(0, i), argv[i+1], background);
                            break;
                        }
                    }
                }
                else if argv.contains(&~"<"){
                    for i in range(0, argv.len()){
                        if argv[i] == ~"<" {
                            self.redirect_left(program, argv.slice(0, i), argv[i+1], background);
                            break;
                        }
                    }
                }
                else if argv.contains(&~"|"){
                    let mut args = argv.to_owned();
                    args.insert(0, program.to_owned());
                    self.check_for_pipes(args);
                }
                else {
                    // No pipe or redirect
                    run::process_status(program, argv);
                }

            }

        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }

    fn check_for_pipes(&mut self, cmd_argv: &[~str]){
        for i in range(0, cmd_argv.len()){
            if cmd_argv[i] == ~"|" {
                self.pipe(cmd_argv[0], cmd_argv.slice(1, i), cmd_argv[i+1], cmd_argv.slice(i+2, cmd_argv.len()));
            }
        }
    }

    // Functional, but not correctly
    fn redirect_right(&mut self, program: &str, argv: &[~str], write_to_file: &str, background: bool){

        if background {
            let path = &Path::new(write_to_file.clone());
            let mut output_file = File::create(path).unwrap();
            println!("Created output file {}", write_to_file);
            let process = Process::new(program, argv, ProcessOptions::new());

            let (port, chan): (Port<~str>, Chan<~str>) = Chan::new();
            spawn(proc() {
                match process {
                    Some(mut p)     => {
                        {
                            let process = &mut p;
                            let reader = process.output();
                            let output = reader.read_to_str();  //~str

                            // Write to output file
                            chan.send(output);
                        }
                        p.close_input();
                        p.close_outputs();
                        p.finish();
                    },
                    None            => {println!("Redirect error!");}
                }
            });
            let output = port.recv();
            output_file.write_str(output);
        } else {
            let path = &Path::new(write_to_file.clone());
            let mut output_file = File::create(path).unwrap();
            println!("Created output file {}", write_to_file);

            // Works now, but requires interrupt signal to
            // be sent twice to return to gash
            match Process::new(program, argv, ProcessOptions::new()) {
                Some(mut p) => {
                    {
                        let process = &mut p;
                        let rdr = process.output();
                        let out = rdr.read_to_str();

                        // Write to output file
                        output_file.write_str(out);
                    }
                    p.close_input();
                    p.close_outputs();
                    p.finish();
                },
                None => {println!("Redirect error!");}
            }
        }
    }

    fn redirect_left(&mut self, program: &str, argv: &[~str], read_from_file: &str, background: bool){
        if background {

        }
        else {
            let path = &Path::new(read_from_file.clone());

            if !path.is_file() {
                println!("There doesn't seem to be any file called {}", read_from_file);
            }
            else {
                let mut input_file = File::open(path);
                let input = input_file.read_to_end();
                println!("Starting process");
                match Process::new(program, argv, ProcessOptions{
                    env: None,
                    dir: None,
                    in_fd: None,
                    out_fd: Some(1),
                    err_fd: Some(2)
                }) {
                    Some(mut p) => {
                        {
                            let process = &mut p;
                            let wtr = process.input();

                            // Read input file
                            wtr.write(input);
                        }
                        p.close_input();
                        p.close_outputs();
                        p.finish();
                    },
                    None => {println!("Redirect error!");}
                }
            }
        }

    }

    fn pipe(&mut self, prog1: &str, prog1_args: &[~str], prog2: &str, prog2_args: &[~str]){

        let process1 = Process::new(prog1, prog1_args, ProcessOptions{
            env: None,
            dir: None,
            in_fd: Some(0),
            out_fd: None,
            err_fd: Some(2)
        });
        let (port1, chan1): (Port<~str>, Chan<~str>) = Chan::new();
        spawn(proc() {
            match process1 {
                Some(mut p1)    => {
                    {
                        let process1 = &mut p1;
                        let output = process1.output().read_to_str();
                        chan1.send(output);
                    }
                    p1.close_input();
                    p1.close_outputs();
                    p1.finish();
                },
                None            => { println!("Pipe Error!");}
            }
        });

        let process2 = Process::new(prog2, prog2_args, ProcessOptions{
            env: None,
            dir: None,
            in_fd: None,
            out_fd: Some(1),
            err_fd: Some(2)
        });

        let (port2, chan2): (Port<~str>, Chan<~str>) = Chan::new();
        spawn(proc() {
            match process2 {
                Some(mut p2)    => {
                    {
                        let process2 = &mut p2;
                        let writer = process2.input();
                        let input = port1.recv();
                        writer.write_str(input);
                    }
                    p2.close_input();
                    p2.close_outputs();
                    p2.finish();
                },
                None            => { println!("Pipe Error!");}
            }
        });
    }

}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<commit_msg>Update gash.rs<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::{stdin, File};
use extra::getopts;
use std::run::{Process, ProcessOptions};
use std::io::signal::{Listener, Interrupt};

struct Shell {
    cmd_prompt: ~str,
    cwd: Path
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            cwd:        os::getcwd()
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());
        let mut history: ~[~str] = ~[];

        loop {
            print!("[{}] {}", self.cwd.filename_display() ,self.cmd_prompt);
            io::stdio::flush();

            // Catches interrupt signal to prevent closing gash,
            // placing the listener outside of the loop broke the external command functionality
            let mut listener = Listener::new();
            listener.register(Interrupt);

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""      =>  { continue; }
                "history"   =>  { for i in range(0, history.len()) {
                                     println! ("{}: {}", i+1, history[i]);
                                    }
                                }
                "exit"  =>  { return; }
                "help"      =>  { println!("Why you askin' me?");}
                "cd"        =>  { self.run_cd(cmd_line)}
                _       =>  { self.run_cmdline(cmd_line); }
            }

            history.push(cmd_line.to_owned());
        }
    }

    fn run_cd(&mut self, cmd_line: &str){
        let argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 1 {
            let path_str: ~str = argv[1];
            let path = Path::new(path_str);
            if os::change_dir(&path) {
                self.cwd.push(path);
            }
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

        if argv.len() > 0 {
        let program: ~str = argv.remove(0);
                self.run_cmd(program, argv);
        }
    }

    fn run_cmd(&mut self, program: &str, argv: &[~str]) {
        if self.cmd_exists(program) {
            if argv.contains(&~"&") {
                let background = true;
                let argv_bkgd = argv.slice(0, argv.len()-1);
                if argv_bkgd.contains(&~">"){
                    for i in range(0, argv_bkgd.len()){
                        if argv_bkgd[i] == ~">" {
                            self.redirect_right(program, argv_bkgd.slice(0, i), argv_bkgd[i+1], background);
                            break;
                        }
                    }
                }
                else if argv_bkgd.contains(&~"<"){
                    for i in range(0, argv_bkgd.len()){
                        if argv_bkgd[i] == ~"<" {
                            self.redirect_left(program, argv_bkgd.slice(0, i), argv_bkgd[i+1], background);
                            break;
                        }
                    }
                }
                else if argv_bkgd.contains(&~"|"){
                    let mut args = argv.to_owned();
                    args.insert(0, program.to_owned());
                    self.check_for_pipes(args);
                }
                else {
                    let process = Process::new(program, argv_bkgd, ProcessOptions{
                        env: None,
                        dir: None,
                        in_fd: Some(0),
                        out_fd: Some(1),
                        err_fd: Some(2)
                    });
                    spawn(proc () {
                        match process {
                            Some(mut process) => {
                                process.finish();
                            },
                            None       => { }
                        }
                    });
                }

            } else {

                let background = false;
                if argv.contains(&~">"){
                    for i in range(0, argv.len()){
                        if argv[i] == ~">" {
                            let mut file = argv[i+1].to_owned();
                            let last_char = file.pop_char();
                            if last_char == ';' {
                                self.redirect_right(program, argv.slice(0, i), file, background);
                                let program = argv[i+2].to_owned();
                                let args = argv.slice(i+3, argv.len());
                                self.run_cmd(program, args);
                                break;
                            }
                            argv[i+1].to_owned().push_char(last_char);
                            self.redirect_right(program, argv.slice(0, i), argv[i+1], background);
                            break;
                        }
                    }
                }
                else if argv.contains(&~"<"){
                    for i in range(0, argv.len()){
                        if argv[i] == ~"<" {
                            self.redirect_left(program, argv.slice(0, i), argv[i+1], background);
                            break;
                        }
                    }
                }
                else if argv.contains(&~"|"){
                    let mut args = argv.to_owned();
                    args.insert(0, program.to_owned());
                    self.check_for_pipes(args);
                }
                else {
                    run::process_status(program, argv);
                }

            }

        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn cmd_exists(&mut self, cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }

    fn check_for_pipes(&mut self, cmd_argv: &[~str]){
        for i in range(0, cmd_argv.len()){
            if cmd_argv[i] == ~"|" {
                self.pipe(cmd_argv[0], cmd_argv.slice(1, i), cmd_argv[i+1], cmd_argv.slice(i+2, cmd_argv.len()));
            }
        }
    }

    // fn check_for_pipes(&mut self, cmd_argv: &[~str]){

    //     // let mut channels: ~[std::os::Pipe] = ~[];
    //     // for _ in range(0, progs.len()) {
    //     //   channels.push(std::os::pipe());
    //     // }
    //     // let mut prog: [&[~str]];
    //     // let mut last = 0;
    //     // for i in range(0, cmd_argv.len()){
    //     //     if cmd_argv[i] == ~"|" {
    //     //         prog.pus(cmd_argv.slice(last, i));
    //     //         last = i+1;
    //     //         //self.pipe(cmd_argv[0], cmd_argv.slice(1, i), cmd_argv[i+1], cmd_argv.slice(i+2, cmd_argv.len()));
    //     //     }
    //     // }

    //     // let mut out;
    //     // let mut into;
    //     // for i in range(0, prog.len()) {
    //     //     if i == 0 {
    //     //         out =
    //     //     }

    //     //     if i == prog.len()-1 {
    //     //         program = prog[i].remove(0);
    //     //         args = prog[i];
    //     //         let fp = Process::new(program, args, ProcessOptions{
    //     //             env: None,
    //     //             dir: None,
    //     //             in_fd: Some(prog.len()-1),
    //     //             out_fd: Some(prog.len()),
    //     //             err_fd: None
    //     //         });
    //     //         fp.unwrap().finish();
    //     //     }
    //     //     else {
    //     //         spwan(proc() {
    //     //             program = prog[i].remove(0);
    //     //             args = prog[i];
    //     //             let fp = Process::new(program, args, ProcessOptions{
    //     //                 env: None,
    //     //                 dir: None,
    //     //                 in_fd: Some(0),
    //     //                 out_fd: Some(1),
    //     //                 err_fd: Some(2)
    //     //             });
    //     //             fp.unwrap().finish();
    //     //         });
    //     //     }
    //     // }

    // }

    // Functional, but not correctly
    fn redirect_right(&mut self, program: &str, argv: &[~str], write_to_file: &str, background: bool){

        if background {
            let path = &Path::new(write_to_file.clone());
            let mut output_file = File::create(path).unwrap();
            let process = Process::new(program, argv, ProcessOptions::new());

            let (port, chan): (Port<~str>, Chan<~str>) = Chan::new();
            spawn(proc() {
                match process {
                    Some(mut p)     => {
                        {
                            let process = &mut p;
                            let reader = process.output();
                            let output = reader.read_to_str();  //~str

                            // Write to output file
                            chan.send(output);
                        }
                        p.close_input();
                        p.close_outputs();
                        p.finish();
                    },
                    None            => {println!("Redirect error!");}
                }
            });
            let output = port.recv();
            output_file.write_str(output);
        } else {
            let path = &Path::new(write_to_file.clone());
            let mut output_file = File::create(path).unwrap();

            // Works now, but requires interrupt signal to
            // be sent twice to return to gash
            match Process::new(program, argv, ProcessOptions::new()) {
                Some(mut p) => {
                    {
                        let process = &mut p;
                        let rdr = process.output();
                        let out = rdr.read_to_str();

                        // Write to output file
                        output_file.write_str(out);
                    }
                    p.close_input();
                    p.close_outputs();
                    p.finish();
                },
                None => {println!("Redirect error!");}
            }
        }
    }

    fn redirect_left(&mut self, program: &str, argv: &[~str], read_from_file: &str, background: bool){
        if background {

        }
        else {
            let path = &Path::new(read_from_file.clone());
            if !path.is_file() {
                println!("There doesn't seem to be any file called {}", read_from_file);
            }
            else {
                let mut input_file = File::open(path);
                let input = input_file.read_to_end();
                match Process::new(program, argv, ProcessOptions{
                    env: None,
                    dir: None,
                    in_fd: None,
                    out_fd: Some(1),
                    err_fd: Some(2)
                }) {
                    Some(mut p) => {
                        {
                            let process = &mut p;
                            let wtr = process.input();

                            // Read input file
                            wtr.write(input);
                        }
                        p.close_input();
                        p.close_outputs();
                        p.finish();
                    },
                    None => {println!("Redirect error!");}
                }
            }
        }

    }

    fn pipe(&mut self, prog1: &str, prog1_args: &[~str], prog2: &str, prog2_args: &[~str]){
        //let mut output: ~str = ~"";

        println!("Prog1: {}", prog1 );
        for i in range(0, prog1_args.len()){
            print!("\t{}", prog1_args[i]);
        }
        println!("\n");

        println!("Prog2: {}", prog2 );
        for i in range(0, prog2_args.len()){
            print!("\t{}", prog2_args[i]);
        }
        println!("\n");

     let (port, chan): (Port<~str>, Chan<~str>) = Chan::new();

    //spawn(proc() {
        match Process::new(prog2, prog2_args, ProcessOptions{
            env: None,
            dir: None,
            in_fd: Some(0),
            out_fd: None,
            err_fd: Some(2)
        }){
            Some(mut p2)    => {
        let process = Process::new(prog1, prog1_args, ProcessOptions{
                        env: None,
                    dir: None,
                    in_fd: None,
                        out_fd: Some(1),
                        err_fd: Some(2)
                    });

        spawn(proc() {
                match process{
                    Some(mut p1)    => {
                        {
                            let process1 = &mut p1;
                            let output = process1.output().read_to_str();
                            //let process = &mut p;
                            //let reader = process.output();
                            //let output = reader.read_to_str();  //~str

                            // Write to output file
                            chan.send(output);
                        }
                        p1.close_input();
                        p1.close_outputs();
                        p1.finish();
                    },
                    None            => { ; }  //println!("Something went wrong with {}", prog1);}
                }
        });

                let output = port.recv();

                {
                    let process2 = &mut p2;
                    let writer = process2.input();
                    writer.write_str(output);
                }
                p2.close_input();
                p2.close_outputs();
                p2.finish();
            },
            None            => { println!("Something went wrong with {}", prog2);}
        }
    //});

    }

    // fn pipe(&mut self, prog1: &str, prog1_args: &[~str], prog2: &str, prog2_args: &[~str]){

    //     match Process::new(prog2, prog2_args, ProcessOptions{
    //         env: None,
    //         dir: None,
    //         in_fd: None,
    //         out_fd: Some(1),
    //         err_fd: Some(2)
    //     }){
    //         Some(mut p2)    => {
    //             let process1 = Process::new(prog1, prog1_args, ProcessOptions{
    //                 env: None,
    //                 dir: None,
    //                 in_fd: Some(0),
    //                 out_fd: None,
    //                 err_fd: Some(2)
    //             });
    //             let (port, chan): (Port<~str>, Chan<~str>) = Chan::new();
    //             spawn(proc() {
    //                 match process1 {
    //                     Some(mut p1)    => {
    //                         {
    //                             let process1 = &mut p1;
    //                             let output = process1.output().read_to_str();
    //                             chan.send(output);
    //                         }
    //                         p1.close_input();
    //                         p1.close_outputs();
    //                         p1.finish();
    //                     },
    //                     None            => { println!("Pipe Error!");}
    //                 }
    //             });

    //             {
    //                 let process2 = &mut p2;
    //                 let writer = process2.input();
    //                 let input = port.recv();
    //                 writer.write_str(input);
    //             }
    //             p2.close_input();
    //             p2.close_outputs();
    //             p2.finish();
    //         },
    //         None            => { println!("Something went wrong with {}", prog2);}
    //     }
    // }

}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<|endoftext|>


<commit_before>#![allow(unused)]

extern crate futures;
extern crate languageserver_types;
extern crate tokio;
extern crate tokio_io;

use std::{
    collections::VecDeque,
    env,
    io::{self, BufRead, BufReader, Write},
    str,
    sync::{
        mpsc::{sync_channel, Receiver, SyncSender, TryRecvError},
        Arc,
    },
};

use jsonrpc_core::{
    id::Id,
    params::Params,
    request::{Call, MethodCall, Notification},
    response::{Output, Response},
    version::Version,
};

use serde::{de::DeserializeOwned, Serialize};
use serde_json::{from_str, from_value, ser::Serializer, to_value, Value};

use self::{
    futures::{future, Future, Poll, Stream},
    tokio::{
        codec::{Decoder, FramedRead},
        prelude::task,
    },
    tokio_io::io::AllowStdIo,
};

use url::Url;

use languageserver_types::*;

use gluon_language_server::rpc::LanguageServerDecoder;

extern crate gluon;
use self::gluon::new_vm;

pub fn test_url(uri: &str) -> Url {
    Url::from_file_path(&env::current_dir().unwrap().join(uri)).unwrap()
}

pub fn write_message<W, V>(writer: &mut W, value: V) -> io::Result<()>
where
    W: ?Sized + Write,
    V: Serialize,
{
    let mut vec = Vec::new();
    value.serialize(&mut Serializer::new(&mut vec)).unwrap();
    write!(
        writer,
        "Content-Length: {}\r\n\r\n{}",
        vec.len(),
        str::from_utf8(&vec).unwrap()
    )
}

pub fn method_call<T>(method: &str, id: u64, value: T) -> Call
where
    T: Serialize,
{
    let value = to_value(value);
    let params = match value {
        Ok(Value::Object(map)) => Params::Map(map),
        Ok(Value::Null) => Params::None,
        _ => panic!("Expected map"),
    };
    Call::MethodCall(MethodCall {
        jsonrpc: Some(Version::V2),
        method: method.into(),
        id: Id::Num(id),
        params: Some(params),
    })
}

pub fn notification<T>(method: &str, value: T) -> Call
where
    T: Serialize,
{
    let value = to_value(value);
    let params = match value {
        Ok(Value::Object(map)) => Params::Map(map),
        Ok(Value::Null) => Params::None,
        _ => panic!("Expected map or null"),
    };
    Call::Notification(Notification {
        jsonrpc: Some(Version::V2),
        method: method.into(),
        params: Some(params),
    })
}

pub fn did_open_uri<W: ?Sized>(stdin: &mut W, uri: Url, text: &str)
where
    W: Write,
{
    let did_open = notification(
        "textDocument/didOpen",
        DidOpenTextDocumentParams {
            text_document: TextDocumentItem {
                uri: uri,
                language_id: "gluon".into(),
                text: text.into(),
                version: 1,
            },
        },
    );

    write_message(stdin, did_open).unwrap();
}

pub fn did_open<W: ?Sized>(stdin: &mut W, uri: &str, text: &str)
where
    W: Write,
{
    did_open_uri(stdin, test_url(uri), text)
}

pub fn did_change<W: ?Sized>(stdin: &mut W, uri: &str, version: u64, range: Range, text: &str)
where
    W: Write,
{
    did_change_event(
        stdin,
        uri,
        version,
        vec![TextDocumentContentChangeEvent {
            range: Some(range),
            range_length: None,
            text: text.to_string(),
        }],
    )
}

pub fn did_change_event<W: ?Sized>(
    stdin: &mut W,
    uri: &str,
    version: u64,
    content_changes: Vec<TextDocumentContentChangeEvent>,
) where
    W: Write,
{
    let hover = notification(
        "textDocument/didChange",
        DidChangeTextDocumentParams {
            text_document: VersionedTextDocumentIdentifier {
                uri: test_url(uri),
                version: Some(version),
            },
            content_changes,
        },
    );

    write_message(stdin, hover).unwrap();
}

fn read_until<T>(output: impl BufRead, f: impl FnMut(String) -> Option<T>) -> T {
    FramedRead::new(AllowStdIo::new(output), LanguageServerDecoder::new())
        .filter_map(f)
        .into_future()
        .map_err(|(err, _)| err)
        .wait()
        .expect("Success")
        .0
        .expect("Expected a response")
}

pub fn expect_response<R, T>(output: R) -> T
where
    T: DeserializeOwned,
    R: BufRead,
{
    read_until(output, |json| {
        // Skip all notifications
        if let Ok(Notification { .. }) = from_str(&json) {
            None
        } else if let Ok(Response::Single(Output::Success(response))) = from_str(&json) {
            Some(from_value(response.result).unwrap_or_else(|err| panic!("{}\n{}", err, json)))
        } else {
            panic!("Expected response, got `{}`", json)
        }
    })
}

pub fn hover<W: ?Sized>(stdin: &mut W, id: u64, uri: &str, position: Position)
where
    W: Write,
{
    let hover = method_call(
        "textDocument/hover",
        id,
        TextDocumentPositionParams {
            text_document: TextDocumentIdentifier { uri: test_url(uri) },
            position: position,
        },
    );

    write_message(stdin, hover).unwrap();
}

pub fn expect_notification<R, T>(output: R) -> T
where
    T: DeserializeOwned,
    R: BufRead,
{
    read_until(output, |json| {
        Some(match from_str(&json) {
            Ok(Notification {
                params: Some(params),
                ..
            }) => {
                let json_value = match params {
                    Params::Map(map) => Value::Object(map),
                    Params::Array(array) => Value::Array(array),
                    Params::None => Value::Null,
                };
                return from_value(json_value).unwrap();
            }
            Ok(_) => panic!("Expected notification\n{}", json),
            Err(err) => panic!("Expected notification, got `{}`\n{}", err, json),
        })
    })
}

pub fn run_no_panic_catch<F>(fut: F)
where
    F: Future<Item = (), Error = ()> + Send + ::std::panic::UnwindSafe + 'static,
{
    use std::sync::{Arc, Mutex};

    let error_result = Arc::new(Mutex::new(None));
    {
        let error_result = error_result.clone();
        tokio::run(
            fut.catch_unwind()
                .map_err(move |err| {
                    *error_result.lock().unwrap() = Some(err);
                })
                .and_then(|result| result),
        );
    }

    if let Some(err) = Arc::try_unwrap(error_result).unwrap().into_inner().unwrap() {
        panic!(err)
    }
}

fn start_local() -> (Box<Write>, Box<BufRead>) {
    let (stdin_read, mut stdin_write) = pipe();
    let (stdout_read, stdout_write) = pipe();
    let stdout_read = BufReader::new(SyncReadPipe(stdout_read));

    let thread = new_vm();
    tokio::spawn(
        ::gluon_language_server::Server::start(thread, stdin_read, stdout_write)
            .map_err(|err| panic!("{}", err)),
    );
    (Box::new(stdin_write), Box::new(stdout_read))
}

fn start_remote() -> (Box<Write>, Box<BufRead>) {
    use std::process::{Command, Stdio};

    let mut child = Command::new("target/debug/gluon_language-server")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()
        .unwrap();
    (
        Box::new(child.stdin.expect("stdin")),
        Box::new(BufReader::new(child.stdout.expect("stdout"))),
    )
}

pub fn send_rpc<F>(f: F)
where
    F: FnOnce(&mut Write, &mut BufRead) + Send + ::std::panic::UnwindSafe + 'static,
{
    run_no_panic_catch(future::lazy(move || {
        let (mut stdin_write, mut stdout_read) = if env::var("GLUON_TEST_REMOTE_SERVER").is_ok() {
            start_remote()
        } else {
            start_local()
        };

        {
            f(&mut stdin_write, &mut stdout_read);

            write_message(&mut stdin_write, method_call("shutdown", 1_000_000, ())).unwrap();

            let () = expect_response(&mut stdout_read);

            let exit = Call::Notification(Notification {
                jsonrpc: Some(Version::V2),
                method: "exit".into(),
                params: None,
            });
            write_message(&mut stdin_write, exit).unwrap();
            drop(stdin_write);
        }
        Ok(())
    }))
}

pub struct ReadPipe {
    task: Arc<task::AtomicTask>,
    recv: Receiver<Vec<u8>>,
    buffer: VecDeque<u8>,
}

impl io::Read for ReadPipe {
    fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
        let l = buffer.len().min(self.buffer.len());
        for (to, from) in buffer.iter_mut().zip(self.buffer.drain(..l)) {
            *to = from;
        }
        self.task.register();
        match self.recv.try_recv() {
            Ok(buf) => {
                self.buffer.extend(buf);
                let extra = self.read(&mut buffer[l..]).unwrap_or(0);
                Ok(l + extra)
            }
            Err(TryRecvError::Disconnected) => Ok(0),
            Err(TryRecvError::Empty) => {
                if l == 0 {
                    Err(io::ErrorKind::WouldBlock.into())
                } else {
                    Ok(l)
                }
            }
        }
    }

    fn read_to_end(&mut self, buffer: &mut Vec<u8>) -> io::Result<usize> {
        let len = buffer.len();
        buffer.extend(self.buffer.drain(..));
        while let Ok(buf) = self.recv.recv() {
            buffer.extend(buf);
        }
        Ok(buffer.len() - len)
    }
}

impl tokio::io::AsyncRead for ReadPipe {}

pub struct SyncReadPipe(pub ReadPipe);

impl io::Read for SyncReadPipe {
    fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
        match self.0.read(buffer) {
            Ok(x) => Ok(x),
            Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => match self.0.recv.recv() {
                Ok(buf) => {
                    let l = buffer.len().min(buf.len());
                    buffer[..l].copy_from_slice(&buf[..l]);
                    self.0.buffer.extend(buf[l..].iter().cloned());
                    Ok(l)
                }
                Err(_) => Ok(0),
            },
            Err(err) => Err(err),
        }
    }
}

#[derive(Clone)]
pub struct WritePipe {
    task: Arc<task::AtomicTask>,
    sender: SyncSender<Vec<u8>>,
}

impl<'a> io::Write for &'a WritePipe {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        if data.is_empty() {
            return Ok(0);
        }
        self.sender
            .send(data.to_owned())
            .map_err(|_| io::Error::from(io::ErrorKind::NotConnected))?;
        self.task.notify();
        Ok(data.len())
    }

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

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

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

impl tokio::io::AsyncWrite for WritePipe {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        Ok(().into())
    }
}

pub fn pipe() -> (ReadPipe, WritePipe) {
    let task = Arc::new(task::AtomicTask::new());
    let (sender, receiver) = sync_channel(10);
    (
        ReadPipe {
            task: task.clone(),
            recv: receiver,
            buffer: VecDeque::new(),
        },
        WritePipe { task, sender },
    )
}
<commit_msg>Disable local testing for the moment<commit_after>#![allow(unused)]

extern crate futures;
extern crate languageserver_types;
extern crate tokio;
extern crate tokio_io;

use std::{
    collections::VecDeque,
    env,
    io::{self, BufRead, BufReader, Write},
    str,
    sync::{
        mpsc::{sync_channel, Receiver, SyncSender, TryRecvError},
        Arc,
    },
};

use jsonrpc_core::{
    id::Id,
    params::Params,
    request::{Call, MethodCall, Notification},
    response::{Output, Response},
    version::Version,
};

use serde::{de::DeserializeOwned, Serialize};
use serde_json::{from_str, from_value, ser::Serializer, to_value, Value};

use self::{
    futures::{future, Future, Poll, Stream},
    tokio::{
        codec::{Decoder, FramedRead},
        prelude::task,
    },
    tokio_io::io::AllowStdIo,
};

use url::Url;

use languageserver_types::*;

use gluon_language_server::rpc::LanguageServerDecoder;

extern crate gluon;
use self::gluon::new_vm;

pub fn test_url(uri: &str) -> Url {
    Url::from_file_path(&env::current_dir().unwrap().join(uri)).unwrap()
}

pub fn write_message<W, V>(writer: &mut W, value: V) -> io::Result<()>
where
    W: ?Sized + Write,
    V: Serialize,
{
    let mut vec = Vec::new();
    value.serialize(&mut Serializer::new(&mut vec)).unwrap();
    write!(
        writer,
        "Content-Length: {}\r\n\r\n{}",
        vec.len(),
        str::from_utf8(&vec).unwrap()
    )
}

pub fn method_call<T>(method: &str, id: u64, value: T) -> Call
where
    T: Serialize,
{
    let value = to_value(value);
    let params = match value {
        Ok(Value::Object(map)) => Params::Map(map),
        Ok(Value::Null) => Params::None,
        _ => panic!("Expected map"),
    };
    Call::MethodCall(MethodCall {
        jsonrpc: Some(Version::V2),
        method: method.into(),
        id: Id::Num(id),
        params: Some(params),
    })
}

pub fn notification<T>(method: &str, value: T) -> Call
where
    T: Serialize,
{
    let value = to_value(value);
    let params = match value {
        Ok(Value::Object(map)) => Params::Map(map),
        Ok(Value::Null) => Params::None,
        _ => panic!("Expected map or null"),
    };
    Call::Notification(Notification {
        jsonrpc: Some(Version::V2),
        method: method.into(),
        params: Some(params),
    })
}

pub fn did_open_uri<W: ?Sized>(stdin: &mut W, uri: Url, text: &str)
where
    W: Write,
{
    let did_open = notification(
        "textDocument/didOpen",
        DidOpenTextDocumentParams {
            text_document: TextDocumentItem {
                uri: uri,
                language_id: "gluon".into(),
                text: text.into(),
                version: 1,
            },
        },
    );

    write_message(stdin, did_open).unwrap();
}

pub fn did_open<W: ?Sized>(stdin: &mut W, uri: &str, text: &str)
where
    W: Write,
{
    did_open_uri(stdin, test_url(uri), text)
}

pub fn did_change<W: ?Sized>(stdin: &mut W, uri: &str, version: u64, range: Range, text: &str)
where
    W: Write,
{
    did_change_event(
        stdin,
        uri,
        version,
        vec![TextDocumentContentChangeEvent {
            range: Some(range),
            range_length: None,
            text: text.to_string(),
        }],
    )
}

pub fn did_change_event<W: ?Sized>(
    stdin: &mut W,
    uri: &str,
    version: u64,
    content_changes: Vec<TextDocumentContentChangeEvent>,
) where
    W: Write,
{
    let hover = notification(
        "textDocument/didChange",
        DidChangeTextDocumentParams {
            text_document: VersionedTextDocumentIdentifier {
                uri: test_url(uri),
                version: Some(version),
            },
            content_changes,
        },
    );

    write_message(stdin, hover).unwrap();
}

fn read_until<T>(output: impl BufRead, f: impl FnMut(String) -> Option<T>) -> T {
    FramedRead::new(AllowStdIo::new(output), LanguageServerDecoder::new())
        .filter_map(f)
        .into_future()
        .map_err(|(err, _)| err)
        .wait()
        .expect("Success")
        .0
        .expect("Expected a response")
}

pub fn expect_response<R, T>(output: R) -> T
where
    T: DeserializeOwned,
    R: BufRead,
{
    read_until(output, |json| {
        // Skip all notifications
        if let Ok(Notification { .. }) = from_str(&json) {
            None
        } else if let Ok(Response::Single(Output::Success(response))) = from_str(&json) {
            Some(from_value(response.result).unwrap_or_else(|err| panic!("{}\n{}", err, json)))
        } else {
            panic!("Expected response, got `{}`", json)
        }
    })
}

pub fn hover<W: ?Sized>(stdin: &mut W, id: u64, uri: &str, position: Position)
where
    W: Write,
{
    let hover = method_call(
        "textDocument/hover",
        id,
        TextDocumentPositionParams {
            text_document: TextDocumentIdentifier { uri: test_url(uri) },
            position: position,
        },
    );

    write_message(stdin, hover).unwrap();
}

pub fn expect_notification<R, T>(output: R) -> T
where
    T: DeserializeOwned,
    R: BufRead,
{
    read_until(output, |json| {
        Some(match from_str(&json) {
            Ok(Notification {
                params: Some(params),
                ..
            }) => {
                let json_value = match params {
                    Params::Map(map) => Value::Object(map),
                    Params::Array(array) => Value::Array(array),
                    Params::None => Value::Null,
                };
                return from_value(json_value).unwrap();
            }
            Ok(_) => panic!("Expected notification\n{}", json),
            Err(err) => panic!("Expected notification, got `{}`\n{}", err, json),
        })
    })
}

pub fn run_no_panic_catch<F>(fut: F)
where
    F: Future<Item = (), Error = ()> + Send + ::std::panic::UnwindSafe + 'static,
{
    use std::sync::{Arc, Mutex};

    let error_result = Arc::new(Mutex::new(None));
    {
        let error_result = error_result.clone();
        tokio::run(
            fut.catch_unwind()
                .map_err(move |err| {
                    *error_result.lock().unwrap() = Some(err);
                })
                .and_then(|result| result),
        );
    }

    if let Some(err) = Arc::try_unwrap(error_result).unwrap().into_inner().unwrap() {
        panic!(err)
    }
}

fn start_local() -> (Box<Write>, Box<BufRead>) {
    let (stdin_read, mut stdin_write) = pipe();
    let (stdout_read, stdout_write) = pipe();
    let stdout_read = BufReader::new(SyncReadPipe(stdout_read));

    let thread = new_vm();
    tokio::spawn(
        ::gluon_language_server::Server::start(thread, stdin_read, stdout_write)
            .map_err(|err| panic!("{}", err)),
    );
    (Box::new(stdin_write), Box::new(stdout_read))
}

fn start_remote() -> (Box<Write>, Box<BufRead>) {
    use std::process::{Command, Stdio};

    let mut child = Command::new("target/debug/gluon_language-server")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()
        .unwrap();
    (
        Box::new(child.stdin.expect("stdin")),
        Box::new(BufReader::new(child.stdout.expect("stdout"))),
    )
}

pub fn send_rpc<F>(f: F)
where
    F: FnOnce(&mut Write, &mut BufRead) + Send + ::std::panic::UnwindSafe + 'static,
{
    run_no_panic_catch(future::lazy(move || {
        let (mut stdin_write, mut stdout_read) = if env::var("GLUON_TEST_LOCAL_SERVER").is_ok() {
            // FIXME Local  testing may deadlock atm
            start_local()
        } else {
            start_remote()
        };

        {
            f(&mut stdin_write, &mut stdout_read);

            write_message(&mut stdin_write, method_call("shutdown", 1_000_000, ())).unwrap();

            let () = expect_response(&mut stdout_read);

            let exit = Call::Notification(Notification {
                jsonrpc: Some(Version::V2),
                method: "exit".into(),
                params: None,
            });
            write_message(&mut stdin_write, exit).unwrap();
            drop(stdin_write);
        }
        Ok(())
    }))
}

pub struct ReadPipe {
    task: Arc<task::AtomicTask>,
    recv: Receiver<Vec<u8>>,
    buffer: VecDeque<u8>,
}

impl io::Read for ReadPipe {
    fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
        let l = buffer.len().min(self.buffer.len());
        for (to, from) in buffer.iter_mut().zip(self.buffer.drain(..l)) {
            *to = from;
        }
        self.task.register();
        match self.recv.try_recv() {
            Ok(buf) => {
                self.buffer.extend(buf);
                let extra = self.read(&mut buffer[l..]).unwrap_or(0);
                Ok(l + extra)
            }
            Err(TryRecvError::Disconnected) => Ok(0),
            Err(TryRecvError::Empty) => {
                if l == 0 {
                    Err(io::ErrorKind::WouldBlock.into())
                } else {
                    Ok(l)
                }
            }
        }
    }

    fn read_to_end(&mut self, buffer: &mut Vec<u8>) -> io::Result<usize> {
        let len = buffer.len();
        buffer.extend(self.buffer.drain(..));
        while let Ok(buf) = self.recv.recv() {
            buffer.extend(buf);
        }
        Ok(buffer.len() - len)
    }
}

impl tokio::io::AsyncRead for ReadPipe {}

pub struct SyncReadPipe(pub ReadPipe);

impl io::Read for SyncReadPipe {
    fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
        match self.0.read(buffer) {
            Ok(x) => Ok(x),
            Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => match self.0.recv.recv() {
                Ok(buf) => {
                    let l = buffer.len().min(buf.len());
                    buffer[..l].copy_from_slice(&buf[..l]);
                    self.0.buffer.extend(buf[l..].iter().cloned());
                    Ok(l)
                }
                Err(_) => Ok(0),
            },
            Err(err) => Err(err),
        }
    }
}

#[derive(Clone)]
pub struct WritePipe {
    task: Arc<task::AtomicTask>,
    sender: SyncSender<Vec<u8>>,
}

impl<'a> io::Write for &'a WritePipe {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        if data.is_empty() {
            return Ok(0);
        }
        self.sender
            .send(data.to_owned())
            .map_err(|_| io::Error::from(io::ErrorKind::NotConnected))?;
        self.task.notify();
        Ok(data.len())
    }

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

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

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

impl tokio::io::AsyncWrite for WritePipe {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        Ok(().into())
    }
}

pub fn pipe() -> (ReadPipe, WritePipe) {
    let task = Arc::new(task::AtomicTask::new());
    let (sender, receiver) = sync_channel(10);
    (
        ReadPipe {
            task: task.clone(),
            recv: receiver,
            buffer: VecDeque::new(),
        },
        WritePipe { task, sender },
    )
}
<|endoftext|>


<commit_before>#![doc(html_root_url = "https://docs.rs/tokio-tls/0.3.0-alpha.4")]
#![warn(
    missing_debug_implementations,
    missing_docs,
    rust_2018_idioms,
    unreachable_pub
)]
#![doc(test(no_crate_inject, attr(deny(rust_2018_idioms))))]

//! Async TLS streams
//!
//! This library is an implementation of TLS streams using the most appropriate
//! system library by default for negotiating the connection. That is, on
//! Windows this library uses SChannel, on OSX it uses SecureTransport, and on
//! other platforms it uses OpenSSL.
//!
//! Each TLS stream implements the `Read` and `Write` traits to interact and
//! interoperate with the rest of the futures I/O ecosystem. Client connections
//! initiated from this crate verify hostnames automatically and by default.
//!
//! This crate primarily exports this ability through two newtypes,
//! `TlsConnector` and `TlsAcceptor`. These newtypes augment the
//! functionality provided by the `native-tls` crate, on which this crate is
//! built. Configuration of TLS parameters is still primarily done through the
//! `native-tls` crate.

use native_tls::{Error, HandshakeError, MidHandshakeTlsStream};
use std::fmt;
use std::future::Future;
use std::io::{self, Read, Write};
use std::marker::Unpin;
use std::pin::Pin;
use std::ptr::null_mut;
use std::task::{Context, Poll};
use tokio_io::{AsyncRead, AsyncWrite};

#[derive(Debug)]
struct AllowStd<S> {
    inner: S,
    context: *mut (),
}

/// A wrapper around an underlying raw stream which implements the TLS or SSL
/// protocol.
///
/// A `TlsStream<S>` represents a handshake that has been completed successfully
/// and both the server and the client are ready for receiving and sending
/// data. Bytes read from a `TlsStream` are decrypted from `S` and bytes written
/// to a `TlsStream` are encrypted when passing through to `S`.
#[derive(Debug)]
pub struct TlsStream<S>(native_tls::TlsStream<AllowStd<S>>);

/// A wrapper around a `native_tls::TlsConnector`, providing an async `connect`
/// method.
#[derive(Clone)]
pub struct TlsConnector(native_tls::TlsConnector);

/// A wrapper around a `native_tls::TlsAcceptor`, providing an async `accept`
/// method.
#[derive(Clone)]
pub struct TlsAcceptor(native_tls::TlsAcceptor);

struct MidHandshake<S>(Option<MidHandshakeTlsStream<AllowStd<S>>>);

enum StartedHandshake<S> {
    Done(TlsStream<S>),
    Mid(MidHandshakeTlsStream<AllowStd<S>>),
}

struct StartedHandshakeFuture<F, S>(Option<StartedHandshakeFutureInner<F, S>>);
struct StartedHandshakeFutureInner<F, S> {
    f: F,
    stream: S,
}

struct Guard<'a, S>(&'a mut TlsStream<S>)
where
    AllowStd<S>: Read + Write;

impl<S> Drop for Guard<'_, S>
where
    AllowStd<S>: Read + Write,
{
    fn drop(&mut self) {
        (self.0).0.get_mut().context = null_mut();
    }
}

// *mut () context is neither Send nor Sync
unsafe impl<S: Send> Send for AllowStd<S> {}
unsafe impl<S: Sync> Sync for AllowStd<S> {}

impl<S> AllowStd<S>
where
    S: Unpin,
{
    fn with_context<F, R>(&mut self, f: F) -> R
    where
        F: FnOnce(&mut Context<'_>, Pin<&mut S>) -> R,
    {
        unsafe {
            assert!(!self.context.is_null());
            let waker = &mut *(self.context as *mut _);
            f(waker, Pin::new(&mut self.inner))
        }
    }
}

impl<S> Read for AllowStd<S>
where
    S: AsyncRead + Unpin,
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match self.with_context(|ctx, stream| stream.poll_read(ctx, buf)) {
            Poll::Ready(r) => r,
            Poll::Pending => Err(io::Error::from(io::ErrorKind::WouldBlock)),
        }
    }
}

impl<S> Write for AllowStd<S>
where
    S: AsyncWrite + Unpin,
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match self.with_context(|ctx, stream| stream.poll_write(ctx, buf)) {
            Poll::Ready(r) => r,
            Poll::Pending => Err(io::Error::from(io::ErrorKind::WouldBlock)),
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        match self.with_context(|ctx, stream| stream.poll_flush(ctx)) {
            Poll::Ready(r) => r,
            Poll::Pending => Err(io::Error::from(io::ErrorKind::WouldBlock)),
        }
    }
}

fn cvt<T>(r: io::Result<T>) -> Poll<io::Result<T>> {
    match r {
        Ok(v) => Poll::Ready(Ok(v)),
        Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Poll::Pending,
        Err(e) => Poll::Ready(Err(e)),
    }
}

impl<S> TlsStream<S> {
    fn with_context<F, R>(&mut self, ctx: &mut Context<'_>, f: F) -> R
    where
        F: FnOnce(&mut native_tls::TlsStream<AllowStd<S>>) -> R,
        AllowStd<S>: Read + Write,
    {
        self.0.get_mut().context = ctx as *mut _ as *mut ();
        let g = Guard(self);
        f(&mut (g.0).0)
    }

    /// Returns a shared reference to the inner stream.
    pub fn get_ref(&self) -> &S
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        &self.0.get_ref().inner
    }

    /// Returns a mutable reference to the inner stream.
    pub fn get_mut(&mut self) -> &mut S
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        &mut self.0.get_mut().inner
    }
}

impl<S> AsyncRead for TlsStream<S>
where
    S: AsyncRead + AsyncWrite + Unpin,
{
    unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool {
        // Note that this does not forward to `S` because the buffer is
        // unconditionally filled in by OpenSSL, not the actual object `S`.
        // We're decrypting bytes from `S` into the buffer above!
        false
    }

    fn poll_read(
        mut self: Pin<&mut Self>,
        ctx: &mut Context<'_>,
        buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        self.with_context(ctx, |s| cvt(s.read(buf)))
    }
}

impl<S> AsyncWrite for TlsStream<S>
where
    S: AsyncRead + AsyncWrite + Unpin,
{
    fn poll_write(
        mut self: Pin<&mut Self>,
        ctx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        self.with_context(ctx, |s| cvt(s.write(buf)))
    }

    fn poll_flush(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.with_context(ctx, |s| cvt(s.flush()))
    }

    fn poll_shutdown(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {
        match self.with_context(ctx, |s| s.shutdown()) {
            Ok(()) => Poll::Ready(Ok(())),
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Poll::Pending,
            Err(e) => Poll::Ready(Err(e)),
        }
    }
}

async fn handshake<F, S>(f: F, stream: S) -> Result<TlsStream<S>, Error>
where
    F: FnOnce(
            AllowStd<S>,
        ) -> Result<native_tls::TlsStream<AllowStd<S>>, HandshakeError<AllowStd<S>>>
        + Unpin,
    S: AsyncRead + AsyncWrite + Unpin,
{
    let start = StartedHandshakeFuture(Some(StartedHandshakeFutureInner { f, stream }));

    match start.await {
        Err(e) => Err(e),
        Ok(StartedHandshake::Done(s)) => Ok(s),
        Ok(StartedHandshake::Mid(s)) => MidHandshake(Some(s)).await,
    }
}

impl<F, S> Future for StartedHandshakeFuture<F, S>
where
    F: FnOnce(
            AllowStd<S>,
        ) -> Result<native_tls::TlsStream<AllowStd<S>>, HandshakeError<AllowStd<S>>>
        + Unpin,
    S: Unpin,
    AllowStd<S>: Read + Write,
{
    type Output = Result<StartedHandshake<S>, Error>;

    fn poll(
        mut self: Pin<&mut Self>,
        ctx: &mut Context<'_>,
    ) -> Poll<Result<StartedHandshake<S>, Error>> {
        let inner = self.0.take().expect("future polled after completion");
        let stream = AllowStd {
            inner: inner.stream,
            context: ctx as *mut _ as *mut (),
        };

        match (inner.f)(stream) {
            Ok(mut s) => {
                s.get_mut().context = null_mut();
                Poll::Ready(Ok(StartedHandshake::Done(TlsStream(s))))
            }
            Err(HandshakeError::WouldBlock(mut s)) => {
                s.get_mut().context = null_mut();
                Poll::Ready(Ok(StartedHandshake::Mid(s)))
            }
            Err(HandshakeError::Failure(e)) => Poll::Ready(Err(e)),
        }
    }
}

impl TlsConnector {
    /// Connects the provided stream with this connector, assuming the provided
    /// domain.
    ///
    /// This function will internally call `TlsConnector::connect` to connect
    /// the stream and returns a future representing the resolution of the
    /// connection operation. The returned future will resolve to either
    /// `TlsStream<S>` or `Error` depending if it's successful or not.
    ///
    /// This is typically used for clients who have already established, for
    /// example, a TCP connection to a remote server. That stream is then
    /// provided here to perform the client half of a connection to a
    /// TLS-powered server.
    pub async fn connect<S>(&self, domain: &str, stream: S) -> Result<TlsStream<S>, Error>
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        handshake(|s| self.0.connect(domain, s), stream).await
    }
}

impl fmt::Debug for TlsConnector {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("TlsConnector").finish()
    }
}

impl From<native_tls::TlsConnector> for TlsConnector {
    fn from(inner: native_tls::TlsConnector) -> TlsConnector {
        TlsConnector(inner)
    }
}

impl TlsAcceptor {
    /// Accepts a new client connection with the provided stream.
    ///
    /// This function will internally call `TlsAcceptor::accept` to connect
    /// the stream and returns a future representing the resolution of the
    /// connection operation. The returned future will resolve to either
    /// `TlsStream<S>` or `Error` depending if it's successful or not.
    ///
    /// This is typically used after a new socket has been accepted from a
    /// `TcpListener`. That socket is then passed to this function to perform
    /// the server half of accepting a client connection.
    pub async fn accept<S>(&self, stream: S) -> Result<TlsStream<S>, Error>
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        handshake(|s| self.0.accept(s), stream).await
    }
}

impl fmt::Debug for TlsAcceptor {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("TlsAcceptor").finish()
    }
}

impl From<native_tls::TlsAcceptor> for TlsAcceptor {
    fn from(inner: native_tls::TlsAcceptor) -> TlsAcceptor {
        TlsAcceptor(inner)
    }
}

impl<S: AsyncRead + AsyncWrite + Unpin> Future for MidHandshake<S> {
    type Output = Result<TlsStream<S>, Error>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let mut_self = self.get_mut();
        let mut s = mut_self.0.take().expect("future polled after completion");

        s.get_mut().context = cx as *mut _ as *mut ();
        match s.handshake() {
            Ok(stream) => Poll::Ready(Ok(TlsStream(stream))),
            Err(HandshakeError::Failure(e)) => Poll::Ready(Err(e)),
            Err(HandshakeError::WouldBlock(mut s)) => {
                s.get_mut().context = null_mut();
                mut_self.0 = Some(s);
                Poll::Pending
            }
        }
    }
}
<commit_msg>tls: fix new temporary lifetime rustc error [E0597] (#1547)<commit_after>#![doc(html_root_url = "https://docs.rs/tokio-tls/0.3.0-alpha.4")]
#![warn(
    missing_debug_implementations,
    missing_docs,
    rust_2018_idioms,
    unreachable_pub
)]
#![doc(test(no_crate_inject, attr(deny(rust_2018_idioms))))]

//! Async TLS streams
//!
//! This library is an implementation of TLS streams using the most appropriate
//! system library by default for negotiating the connection. That is, on
//! Windows this library uses SChannel, on OSX it uses SecureTransport, and on
//! other platforms it uses OpenSSL.
//!
//! Each TLS stream implements the `Read` and `Write` traits to interact and
//! interoperate with the rest of the futures I/O ecosystem. Client connections
//! initiated from this crate verify hostnames automatically and by default.
//!
//! This crate primarily exports this ability through two newtypes,
//! `TlsConnector` and `TlsAcceptor`. These newtypes augment the
//! functionality provided by the `native-tls` crate, on which this crate is
//! built. Configuration of TLS parameters is still primarily done through the
//! `native-tls` crate.

use native_tls::{Error, HandshakeError, MidHandshakeTlsStream};
use std::fmt;
use std::future::Future;
use std::io::{self, Read, Write};
use std::marker::Unpin;
use std::pin::Pin;
use std::ptr::null_mut;
use std::task::{Context, Poll};
use tokio_io::{AsyncRead, AsyncWrite};

#[derive(Debug)]
struct AllowStd<S> {
    inner: S,
    context: *mut (),
}

/// A wrapper around an underlying raw stream which implements the TLS or SSL
/// protocol.
///
/// A `TlsStream<S>` represents a handshake that has been completed successfully
/// and both the server and the client are ready for receiving and sending
/// data. Bytes read from a `TlsStream` are decrypted from `S` and bytes written
/// to a `TlsStream` are encrypted when passing through to `S`.
#[derive(Debug)]
pub struct TlsStream<S>(native_tls::TlsStream<AllowStd<S>>);

/// A wrapper around a `native_tls::TlsConnector`, providing an async `connect`
/// method.
#[derive(Clone)]
pub struct TlsConnector(native_tls::TlsConnector);

/// A wrapper around a `native_tls::TlsAcceptor`, providing an async `accept`
/// method.
#[derive(Clone)]
pub struct TlsAcceptor(native_tls::TlsAcceptor);

struct MidHandshake<S>(Option<MidHandshakeTlsStream<AllowStd<S>>>);

enum StartedHandshake<S> {
    Done(TlsStream<S>),
    Mid(MidHandshakeTlsStream<AllowStd<S>>),
}

struct StartedHandshakeFuture<F, S>(Option<StartedHandshakeFutureInner<F, S>>);
struct StartedHandshakeFutureInner<F, S> {
    f: F,
    stream: S,
}

struct Guard<'a, S>(&'a mut TlsStream<S>)
where
    AllowStd<S>: Read + Write;

impl<S> Drop for Guard<'_, S>
where
    AllowStd<S>: Read + Write,
{
    fn drop(&mut self) {
        (self.0).0.get_mut().context = null_mut();
    }
}

// *mut () context is neither Send nor Sync
unsafe impl<S: Send> Send for AllowStd<S> {}
unsafe impl<S: Sync> Sync for AllowStd<S> {}

impl<S> AllowStd<S>
where
    S: Unpin,
{
    fn with_context<F, R>(&mut self, f: F) -> R
    where
        F: FnOnce(&mut Context<'_>, Pin<&mut S>) -> R,
    {
        unsafe {
            assert!(!self.context.is_null());
            let waker = &mut *(self.context as *mut _);
            f(waker, Pin::new(&mut self.inner))
        }
    }
}

impl<S> Read for AllowStd<S>
where
    S: AsyncRead + Unpin,
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match self.with_context(|ctx, stream| stream.poll_read(ctx, buf)) {
            Poll::Ready(r) => r,
            Poll::Pending => Err(io::Error::from(io::ErrorKind::WouldBlock)),
        }
    }
}

impl<S> Write for AllowStd<S>
where
    S: AsyncWrite + Unpin,
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match self.with_context(|ctx, stream| stream.poll_write(ctx, buf)) {
            Poll::Ready(r) => r,
            Poll::Pending => Err(io::Error::from(io::ErrorKind::WouldBlock)),
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        match self.with_context(|ctx, stream| stream.poll_flush(ctx)) {
            Poll::Ready(r) => r,
            Poll::Pending => Err(io::Error::from(io::ErrorKind::WouldBlock)),
        }
    }
}

fn cvt<T>(r: io::Result<T>) -> Poll<io::Result<T>> {
    match r {
        Ok(v) => Poll::Ready(Ok(v)),
        Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Poll::Pending,
        Err(e) => Poll::Ready(Err(e)),
    }
}

impl<S> TlsStream<S> {
    fn with_context<F, R>(&mut self, ctx: &mut Context<'_>, f: F) -> R
    where
        F: FnOnce(&mut native_tls::TlsStream<AllowStd<S>>) -> R,
        AllowStd<S>: Read + Write,
    {
        self.0.get_mut().context = ctx as *mut _ as *mut ();
        let g = Guard(self);
        f(&mut (g.0).0)
    }

    /// Returns a shared reference to the inner stream.
    pub fn get_ref(&self) -> &S
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        &self.0.get_ref().inner
    }

    /// Returns a mutable reference to the inner stream.
    pub fn get_mut(&mut self) -> &mut S
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        &mut self.0.get_mut().inner
    }
}

impl<S> AsyncRead for TlsStream<S>
where
    S: AsyncRead + AsyncWrite + Unpin,
{
    unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool {
        // Note that this does not forward to `S` because the buffer is
        // unconditionally filled in by OpenSSL, not the actual object `S`.
        // We're decrypting bytes from `S` into the buffer above!
        false
    }

    fn poll_read(
        mut self: Pin<&mut Self>,
        ctx: &mut Context<'_>,
        buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        self.with_context(ctx, |s| cvt(s.read(buf)))
    }
}

impl<S> AsyncWrite for TlsStream<S>
where
    S: AsyncRead + AsyncWrite + Unpin,
{
    fn poll_write(
        mut self: Pin<&mut Self>,
        ctx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        self.with_context(ctx, |s| cvt(s.write(buf)))
    }

    fn poll_flush(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {
        self.with_context(ctx, |s| cvt(s.flush()))
    }

    fn poll_shutdown(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<io::Result<()>> {
        match self.with_context(ctx, |s| s.shutdown()) {
            Ok(()) => Poll::Ready(Ok(())),
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => Poll::Pending,
            Err(e) => Poll::Ready(Err(e)),
        }
    }
}

async fn handshake<F, S>(f: F, stream: S) -> Result<TlsStream<S>, Error>
where
    F: FnOnce(
            AllowStd<S>,
        ) -> Result<native_tls::TlsStream<AllowStd<S>>, HandshakeError<AllowStd<S>>>
        + Unpin,
    S: AsyncRead + AsyncWrite + Unpin,
{
    let start = StartedHandshakeFuture(Some(StartedHandshakeFutureInner { f, stream }));

    match start.await {
        Err(e) => Err(e),
        Ok(StartedHandshake::Done(s)) => Ok(s),
        Ok(StartedHandshake::Mid(s)) => MidHandshake(Some(s)).await,
    }
}

impl<F, S> Future for StartedHandshakeFuture<F, S>
where
    F: FnOnce(
            AllowStd<S>,
        ) -> Result<native_tls::TlsStream<AllowStd<S>>, HandshakeError<AllowStd<S>>>
        + Unpin,
    S: Unpin,
    AllowStd<S>: Read + Write,
{
    type Output = Result<StartedHandshake<S>, Error>;

    fn poll(
        mut self: Pin<&mut Self>,
        ctx: &mut Context<'_>,
    ) -> Poll<Result<StartedHandshake<S>, Error>> {
        let inner = self.0.take().expect("future polled after completion");
        let stream = AllowStd {
            inner: inner.stream,
            context: ctx as *mut _ as *mut (),
        };

        match (inner.f)(stream) {
            Ok(mut s) => {
                s.get_mut().context = null_mut();
                Poll::Ready(Ok(StartedHandshake::Done(TlsStream(s))))
            }
            Err(HandshakeError::WouldBlock(mut s)) => {
                s.get_mut().context = null_mut();
                Poll::Ready(Ok(StartedHandshake::Mid(s)))
            }
            Err(HandshakeError::Failure(e)) => Poll::Ready(Err(e)),
        }
    }
}

impl TlsConnector {
    /// Connects the provided stream with this connector, assuming the provided
    /// domain.
    ///
    /// This function will internally call `TlsConnector::connect` to connect
    /// the stream and returns a future representing the resolution of the
    /// connection operation. The returned future will resolve to either
    /// `TlsStream<S>` or `Error` depending if it's successful or not.
    ///
    /// This is typically used for clients who have already established, for
    /// example, a TCP connection to a remote server. That stream is then
    /// provided here to perform the client half of a connection to a
    /// TLS-powered server.
    pub async fn connect<S>(&self, domain: &str, stream: S) -> Result<TlsStream<S>, Error>
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        handshake(move |s| self.0.connect(domain, s), stream).await
    }
}

impl fmt::Debug for TlsConnector {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("TlsConnector").finish()
    }
}

impl From<native_tls::TlsConnector> for TlsConnector {
    fn from(inner: native_tls::TlsConnector) -> TlsConnector {
        TlsConnector(inner)
    }
}

impl TlsAcceptor {
    /// Accepts a new client connection with the provided stream.
    ///
    /// This function will internally call `TlsAcceptor::accept` to connect
    /// the stream and returns a future representing the resolution of the
    /// connection operation. The returned future will resolve to either
    /// `TlsStream<S>` or `Error` depending if it's successful or not.
    ///
    /// This is typically used after a new socket has been accepted from a
    /// `TcpListener`. That socket is then passed to this function to perform
    /// the server half of accepting a client connection.
    pub async fn accept<S>(&self, stream: S) -> Result<TlsStream<S>, Error>
    where
        S: AsyncRead + AsyncWrite + Unpin,
    {
        handshake(move |s| self.0.accept(s), stream).await
    }
}

impl fmt::Debug for TlsAcceptor {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("TlsAcceptor").finish()
    }
}

impl From<native_tls::TlsAcceptor> for TlsAcceptor {
    fn from(inner: native_tls::TlsAcceptor) -> TlsAcceptor {
        TlsAcceptor(inner)
    }
}

impl<S: AsyncRead + AsyncWrite + Unpin> Future for MidHandshake<S> {
    type Output = Result<TlsStream<S>, Error>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let mut_self = self.get_mut();
        let mut s = mut_self.0.take().expect("future polled after completion");

        s.get_mut().context = cx as *mut _ as *mut ();
        match s.handshake() {
            Ok(stream) => Poll::Ready(Ok(TlsStream(stream))),
            Err(HandshakeError::Failure(e)) => Poll::Ready(Err(e)),
            Err(HandshakeError::WouldBlock(mut s)) => {
                s.get_mut().context = null_mut();
                mut_self.0 = Some(s);
                Poll::Pending
            }
        }
    }
}
<|endoftext|>


<commit_before>
extern crate rand;
extern crate errno;
use errno::{Errno, errno};

extern crate modbus;
use modbus::{Modbus, ModbusMapping, ModbusResult};
use rand::{thread_rng, Rng};

/* The goal of this program is to check all major functions of
   libmodbus:
   - write_coil
   - read_bits
   - write_coils
   - write_register
   - read_registers
   - write_registers
   - read_registers

   All these functions are called with random values on a address
   range defined by the following defines.
*/

const LOOP: i32             =   1;
const SERVER_ID: i32        =   17;
const ADDRESS_START: i32    =   0;
const ADDRESS_END: i32      =   99;

/*
macro_rules! log_try {
    ($e:expr,$v:ident) => (match $e {
        Ok(val) => val,
        Err(err) => {
            $v += 1;
            return Err(::std::convert::From::from(err))
        },
    });
}
*/
/*
macro_rules! log_try {
    ($e:expr) => (match $e {
        Ok(val) => val,
        Err(err) => return Err(::std::convert::From::from(err)),
    });
}
*/

fn log_res( result: ModbusResult, log_var: &mut u32 ) -> ModbusResult
{
    match result {
        Ok(_) => return result,
        Err(_) => { *log_var = *log_var + 1; return result }
    }
}

pub fn main() {

    let addr = "127.0.0.1:1502".parse().unwrap();
    let mut mb = Modbus::new_tcp(&addr);

    mb.set_debug(true);

    mb.connect();

    let nb = (ADDRESS_END - ADDRESS_START) as usize;
    let mut nb_fail: u32 = 0;

    let mut tab_rp_bits = vec![0u8; nb];

    for nb_loop in 0..LOOP {
        for addr in ADDRESS_START..ADDRESS_END {

            let tab_rq_registers = rand::thread_rng()
                                    .gen_iter::<u16>()
                                    .take(nb).collect::<Vec<u16>>();

            let tab_rw_rq_registers = tab_rq_registers.iter()
                                    .map(|&x| !x).collect::<Vec<u16>>();

            let tab_rq_bits = tab_rw_rq_registers.iter()
                                    .map(|&x| (x % 2) as u8).collect::<Vec<u8>>();

            /* WRITE BIT */
            /*
            match mb.write_bit(addr, tab_rq_bits[0]) {
                Ok(()) => _,
                Err(err) =>
            }
            */
            /*
            if mb.write_bit(addr, tab_rq_bits[0] as i32).is_ok() {
            }
            else {

            }
            */
            //log_try!( mb.write_bit(addr, tab_rq_bits[0] as i32); nb_fail );
            //log_try!( mb.write_bit(addr, tab_rq_bits[0] as i32) );
            //try!( mb.write_bit(addr, tab_rq_bits[0] as i32) );
            //
            if let Err(e) = mb.write_bit(addr, tab_rq_bits[0] as i32) {
                println!("Error happened:");
                println!("{}", e);
            }
            /*
            if log_res( mb.write_bit(addr, tab_rq_bits[0] as i32), &mut nb_fail ).is_ok() {
                log_res( mb.read_bits(addr, &mut tab_rp_bits[0..1]), &mut nb_fail );
            }
            */

            /*
            if log_res( mb.write_bits(addr, &tab_rq_bits[..]), &mut nb_fail ).is_ok() {
                log_res( mb.read_bits(addr, &mut tab_rp_bits[..]), &mut nb_fail );
            }
            */

        }

        println!( "nb_fail is = {}", nb_fail );

    }
}
<commit_msg>random-test-client should be functionally the same to the libmodbus version now<commit_after>
extern crate rand;
extern crate errno;
use errno::{Errno, errno};

extern crate modbus;
use modbus::{Modbus, ModbusMapping, ModbusResult};
use rand::{thread_rng, Rng};

/* The goal of this program is to check all major functions of
   libmodbus:
   - write_coil
   - read_bits
   - write_coils
   - write_register
   - read_registers
   - write_registers
   - read_registers

   All these functions are called with random values on a address
   range defined by the following defines.
*/

const LOOP: i32             =   1;
const SERVER_ID: i32        =   17;
const ADDRESS_START: i32    =   0;
const ADDRESS_END: i32      =   99;

/*
macro_rules! log_try {
    ($e:expr,$v:ident) => (match $e {
        Ok(val) => val,
        Err(err) => {
            $v += 1;
            return Err(::std::convert::From::from(err))
        },
    });
}
*/
/*
macro_rules! log_try {
    ($e:expr) => (match $e {
        Ok(val) => val,
        Err(err) => return Err(::std::convert::From::from(err)),
    });
}
*/

fn log_res( result: ModbusResult, log_var: &mut u32 ) -> ModbusResult
{
    match result {
        Ok(_) => return result,
        Err(_) => { *log_var = *log_var + 1; return result }
    }
}

pub fn main() {

    let addr = "127.0.0.1:1502".parse().unwrap();
    let mut mb = Modbus::new_tcp(&addr);

    mb.set_debug(true);

    mb.connect();

    let nb = (ADDRESS_END - ADDRESS_START) as usize;
    let mut nb_fail: u32 = 0;

    let mut tab_rp_bits = vec![0u8; nb];
    let mut tab_rp_registers = vec![0u16; nb];

    for nb_loop in 0..LOOP {
        for addr in ADDRESS_START..ADDRESS_END {

            let tab_rq_registers = rand::thread_rng()
                                    .gen_iter::<u16>()
                                    .take(nb).collect::<Vec<u16>>();

            let tab_rw_rq_registers = tab_rq_registers.iter()
                                    .map(|&x| !x).collect::<Vec<u16>>();

            let tab_rq_bits = tab_rw_rq_registers.iter()
                                    .map(|&x| (x % 2) as u8).collect::<Vec<u8>>();

            /* WRITE BIT */
            if let Err(e) = mb.write_bit(addr, tab_rq_bits[0] as i32) {
                println!("Error: Modbus::write_bit");
                println!("{}", e);
                nb_fail += 1;
            }
            else {
                if let Err(e) = mb.read_bits(addr, &mut tab_rp_bits[0..1]) {
                    println!("Error: Modbus::read_bits");
                    println!("{}", e);
                    nb_fail += 1;
                }
                else {
                    if tab_rq_bits[0] != tab_rp_bits[0] {
                        println!("Error: write_bit/read_bits mismatch");
                        nb_fail += 1;
                    }
                }
            }

            /* MULTIPLE BITS */
            if let Err(e) = mb.write_bits(addr, &tab_rq_bits[..]) {
                println!("Error: Modbus::write_bits");
                println!("{}", e);
                nb_fail += 1;
            }
            else {
                if let Err(e) = mb.read_bits(addr, &mut tab_rp_bits[..]) {
                    println!("Error: Modbus::read_bits");
                    println!("{}", e);
                    nb_fail += 1;
                }
                else {
                    for (i, item) in tab_rq_bits.iter().enumerate() {
                        if *item != tab_rp_bits[i] {
                            println!("Error: Modbus write_bits/read_bits: for index {}, read {}, write {}",
                                     i, tab_rp_bits[i], item);
                            nb_fail += 1;
                        }
                    }
                }
            }

            /* SINGLE REGISTER */
            if let Err(e) = mb.write_register(addr, tab_rq_registers[0] as i32) {
                println!("Error: Modbus::write_register");
                println!("{}", e);
                nb_fail += 1;
            }
            else {
                if let Err(e) = mb.read_registers(addr, &mut tab_rp_registers[0..1]) {
                    println!("Error: Modbus::read_registers");
                    println!("{}", e);
                    nb_fail += 1;
                }
                else {
                    if tab_rq_registers[0] != tab_rp_registers[0] {
                        println!("Error: write_register/read_registers mismatch");
                        nb_fail += 1;
                    }
                }
            }

            /* MULTIPLE REGISTERS */
            if let Err(e) = mb.write_registers(addr, &tab_rq_registers[..]) {
                println!("Error: Modbus::write_registers");
                println!("{}", e);
                nb_fail += 1;
            }
            else {
                if let Err(e) = mb.read_registers(addr, &mut tab_rp_registers[..]) {
                    println!("Error: Modbus::read_registers");
                    println!("{}", e);
                    nb_fail += 1;
                }
                else {
                    for (i, item) in tab_rq_registers.iter().enumerate() {
                        if *item != tab_rp_registers[i] {
                            println!("Error: Modbus write_registers/read_registers: for index {}, read {}, write {}",
                                     i, tab_rp_registers[i], item);
                            nb_fail += 1;
                        }
                    }
                }
            }

            /* R/W MULTIPLE REGISTERS */
            match mb.write_and_read_registers(addr, &tab_rq_registers[..],
                                                        addr, &mut tab_rp_registers[..]) {
                Ok(rv) =>
                    if rv != nb as i32 {
                        println!("Error: Modbus::write_and_read_registers mismatch");
                        nb_fail += 1;
                    }
                    else {
                        for (i, item) in tab_rq_registers.iter().enumerate() {
                            if *item != tab_rp_registers[i] {
                                println!("Error: Modbus write_registers/read_registers: for index {}, read {}, write {}",
                                         i, tab_rp_registers[i], item);
                                nb_fail += 1;
                            }
                        }
                    },
                Err(e) =>
                    println!("Error: Modbus::write_and_read_registers"),
            }
        }

        println!("Test: ");
        match nb_fail {
            0 => println!("SUCCESS"),
            x => println!("{} FAILS", x),
        }
    }
}
<|endoftext|>


<commit_before>//! This module is used to store stuff from Rust's AST in a more convenient
//! manner (and with prettier names) before cleaning.
pub use self::StructType::*;

use syntax::ast;
use syntax::ast::Name;
use syntax_expand::base::MacroKind;
use syntax_pos::{self, Span};

use rustc::hir;
use rustc::hir::def_id::CrateNum;
use rustc::hir::ptr::P;

pub struct Module<'hir> {
    pub name: Option<Name>,
    pub attrs: &'hir [ast::Attribute],
    pub where_outer: Span,
    pub where_inner: Span,
    pub extern_crates: Vec<ExternCrate<'hir>>,
    pub imports: Vec<Import<'hir>>,
    pub structs: Vec<Struct<'hir>>,
    pub unions: Vec<Union<'hir>>,
    pub enums: Vec<Enum<'hir>>,
    pub fns: Vec<Function<'hir>>,
    pub mods: Vec<Module<'hir>>,
    pub id: hir::HirId,
    pub typedefs: Vec<Typedef<'hir>>,
    pub opaque_tys: Vec<OpaqueTy<'hir>>,
    pub statics: Vec<Static<'hir>>,
    pub constants: Vec<Constant<'hir>>,
    pub traits: Vec<Trait<'hir>>,
    pub vis: &'hir hir::Visibility,
    pub impls: Vec<Impl<'hir>>,
    pub foreigns: Vec<ForeignItem<'hir>>,
    pub macros: Vec<Macro<'hir>>,
    pub proc_macros: Vec<ProcMacro<'hir>>,
    pub trait_aliases: Vec<TraitAlias<'hir>>,
    pub is_crate: bool,
}

impl Module<'hir> {
    pub fn new(
        name: Option<Name>,
        attrs: &'hir [ast::Attribute],
        vis: &'hir hir::Visibility,
    ) -> Module<'hir> {
        Module {
            name       : name,
            id: hir::CRATE_HIR_ID,
            vis,
            where_outer: syntax_pos::DUMMY_SP,
            where_inner: syntax_pos::DUMMY_SP,
            attrs,
            extern_crates: Vec::new(),
            imports    :   Vec::new(),
            structs    :   Vec::new(),
            unions     :   Vec::new(),
            enums      :   Vec::new(),
            fns        :   Vec::new(),
            mods       :   Vec::new(),
            typedefs   :   Vec::new(),
            opaque_tys :  Vec::new(),
            statics    :   Vec::new(),
            constants  :   Vec::new(),
            traits     :   Vec::new(),
            impls      :   Vec::new(),
            foreigns   :   Vec::new(),
            macros     :   Vec::new(),
            proc_macros:   Vec::new(),
            trait_aliases: Vec::new(),
            is_crate   : false,
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub enum StructType {
    /// A braced struct
    Plain,
    /// A tuple struct
    Tuple,
    /// A unit struct
    Unit,
}

pub struct Struct<'hir> {
    pub vis: &'hir hir::Visibility,
    pub id: hir::HirId,
    pub struct_type: StructType,
    pub name: Name,
    pub generics: &'hir hir::Generics,
    pub attrs: &'hir [ast::Attribute],
    pub fields: &'hir [hir::StructField],
    pub whence: Span,
}

pub struct Union<'hir> {
    pub vis: &'hir hir::Visibility,
    pub id: hir::HirId,
    pub struct_type: StructType,
    pub name: Name,
    pub generics: &'hir hir::Generics,
    pub attrs: &'hir [ast::Attribute],
    pub fields: &'hir [hir::StructField],
    pub whence: Span,
}

pub struct Enum<'hir> {
    pub vis: &'hir hir::Visibility,
    pub variants: Vec<Variant<'hir>>,
    pub generics: &'hir hir::Generics,
    pub attrs: &'hir [ast::Attribute],
    pub id: hir::HirId,
    pub whence: Span,
    pub name: Name,
}

pub struct Variant<'hir> {
    pub name: Name,
    pub id: hir::HirId,
    pub attrs: &'hir [ast::Attribute],
    pub def: &'hir hir::VariantData,
    pub whence: Span,
}

pub struct Function<'hir> {
    pub decl: &'hir hir::FnDecl,
    pub attrs: &'hir [ast::Attribute],
    pub id: hir::HirId,
    pub name: Name,
    pub vis: &'hir hir::Visibility,
    pub header: hir::FnHeader,
    pub whence: Span,
    pub generics: &'hir hir::Generics,
    pub body: hir::BodyId,
}

pub struct Typedef<'hir> {
    pub ty: &'hir P<hir::Ty>,
    pub gen: &'hir hir::Generics,
    pub name: Name,
    pub id: hir::HirId,
    pub attrs: &'hir [ast::Attribute],
    pub whence: Span,
    pub vis: &'hir hir::Visibility,
}

pub struct OpaqueTy<'hir> {
    pub opaque_ty: &'hir hir::OpaqueTy,
    pub name: Name,
    pub id: hir::HirId,
    pub attrs: &'hir [ast::Attribute],
    pub whence: Span,
    pub vis: &'hir hir::Visibility,
}

#[derive(Debug)]
pub struct Static<'hir> {
    pub type_: &'hir P<hir::Ty>,
    pub mutability: hir::Mutability,
    pub expr: hir::BodyId,
    pub name: Name,
    pub attrs: &'hir [ast::Attribute],
    pub vis: &'hir hir::Visibility,
    pub id: hir::HirId,
    pub whence: Span,
}

pub struct Constant<'hir> {
    pub type_: &'hir P<hir::Ty>,
    pub expr: hir::BodyId,
    pub name: Name,
    pub attrs: &'hir [ast::Attribute],
    pub vis: &'hir hir::Visibility,
    pub id: hir::HirId,
    pub whence: Span,
}

pub struct Trait<'hir> {
    pub is_auto: hir::IsAuto,
    pub unsafety: hir::Unsafety,
    pub name: Name,
    pub items: Vec<&'hir hir::TraitItem>,
    pub generics: &'hir hir::Generics,
    pub bounds: &'hir [hir::GenericBound],
    pub attrs: &'hir [ast::Attribute],
    pub id: hir::HirId,
    pub whence: Span,
    pub vis: &'hir hir::Visibility,
}

pub struct TraitAlias<'hir> {
    pub name: Name,
    pub generics: &'hir hir::Generics,
    pub bounds: &'hir [hir::GenericBound],
    pub attrs: &'hir [ast::Attribute],
    pub id: hir::HirId,
    pub whence: Span,
    pub vis: &'hir hir::Visibility,
}

#[derive(Debug)]
pub struct Impl<'hir> {
    pub unsafety: hir::Unsafety,
    pub polarity: hir::ImplPolarity,
    pub defaultness: hir::Defaultness,
    pub generics: &'hir hir::Generics,
    pub trait_: &'hir Option<hir::TraitRef>,
    pub for_: &'hir P<hir::Ty>,
    pub items: Vec<&'hir hir::ImplItem>,
    pub attrs: &'hir [ast::Attribute],
    pub whence: Span,
    pub vis: &'hir hir::Visibility,
    pub id: hir::HirId,
}

pub struct ForeignItem<'hir> {
    pub vis: &'hir hir::Visibility,
    pub id: hir::HirId,
    pub name: Name,
    pub kind: &'hir hir::ForeignItemKind,
    pub attrs: &'hir [ast::Attribute],
    pub whence: Span,
}

// For Macro we store the DefId instead of the NodeId, since we also create
// these imported macro_rules (which only have a DUMMY_NODE_ID).
pub struct Macro<'hir> {
    pub name: Name,
    pub hid: hir::HirId,
    pub def_id: hir::def_id::DefId,
    pub attrs: &'hir [ast::Attribute],
    pub whence: Span,
    pub matchers: hir::HirVec<Span>,
    pub imported_from: Option<Name>,
}

pub struct ExternCrate<'hir> {
    pub name: Name,
    pub cnum: CrateNum,
    pub path: Option<String>,
    pub vis: &'hir hir::Visibility,
    pub attrs: &'hir [ast::Attribute],
    pub whence: Span,
}

pub struct Import<'hir> {
    pub name: Name,
    pub id: hir::HirId,
    pub vis: &'hir hir::Visibility,
    pub attrs: &'hir [ast::Attribute],
    pub path: &'hir hir::Path,
    pub glob: bool,
    pub whence: Span,
}

pub struct ProcMacro<'hir> {
    pub name: Name,
    pub id: hir::HirId,
    pub kind: MacroKind,
    pub helpers: Vec<Name>,
    pub attrs: &'hir [ast::Attribute],
    pub whence: Span,
}

pub fn struct_type_from_def(vdata: &hir::VariantData) -> StructType {
    match *vdata {
        hir::VariantData::Struct(..) => Plain,
        hir::VariantData::Tuple(..) => Tuple,
        hir::VariantData::Unit(..) => Unit,
    }
}
<commit_msg>Rollup merge of #65706 - popzxc:add-missing-space, r=Mark-Simulacrum<commit_after>//! This module is used to store stuff from Rust's AST in a more convenient
//! manner (and with prettier names) before cleaning.
pub use self::StructType::*;

use syntax::ast;
use syntax::ast::Name;
use syntax_expand::base::MacroKind;
use syntax_pos::{self, Span};

use rustc::hir;
use rustc::hir::def_id::CrateNum;
use rustc::hir::ptr::P;

pub struct Module<'hir> {
    pub name: Option<Name>,
    pub attrs: &'hir [ast::Attribute],
    pub where_outer: Span,
    pub where_inner: Span,
    pub extern_crates: Vec<ExternCrate<'hir>>,
    pub imports: Vec<Import<'hir>>,
    pub structs: Vec<Struct<'hir>>,
    pub unions: Vec<Union<'hir>>,
    pub enums: Vec<Enum<'hir>>,
    pub fns: Vec<Function<'hir>>,
    pub mods: Vec<Module<'hir>>,
    pub id: hir::HirId,
    pub typedefs: Vec<Typedef<'hir>>,
    pub opaque_tys: Vec<OpaqueTy<'hir>>,
    pub statics: Vec<Static<'hir>>,
    pub constants: Vec<Constant<'hir>>,
    pub traits: Vec<Trait<'hir>>,
    pub vis: &'hir hir::Visibility,
    pub impls: Vec<Impl<'hir>>,
    pub foreigns: Vec<ForeignItem<'hir>>,
    pub macros: Vec<Macro<'hir>>,
    pub proc_macros: Vec<ProcMacro<'hir>>,
    pub trait_aliases: Vec<TraitAlias<'hir>>,
    pub is_crate: bool,
}

impl Module<'hir> {
    pub fn new(
        name: Option<Name>,
        attrs: &'hir [ast::Attribute],
        vis: &'hir hir::Visibility,
    ) -> Module<'hir> {
        Module {
            name       : name,
            id: hir::CRATE_HIR_ID,
            vis,
            where_outer: syntax_pos::DUMMY_SP,
            where_inner: syntax_pos::DUMMY_SP,
            attrs,
            extern_crates: Vec::new(),
            imports    :   Vec::new(),
            structs    :   Vec::new(),
            unions     :   Vec::new(),
            enums      :   Vec::new(),
            fns        :   Vec::new(),
            mods       :   Vec::new(),
            typedefs   :   Vec::new(),
            opaque_tys :   Vec::new(),
            statics    :   Vec::new(),
            constants  :   Vec::new(),
            traits     :   Vec::new(),
            impls      :   Vec::new(),
            foreigns   :   Vec::new(),
            macros     :   Vec::new(),
            proc_macros:   Vec::new(),
            trait_aliases: Vec::new(),
            is_crate   : false,
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub enum StructType {
    /// A braced struct
    Plain,
    /// A tuple struct
    Tuple,
    /// A unit struct
    Unit,
}

pub struct Struct<'hir> {
    pub vis: &'hir hir::Visibility,
    pub id: hir::HirId,
    pub struct_type: StructType,
    pub name: Name,
    pub generics: &'hir hir::Generics,
    pub attrs: &'hir [ast::Attribute],
    pub fields: &'hir [hir::StructField],
    pub whence: Span,
}

pub struct Union<'hir> {
    pub vis: &'hir hir::Visibility,
    pub id: hir::HirId,
    pub struct_type: StructType,
    pub name: Name,
    pub generics: &'hir hir::Generics,
    pub attrs: &'hir [ast::Attribute],
    pub fields: &'hir [hir::StructField],
    pub whence: Span,
}

pub struct Enum<'hir> {
    pub vis: &'hir hir::Visibility,
    pub variants: Vec<Variant<'hir>>,
    pub generics: &'hir hir::Generics,
    pub attrs: &'hir [ast::Attribute],
    pub id: hir::HirId,
    pub whence: Span,
    pub name: Name,
}

pub struct Variant<'hir> {
    pub name: Name,
    pub id: hir::HirId,
    pub attrs: &'hir [ast::Attribute],
    pub def: &'hir hir::VariantData,
    pub whence: Span,
}

pub struct Function<'hir> {
    pub decl: &'hir hir::FnDecl,
    pub attrs: &'hir [ast::Attribute],
    pub id: hir::HirId,
    pub name: Name,
    pub vis: &'hir hir::Visibility,
    pub header: hir::FnHeader,
    pub whence: Span,
    pub generics: &'hir hir::Generics,
    pub body: hir::BodyId,
}

pub struct Typedef<'hir> {
    pub ty: &'hir P<hir::Ty>,
    pub gen: &'hir hir::Generics,
    pub name: Name,
    pub id: hir::HirId,
    pub attrs: &'hir [ast::Attribute],
    pub whence: Span,
    pub vis: &'hir hir::Visibility,
}

pub struct OpaqueTy<'hir> {
    pub opaque_ty: &'hir hir::OpaqueTy,
    pub name: Name,
    pub id: hir::HirId,
    pub attrs: &'hir [ast::Attribute],
    pub whence: Span,
    pub vis: &'hir hir::Visibility,
}

#[derive(Debug)]
pub struct Static<'hir> {
    pub type_: &'hir P<hir::Ty>,
    pub mutability: hir::Mutability,
    pub expr: hir::BodyId,
    pub name: Name,
    pub attrs: &'hir [ast::Attribute],
    pub vis: &'hir hir::Visibility,
    pub id: hir::HirId,
    pub whence: Span,
}

pub struct Constant<'hir> {
    pub type_: &'hir P<hir::Ty>,
    pub expr: hir::BodyId,
    pub name: Name,
    pub attrs: &'hir [ast::Attribute],
    pub vis: &'hir hir::Visibility,
    pub id: hir::HirId,
    pub whence: Span,
}

pub struct Trait<'hir> {
    pub is_auto: hir::IsAuto,
    pub unsafety: hir::Unsafety,
    pub name: Name,
    pub items: Vec<&'hir hir::TraitItem>,
    pub generics: &'hir hir::Generics,
    pub bounds: &'hir [hir::GenericBound],
    pub attrs: &'hir [ast::Attribute],
    pub id: hir::HirId,
    pub whence: Span,
    pub vis: &'hir hir::Visibility,
}

pub struct TraitAlias<'hir> {
    pub name: Name,
    pub generics: &'hir hir::Generics,
    pub bounds: &'hir [hir::GenericBound],
    pub attrs: &'hir [ast::Attribute],
    pub id: hir::HirId,
    pub whence: Span,
    pub vis: &'hir hir::Visibility,
}

#[derive(Debug)]
pub struct Impl<'hir> {
    pub unsafety: hir::Unsafety,
    pub polarity: hir::ImplPolarity,
    pub defaultness: hir::Defaultness,
    pub generics: &'hir hir::Generics,
    pub trait_: &'hir Option<hir::TraitRef>,
    pub for_: &'hir P<hir::Ty>,
    pub items: Vec<&'hir hir::ImplItem>,
    pub attrs: &'hir [ast::Attribute],
    pub whence: Span,
    pub vis: &'hir hir::Visibility,
    pub id: hir::HirId,
}

pub struct ForeignItem<'hir> {
    pub vis: &'hir hir::Visibility,
    pub id: hir::HirId,
    pub name: Name,
    pub kind: &'hir hir::ForeignItemKind,
    pub attrs: &'hir [ast::Attribute],
    pub whence: Span,
}

// For Macro we store the DefId instead of the NodeId, since we also create
// these imported macro_rules (which only have a DUMMY_NODE_ID).
pub struct Macro<'hir> {
    pub name: Name,
    pub hid: hir::HirId,
    pub def_id: hir::def_id::DefId,
    pub attrs: &'hir [ast::Attribute],
    pub whence: Span,
    pub matchers: hir::HirVec<Span>,
    pub imported_from: Option<Name>,
}

pub struct ExternCrate<'hir> {
    pub name: Name,
    pub cnum: CrateNum,
    pub path: Option<String>,
    pub vis: &'hir hir::Visibility,
    pub attrs: &'hir [ast::Attribute],
    pub whence: Span,
}

pub struct Import<'hir> {
    pub name: Name,
    pub id: hir::HirId,
    pub vis: &'hir hir::Visibility,
    pub attrs: &'hir [ast::Attribute],
    pub path: &'hir hir::Path,
    pub glob: bool,
    pub whence: Span,
}

pub struct ProcMacro<'hir> {
    pub name: Name,
    pub id: hir::HirId,
    pub kind: MacroKind,
    pub helpers: Vec<Name>,
    pub attrs: &'hir [ast::Attribute],
    pub whence: Span,
}

pub fn struct_type_from_def(vdata: &hir::VariantData) -> StructType {
    match *vdata {
        hir::VariantData::Struct(..) => Plain,
        hir::VariantData::Tuple(..) => Tuple,
        hir::VariantData::Unit(..) => Unit,
    }
}
<|endoftext|>