<commit_before>use cd::cd;
use command_handler::CommandResult;
use env::env;
use env::setenv;
use env::unsetenv;
use launch_bin::launch_bin;
use parser::lexer::TokenOperator;
use parser::nodes::ASTNode;
use parser::nodes::BinOp;
use parser::nodes::Command;
use parser::parser::Parser;
use std::fs::{File, OpenOptions};
use std::process::{Child, Stdio, Output};
use std::io::Write;

pub trait NodeVisitor {
    fn visit(&mut self, node: &Box<dyn ASTNode>, stdin: Option<Stdio>, stdout: Option<Stdio>) -> CommandResult;
}

pub struct Interpreter {
    pub parser: Parser
}

impl NodeVisitor for Interpreter {
    fn visit(&mut self, node: &Box<dyn ASTNode>, stdin: Option<Stdio>, stdout: Option<Stdio>) -> CommandResult {
        if node.type_of() == "BinOp" {
            self.visit_binop(&node.downcast_ref::<BinOp>().unwrap())
        } else {
            self.visit_command(&node.downcast_ref::<Command>().unwrap(), stdin, stdout)
        }
    }
}

impl Interpreter {
    fn set_command(&mut self, command: String) {
        self.parser.set_command(command);
    }

    fn visit_command(&mut self, node: &Command, stdin: Option<Stdio>, stdout: Option<Stdio>) -> CommandResult {
        let mut cmd: Vec<String> = node.value.clone().split(' ').map(|x: &str| x.to_string()).collect();

        let result = match cmd[0].as_str() {
            "cd"        => cd(&mut cmd),
            "env"       => env(),
            "setenv"    => setenv(&mut cmd),
            "unsetenv"  => unsetenv(&mut cmd),
            _           => CommandResult {child : launch_bin(&mut cmd, stdin, stdout), output: None, status: None}
        };
        return result
    }

    fn get_child(&mut self, result: CommandResult) -> Option<Child> {
        match result.child {
            Some(ch) => {
                Some(ch)
            },
            None => {
                None
            }
        }
    }

    fn wait_for_child(&mut self, result: CommandResult) -> Option<Output> {
        match self.get_child(result) {
            Some(ch) => {
                match ch.wait_with_output() {
                    Ok(output) => {
                        Some(output)
                    },
                    Err(_) => None
                }
            },
            None => {
                None
            }
        }
    }

    fn binop_pipe(&mut self, n: &BinOp) -> CommandResult {
        let pipe1 = self.visit(&n.left, None, Some(Stdio::piped()));
        let cr = match pipe1.output {
            None => {
                let out1 = self.wait_for_child(pipe1);
                let mut pipe2 = self.visit(&n.right, Some(Stdio::piped()), Some(Stdio::piped()));
                pipe2.child.as_mut().unwrap().stdin.as_mut().unwrap().write_all(out1.unwrap().stdout.as_slice()).ok();

                let output = self.wait_for_child(pipe2);

                CommandResult {
                    child: None,
                    output,
                    status: None
                }
            },
            Some(out1) => {
                let mut pipe2 = self.visit(&n.right, Some(Stdio::piped()), Some(Stdio::piped()));
                pipe2.child.as_mut().unwrap().stdin.as_mut().unwrap().write_all(out1.stdout.as_slice()).ok();

                let output = self.wait_for_child(pipe2);

                CommandResult {
                    child: None,
                    output,
                    status: None
                }
            }
        };
//        print!("{}", std::str::from_utf8(cr.output.as_ref().unwrap().stdout.as_slice()).ok().unwrap());
        return cr;
    }

    fn binop_semi(&mut self, n: &BinOp) -> CommandResult {
        let r = self.visit(&n.left, None, None);
        self.wait_for_child(r);
        let r = self.visit(&n.right, None, None);
        CommandResult{child: None, output: Some(self.wait_for_child(r).unwrap()), status: None}
    }

    fn binop_and(&mut self, n: &BinOp) -> CommandResult {
        let r = self.visit(&n.left, None, None);
        let output_1 = self.wait_for_child(r).unwrap();
        let status_1 = output_1.status.success();

        if status_1 {
            let r = self.visit(&n.right, None, None);
            let output_2 = self.wait_for_child(r).unwrap();
            let status_2 = output_2.status.success();
            if !status_2 {
                CommandResult { child: None, output: Some(output_2), status: None }
            } else {
                CommandResult { child: None, output: Some(output_1), status: None }
            }
        } else {
            CommandResult { child: None, output: Some(output_1), status: None }
        }
    }

    fn binop_or(&mut self, n: &BinOp) -> CommandResult {
        let r = self.visit(&n.left, None, None);
        let output_1 = self.wait_for_child(r).unwrap();
        let status_1 = output_1.status.code().unwrap();

        if status_1 != 0 {
            let r = self.visit(&n.right, None, None);
            let output_2 = self.wait_for_child(r).unwrap();
            return CommandResult { child: None, output: Some(output_2), status: None }
        }
        return CommandResult { child: None, output: Some(output_1), status: None }
    }

    fn binop_single_right(&mut self, n: &BinOp) -> CommandResult {
        let path = &n.right.downcast_ref::<Command>().unwrap().value;
        match  File::create(&path) {
            Ok(f) => {
                let r = self.visit(&n.left, None, Some(f.into()));
                let output = self.wait_for_child(r);
                CommandResult { child: None, output, status: None }
            },
            Err(_) => {
                println!("RustSH : File error : {}", path);
                CommandResult { child: None, output: None, status: Some(1) }
            },
        };
        CommandResult { child: None, output: None, status: None }
    }

    fn binop_double_right(&mut self, n: &BinOp) -> CommandResult {
        let path = &n.right.downcast_ref::<Command>().unwrap().value;
        match  OpenOptions::new().append(true).create(true).open(&path) {
            Ok(f) => {
                let r = self.visit(&n.left, None, Some(f.into()));
                let output = self.wait_for_child(r);
                CommandResult { child: None, output, status: None }
            },
            Err(_) => {
                println!("RustSH : Could not open file : {}", path);
                CommandResult { child: None, output: None, status: Some(1) }
            },
        };
        CommandResult { child: None, output: None, status: None}
    }

    fn binop_single_left(&mut self, n: &BinOp) -> CommandResult {
        let path = &n.right.downcast_ref::<Command>().unwrap().value;

        match File::open(&path) {
            Ok(f) => {
                let r = self.visit(&n.left, Some(f.into()), None);
                let output = self.wait_for_child(r);
                CommandResult { child: None, output, status: None }
            },
            Err(_) => {
                println!("RustSH: {} : file not found", path);
                CommandResult { child: None, output: None, status: Some(1) }
            },
        };
        CommandResult { child: None, output: None, status: None }
    }

    fn visit_binop(&mut self, node: &BinOp) -> CommandResult {
        let n = *&node;
        match n.token.kind {
            TokenOperator::Semicolon => { return self.binop_semi(node) }
            TokenOperator::And => { return self.binop_and(&node) }
            TokenOperator::Or => { return self.binop_or(&node) }
            TokenOperator::SingleRight => { return self.binop_single_right(&node) }
            TokenOperator::DoubleRight => { return self.binop_double_right(&node) }
            TokenOperator::SingleLeft => { return self.binop_single_left(&node) }
            TokenOperator::Pipe => { self.binop_pipe(&node) }
            _ => {unimplemented!()}
        }
    }

//    fn dbug_tree(&self, node: &Box<dyn ASTNode>) {
//        if node.type_of() == "BinOp" {
//            let n: &BinOp = &node.downcast_ref::<BinOp>().unwrap();
//            println!("{:?}", n.token);
//            self.dbug_tree(&n.left);
//            self.dbug_tree(&n.right);
//        } else if node.type_of() == "Eof" {
//            println!("EOF")
//        } else {
//            let n: &Command = &node.downcast_ref::<Command>().unwrap();
//            println!("command {:?}", n.value);
//        }
//    }

    pub fn interpret(&mut self, command: String) {
        self.set_command(command);
        let node = self.parser.expr();
        let mut result = self.visit(&node, None, None);

        match &mut result.child {
            Some(_) => {
                self.wait_for_child(result);
            },
            None => {}
        }
    }
}
<commit_msg>pipes seem to work ?<commit_after>use cd::cd;
use command_handler::CommandResult;
use env::env;
use env::setenv;
use env::unsetenv;
use launch_bin::launch_bin;
use parser::lexer::TokenOperator;
use parser::nodes::ASTNode;
use parser::nodes::BinOp;
use parser::nodes::Command;
use parser::parser::Parser;
use std::fs::{File, OpenOptions};
use std::process::{Child, Stdio, Output};
use std::io::Write;

pub trait NodeVisitor {
    fn visit(&mut self, node: &Box<dyn ASTNode>, stdin: Option<Stdio>, stdout: Option<Stdio>) -> CommandResult;
}

pub struct Interpreter {
    pub parser: Parser
}

impl NodeVisitor for Interpreter {
    fn visit(&mut self, node: &Box<dyn ASTNode>, stdin: Option<Stdio>, stdout: Option<Stdio>) -> CommandResult {
        if node.type_of() == "BinOp" {
            self.visit_binop(&node.downcast_ref::<BinOp>().unwrap())
        } else {
            self.visit_command(&node.downcast_ref::<Command>().unwrap(), stdin, stdout)
        }
    }
}

impl Interpreter {
    fn set_command(&mut self, command: String) {
        self.parser.set_command(command);
    }

    fn visit_command(&mut self, node: &Command, stdin: Option<Stdio>, stdout: Option<Stdio>) -> CommandResult {
        let mut cmd: Vec<String> = node.value.clone().split(' ').map(|x: &str| x.to_string()).collect();

        let result = match cmd[0].as_str() {
            "cd"        => cd(&mut cmd),
            "env"       => env(),
            "setenv"    => setenv(&mut cmd),
            "unsetenv"  => unsetenv(&mut cmd),
            _           => CommandResult {child : launch_bin(&mut cmd, stdin, stdout), output: None, status: None}
        };
        return result
    }

    fn get_child(&mut self, result: CommandResult) -> Option<Child> {
        match result.child {
            Some(ch) => {
                Some(ch)
            },
            None => {
                None
            }
        }
    }

    fn wait_for_child(&mut self, result: CommandResult) -> Option<Output> {
        match self.get_child(result) {
            Some(ch) => {
                match ch.wait_with_output() {
                    Ok(output) => {
                        Some(output)
                    },
                    Err(_) => None
                }
            },
            None => {
                None
            }
        }
    }

    fn binop_pipe(&mut self, n: &BinOp) -> CommandResult {
        let pipe1 = self.visit(&n.left, None, Some(Stdio::piped()));
        let cr = match pipe1.output {
            None => {
                let out1 = self.wait_for_child(pipe1);
                let mut pipe2 = self.visit(&n.right, Some(Stdio::piped()), Some(Stdio::piped()));
                pipe2.child.as_mut().unwrap().stdin.as_mut().unwrap().write_all(out1.unwrap().stdout.as_slice()).ok();

                let output = self.wait_for_child(pipe2);

                CommandResult {
                    child: None,
                    output,
                    status: None
                }
            },
            Some(out1) => {
                let mut pipe = self.visit(&n.right, Some(Stdio::piped()), Some(Stdio::piped()));
                pipe.child.as_mut().unwrap().stdin.as_mut().unwrap().write_all(out1.stdout.as_slice()).ok();

                let output = self.wait_for_child(pipe);

                CommandResult {
                    child: None,
                    output,
                    status: None
                }
            }
        };
        return cr;
    }

    fn binop_semi(&mut self, n: &BinOp) -> CommandResult {
        let r = self.visit(&n.left, None, None);
        self.wait_for_child(r);
        let r = self.visit(&n.right, None, None);
        CommandResult{child: None, output: Some(self.wait_for_child(r).unwrap()), status: None}
    }

    fn binop_and(&mut self, n: &BinOp) -> CommandResult {
        let r = self.visit(&n.left, None, None);
        let output_1 = self.wait_for_child(r).unwrap();
        let status_1 = output_1.status.success();

        if status_1 {
            let r = self.visit(&n.right, None, None);
            let output_2 = self.wait_for_child(r).unwrap();
            let status_2 = output_2.status.success();
            if !status_2 {
                CommandResult { child: None, output: Some(output_2), status: None }
            } else {
                CommandResult { child: None, output: Some(output_1), status: None }
            }
        } else {
            CommandResult { child: None, output: Some(output_1), status: None }
        }
    }

    fn binop_or(&mut self, n: &BinOp) -> CommandResult {
        let r = self.visit(&n.left, None, None);
        let output_1 = self.wait_for_child(r).unwrap();
        let status_1 = output_1.status.code().unwrap();

        if status_1 != 0 {
            let r = self.visit(&n.right, None, None);
            let output_2 = self.wait_for_child(r).unwrap();
            return CommandResult { child: None, output: Some(output_2), status: None }
        }
        return CommandResult { child: None, output: Some(output_1), status: None }
    }

    fn binop_single_right(&mut self, n: &BinOp) -> CommandResult {
        let path = &n.right.downcast_ref::<Command>().unwrap().value;
        match  File::create(&path) {
            Ok(mut f) => {
                let r = self.visit(&n.left, None, None);
                match r.output {
                    Some(out) => {
                        f.write_all(out.stdout.as_ref()).ok();
                    },
                    None => {
                        let output = self.wait_for_child(r);
                        match output {
                            Some(out) => {
                                f.write_all(out.stdout.as_ref()).ok();
                            },
                            None => {}
                        }
                    }
                }

                CommandResult { child: None, output: None, status: None }
            },
            Err(_) => {
                println!("RustSH : File error : {}", path);
                CommandResult { child: None, output: None, status: Some(1) }
            },
        };
        CommandResult { child: None, output: None, status: None }
    }

    fn binop_double_right(&mut self, n: &BinOp) -> CommandResult {
        let path = &n.right.downcast_ref::<Command>().unwrap().value;
        match  OpenOptions::new().append(true).create(true).open(&path) {
            Ok(mut f) => {
                let r = self.visit(&n.left, None, None);
                match r.output {
                    Some(out) => {
                        f.write_all(out.stdout.as_ref()).ok();
                    },
                    None => {
                        let output = self.wait_for_child(r);
                        match output {
                            Some(out) => {
                                f.write_all(out.stdout.as_ref()).ok();
                            },
                            None => {}
                        }
                    }
                }

                CommandResult { child: None, output: None, status: None }
            },
            Err(_) => {
                println!("RustSH : Could not open file : {}", path);
                CommandResult { child: None, output: None, status: Some(1) }
            },
        };
        CommandResult { child: None, output: None, status: None}
    }

    fn binop_single_left(&mut self, n: &BinOp) -> CommandResult {
        let path = &n.right.downcast_ref::<Command>().unwrap().value;

        match File::open(&path) {
            Ok(f) => {
                let r = self.visit(&n.left, Some(f.into()), None);
                let output = self.wait_for_child(r);
                CommandResult { child: None, output, status: None }
            },
            Err(_) => {
                println!("RustSH: {} : file not found", path);
                CommandResult { child: None, output: None, status: Some(1) }
            },
        };
        CommandResult { child: None, output: None, status: None }
    }

    fn visit_binop(&mut self, node: &BinOp) -> CommandResult {
        let n = *&node;
        match n.token.kind {
            TokenOperator::Semicolon => { return self.binop_semi(node) }
            TokenOperator::And => { return self.binop_and(&node) }
            TokenOperator::Or => { return self.binop_or(&node) }
            TokenOperator::SingleRight => { return self.binop_single_right(&node) }
            TokenOperator::DoubleRight => { return self.binop_double_right(&node) }
            TokenOperator::SingleLeft => { return self.binop_single_left(&node) }
            TokenOperator::Pipe => { self.binop_pipe(&node) }
            _ => {unimplemented!()}
        }
    }

//    fn dbug_tree(&self, node: &Box<dyn ASTNode>) {
//        if node.type_of() == "BinOp" {
//            let n: &BinOp = &node.downcast_ref::<BinOp>().unwrap();
//            println!("{:?}", n.token);
//            self.dbug_tree(&n.left);
//            self.dbug_tree(&n.right);
//        } else if node.type_of() == "Eof" {
//            println!("EOF")
//        } else {
//            let n: &Command = &node.downcast_ref::<Command>().unwrap();
//            println!("command {:?}", n.value);
//        }
//    }

    pub fn interpret(&mut self, command: String) {
        self.set_command(command);
        let node = self.parser.expr();
        let mut result = self.visit(&node, None, None);

        match &mut result.child {
            Some(_) => {
                match self.wait_for_child(result) {
                    Some(out) => {
                        if !out.stdout.is_empty() {
                            println!("{}", std::str::from_utf8(out.stdout.as_slice()).ok().unwrap());
                        }
                    },
                    None => {}
                }
            },
            None => {
                match result.output {
                    Some(out) => {
                        if !out.stdout.is_empty() {
                            print!("{}", std::str::from_utf8(out.stdout.as_slice()).ok().unwrap());
                        }
                    },
                    None => {}
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use input::Input;
use keyboard::Key;
use view::View;
use frontends::{Frontend, EditorEvent};
use modes::{Mode, ModeType, InsertMode, NormalMode};
use overlay::{Overlay, OverlayEvent};

use command::Command;
use command::{Action, BuilderEvent, Operation, Instruction};

/// The main Editor structure
///
/// This is the top-most structure in Iota.
pub struct Editor<'e, T: Frontend> {
    view: View,
    running: bool,
    frontend: T,
    mode: Box<Mode + 'e>,
}

impl<'e, T: Frontend> Editor<'e, T> {
    /// Create a new Editor instance
    pub fn new(source: Input, mode: Box<Mode + 'e>, frontend: T) -> Editor<'e, T> {
        let height = frontend.get_window_height();
        let width = frontend.get_window_width();
        let view = View::new(source, width, height);

        Editor {
            view: view,
            running: true,
            frontend: frontend,
            mode: mode,
        }
    }

    /// Handle key events
    ///
    /// Key events can be handled in an Overlay, OR in the current Mode.
    ///
    /// If there is an active Overlay, the key event is sent there, which gives
    /// back an OverlayEvent. We then parse this OverlayEvent and determine if
    /// the Overlay is finished and can be cleared. The response from the
    /// Overlay is then converted to a Command and sent off to be handled.
    ///
    /// If there is no active Overlay, the key event is sent to the current
    /// Mode, which returns a Command which we dispatch to handle_command.
    fn handle_key_event(&mut self, key: Option<Key>) {
        let key = match key {
            Some(k) => k,
            None => return
        };

        let mut remove_overlay = false;
        let command = match self.view.overlay {
            Overlay::None => self.mode.handle_key_event(key),
            _             => {
                let event = self.view.overlay.handle_key_event(key);
                match event {
                    OverlayEvent::Finished(response) => {
                        remove_overlay = true;
                        self.handle_overlay_response(response)
                    }

                    _ => { BuilderEvent::Incomplete }
                }
            }
        };

        if remove_overlay {
            self.view.overlay = Overlay::None;
            self.view.clear(&mut self.frontend);
        }

        if let BuilderEvent::Complete(c) = command {
            self.handle_command(c);
        }
    }

    /// Translate the response from an Overlay to a Command wrapped in a BuilderEvent
    ///
    /// In most cases, we will just want to convert the response directly to
    /// a Command, however in some cases we will want to perform other actions
    /// first, such as in the case of Overlay::SavePrompt.
    fn handle_overlay_response(&mut self, response: Option<String>) -> BuilderEvent {
        // FIXME: This entire method neext to be updated
        match response {
            Some(data) => {
                match self.view.overlay {

                    // FIXME: this is just a temporary fix
                    Overlay::Prompt { ref data, .. } => {
                        match &**data {
                            "q" | "quit" => BuilderEvent::Complete(Command::exit_editor()),

                            _ => BuilderEvent::Incomplete
                        }
                    }

                    Overlay::SavePrompt { .. } => {
                        let path = Path::new(&*data);
                        self.view.buffer.file_path = Some(path);
                        BuilderEvent::Complete(Command::save_buffer())
                    }
                    _ => BuilderEvent::Incomplete,
                }
            }
            None => BuilderEvent::Incomplete
        }
    }

    /// Handle resize events
    ///
    /// width and height represent the new height of the window.
    fn handle_resize_event(&mut self, width: usize, height: usize) {
        self.view.resize(width, height);
    }

    /// Draw the current view to the frontend
    fn draw(&mut self) {
        self.view.draw(&mut self.frontend);
    }

    /// Handle the given command, performing the associated action
    fn handle_command(&mut self, command: Command) {
        let repeat = if command.number > 0 {
            command.number
        } else { 1 };
        for _ in range(0, repeat) {
            match command.action {
                Action::Instruction(i) => self.handle_instruction(i, command),
                Action::Operation(o) => self.handle_operation(o, command),
            }
        }
    }

    fn handle_instruction(&mut self, instruction: Instruction, command: Command) {
        match instruction {
            Instruction::SaveBuffer => { self.view.try_save_buffer() }
            Instruction::ExitEditor => { self.running = false; }
            Instruction::SetMark(mark) => {
                if let Some(object) = command.object {
                    self.view.move_mark(mark, object)
                }
            }
            Instruction::SetOverlay(overlay_type) => {
                self.view.set_overlay(overlay_type)
            }
            Instruction::SetMode(mode) => {
                match mode {
                    ModeType::Insert => { self.mode = Box::new(InsertMode::new()) }
                    ModeType::Normal => { self.mode = Box::new(NormalMode::new()) }
                }
            }
        }
    }

    fn handle_operation(&mut self, operation: Operation, command: Command) {
        match operation {
            Operation::Insert(c) => {
                for _ in 0..command.number {
                    self.view.insert_char(c)
                }
            }
            Operation::DeleteObject => {
                if let Some(obj) = command.object {
                    self.view.delete_object(obj);
                }
            }
            Operation::DeleteFromMark(m) => {
                if command.object.is_some() {
                    self.view.delete_from_mark_to_object(m, command.object.unwrap())
                }
            }
            Operation::Undo => { self.view.undo() }
            Operation::Redo => { self.view.redo() }
        }
    }

    /// Start Iota!
    pub fn start(&mut self) {
        while self.running {
            self.draw();
            self.frontend.present();
            let event = self.frontend.poll_event();

            match event {
                EditorEvent::KeyEvent(key)         => self.handle_key_event(key),
                EditorEvent::Resize(width, height) => self.handle_resize_event(width, height),

                _ => {}
            }
        }
    }
}
<commit_msg>re-enabled saving buffer in normal mode<commit_after>use input::Input;
use keyboard::Key;
use view::View;
use frontends::{Frontend, EditorEvent};
use modes::{Mode, ModeType, InsertMode, NormalMode};
use overlay::{Overlay, OverlayEvent};

use command::Command;
use command::{Action, BuilderEvent, Operation, Instruction};

/// The main Editor structure
///
/// This is the top-most structure in Iota.
pub struct Editor<'e, T: Frontend> {
    view: View,
    running: bool,
    frontend: T,
    mode: Box<Mode + 'e>,
}

impl<'e, T: Frontend> Editor<'e, T> {
    /// Create a new Editor instance
    pub fn new(source: Input, mode: Box<Mode + 'e>, frontend: T) -> Editor<'e, T> {
        let height = frontend.get_window_height();
        let width = frontend.get_window_width();
        let view = View::new(source, width, height);

        Editor {
            view: view,
            running: true,
            frontend: frontend,
            mode: mode,
        }
    }

    /// Handle key events
    ///
    /// Key events can be handled in an Overlay, OR in the current Mode.
    ///
    /// If there is an active Overlay, the key event is sent there, which gives
    /// back an OverlayEvent. We then parse this OverlayEvent and determine if
    /// the Overlay is finished and can be cleared. The response from the
    /// Overlay is then converted to a Command and sent off to be handled.
    ///
    /// If there is no active Overlay, the key event is sent to the current
    /// Mode, which returns a Command which we dispatch to handle_command.
    fn handle_key_event(&mut self, key: Option<Key>) {
        let key = match key {
            Some(k) => k,
            None => return
        };

        let mut remove_overlay = false;
        let command = match self.view.overlay {
            Overlay::None => self.mode.handle_key_event(key),
            _             => {
                let event = self.view.overlay.handle_key_event(key);
                match event {
                    OverlayEvent::Finished(response) => {
                        remove_overlay = true;
                        self.handle_overlay_response(response)
                    }

                    _ => { BuilderEvent::Incomplete }
                }
            }
        };

        if remove_overlay {
            self.view.overlay = Overlay::None;
            self.view.clear(&mut self.frontend);
        }

        if let BuilderEvent::Complete(c) = command {
            self.handle_command(c);
        }
    }

    /// Translate the response from an Overlay to a Command wrapped in a BuilderEvent
    ///
    /// In most cases, we will just want to convert the response directly to
    /// a Command, however in some cases we will want to perform other actions
    /// first, such as in the case of Overlay::SavePrompt.
    fn handle_overlay_response(&mut self, response: Option<String>) -> BuilderEvent {
        // FIXME: This entire method neext to be updated
        match response {
            Some(data) => {
                match self.view.overlay {

                    // FIXME: this is just a temporary fix
                    Overlay::Prompt { ref data, .. } => {
                        match &**data {
                            // FIXME: need to find a better system for these commands
                            //        They should be chainable
                            //          ie: wq - save & quit
                            //        They should also take arguments
                            //          ie w file.txt - write buffer to file.txt
                            "q" | "quit" => BuilderEvent::Complete(Command::exit_editor()),
                            "w" | "write" => BuilderEvent::Complete(Command::save_buffer()),

                            _ => BuilderEvent::Incomplete
                        }
                    }

                    Overlay::SavePrompt { .. } => {
                        let path = Path::new(&*data);
                        self.view.buffer.file_path = Some(path);
                        BuilderEvent::Complete(Command::save_buffer())
                    }
                    _ => BuilderEvent::Incomplete,
                }
            }
            None => BuilderEvent::Incomplete
        }
    }

    /// Handle resize events
    ///
    /// width and height represent the new height of the window.
    fn handle_resize_event(&mut self, width: usize, height: usize) {
        self.view.resize(width, height);
    }

    /// Draw the current view to the frontend
    fn draw(&mut self) {
        self.view.draw(&mut self.frontend);
    }

    /// Handle the given command, performing the associated action
    fn handle_command(&mut self, command: Command) {
        let repeat = if command.number > 0 {
            command.number
        } else { 1 };
        for _ in range(0, repeat) {
            match command.action {
                Action::Instruction(i) => self.handle_instruction(i, command),
                Action::Operation(o) => self.handle_operation(o, command),
            }
        }
    }

    fn handle_instruction(&mut self, instruction: Instruction, command: Command) {
        match instruction {
            Instruction::SaveBuffer => { self.view.try_save_buffer() }
            Instruction::ExitEditor => { self.running = false; }
            Instruction::SetMark(mark) => {
                if let Some(object) = command.object {
                    self.view.move_mark(mark, object)
                }
            }
            Instruction::SetOverlay(overlay_type) => {
                self.view.set_overlay(overlay_type)
            }
            Instruction::SetMode(mode) => {
                match mode {
                    ModeType::Insert => { self.mode = Box::new(InsertMode::new()) }
                    ModeType::Normal => { self.mode = Box::new(NormalMode::new()) }
                }
            }
        }
    }

    fn handle_operation(&mut self, operation: Operation, command: Command) {
        match operation {
            Operation::Insert(c) => {
                for _ in 0..command.number {
                    self.view.insert_char(c)
                }
            }
            Operation::DeleteObject => {
                if let Some(obj) = command.object {
                    self.view.delete_object(obj);
                }
            }
            Operation::DeleteFromMark(m) => {
                if command.object.is_some() {
                    self.view.delete_from_mark_to_object(m, command.object.unwrap())
                }
            }
            Operation::Undo => { self.view.undo() }
            Operation::Redo => { self.view.redo() }
        }
    }

    /// Start Iota!
    pub fn start(&mut self) {
        while self.running {
            self.draw();
            self.frontend.present();
            let event = self.frontend.poll_event();

            match event {
                EditorEvent::KeyEvent(key)         => self.handle_key_event(key),
                EditorEvent::Resize(width, height) => self.handle_resize_event(width, height),

                _ => {}
            }
        }
    }
}
<|endoftext|>


<commit_before>use ::serde_json;
use ::zip;
use std::collections::HashMap;

#[derive(Serialize, Debug)]
struct MultiArchiveJsonWriter {
    archives: HashMap<String, ZipArchiveJsonWriter>,
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct ZipArchiveJsonWriter {
    objects: HashMap<String, ZipObjectJsonWriter>,
}

impl ZipArchiveJsonWriter {
    pub fn new() -> ZipArchiveJsonWriter {
        ZipArchiveJsonWriter { objects: HashMap::new() }
    }
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct ZipObjectJsonWriter {
    compression_type: String,
    original_size: u64,
    compressed_size: u64,
    compression_rate: String,
}

#[cfg(test)]
mod tests {
    use super::*;

    fn get_zip_object() -> ZipObjectJsonWriter {
        ZipObjectJsonWriter {
            compression_type: format!("{}", zip::CompressionMethod::Deflated),
            original_size: 100,
            compressed_size: 50,
            compression_rate: String::from("50%"),
        }
    }

    #[test]
    fn test_serialize_object_json_writer() {
        let zip_object = get_zip_object();

        let zip_object_serialized = serde_json::to_string(&zip_object)
            .unwrap();

        let zip_object_pretty = serde_json::
            to_string_pretty(&zip_object).unwrap();

        let zip_object_deserialized: ZipObjectJsonWriter =
            serde_json::from_str(zip_object_serialized.as_str()).unwrap();

        let zip_object_depretty: ZipObjectJsonWriter =
            serde_json::from_str(zip_object_pretty.as_str()).unwrap();

        assert_eq!(zip_object, zip_object_deserialized);
        assert_eq!(zip_object, zip_object_depretty);
    }

    #[test]
    fn test_new_archive_has_empty_map_of_zip_objects() {
        let zip_archive = ZipArchiveJsonWriter::new();
        let empty_hashmap: HashMap<String, ZipObjectJsonWriter> =
            HashMap::new();

        assert_eq!(empty_hashmap, zip_archive.objects);
    }

    #[test]
    fn test_serialize_archive_json_writer() {
        let zip_object_name = String::from("foo.txt");
        let zip_object = get_zip_object();

        {
            let mut zip_archive = ZipArchiveJsonWriter::new();
            zip_archive.objects.insert(zip_object_name, zip_object);

            let zip_archive_serialized = serde_json::to_string(&zip_archive)
                .unwrap();
            println!("zip_archive_serialized: {}", zip_archive_serialized);

            let zip_archive_pretty = serde_json::to_string_pretty(&zip_archive)
                .unwrap();
            println!("zip_archive_pretty: {}", zip_archive_pretty);

            let zip_archive_deserialized: ZipArchiveJsonWriter =
                serde_json::from_str(zip_archive_serialized.as_str()).unwrap();

            let zip_archive_depretty: ZipArchiveJsonWriter =
                serde_json::from_str(zip_archive_serialized.as_str()).unwrap();

            assert_eq!(zip_archive, zip_archive_deserialized);
            assert_eq!(zip_archive, zip_archive_depretty);
        }
    }
}
<commit_msg>Add MultiArchiveJsonWriter::new and test<commit_after>use ::serde_json;
use ::zip;
use std::collections::HashMap;

#[derive(Serialize, Debug)]
struct MultiArchiveJsonWriter {
    archives: HashMap<String, ZipArchiveJsonWriter>,
}

impl MultiArchiveJsonWriter {
    pub fn new() -> MultiArchiveJsonWriter {
        MultiArchiveJsonWriter { archives: HashMap::new() }
    }
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct ZipArchiveJsonWriter {
    objects: HashMap<String, ZipObjectJsonWriter>,
}

impl ZipArchiveJsonWriter {
    pub fn new() -> ZipArchiveJsonWriter {
        ZipArchiveJsonWriter { objects: HashMap::new() }
    }
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct ZipObjectJsonWriter {
    compression_type: String,
    original_size: u64,
    compressed_size: u64,
    compression_rate: String,
}

#[cfg(test)]
mod tests {
    use super::*;

    fn get_zip_object() -> ZipObjectJsonWriter {
        ZipObjectJsonWriter {
            compression_type: format!("{}", zip::CompressionMethod::Deflated),
            original_size: 100,
            compressed_size: 50,
            compression_rate: String::from("50%"),
        }
    }

    #[test]
    fn test_serialize_object_json_writer() {
        let zip_object = get_zip_object();

        let zip_object_serialized = serde_json::to_string(&zip_object)
            .unwrap();

        let zip_object_pretty = serde_json::
            to_string_pretty(&zip_object).unwrap();

        let zip_object_deserialized: ZipObjectJsonWriter =
            serde_json::from_str(zip_object_serialized.as_str()).unwrap();

        let zip_object_depretty: ZipObjectJsonWriter =
            serde_json::from_str(zip_object_pretty.as_str()).unwrap();

        assert_eq!(zip_object, zip_object_deserialized);
        assert_eq!(zip_object, zip_object_depretty);
    }

    #[test]
    fn test_new_archive_has_empty_map_of_zip_objects() {
        let zip_archive = ZipArchiveJsonWriter::new();
        let empty_hashmap: HashMap<String, ZipObjectJsonWriter> =
            HashMap::new();

        assert_eq!(empty_hashmap, zip_archive.objects);
    }

    #[test]
    fn test_serialize_archive_json_writer() {
        let zip_object_name = String::from("foo.txt");
        let zip_object = get_zip_object();

        {
            let mut zip_archive = ZipArchiveJsonWriter::new();
            zip_archive.objects.insert(zip_object_name, zip_object);

            let zip_archive_serialized = serde_json::to_string(&zip_archive)
                .unwrap();
            println!("zip_archive_serialized: {}", zip_archive_serialized);

            let zip_archive_pretty = serde_json::to_string_pretty(&zip_archive)
                .unwrap();
            println!("zip_archive_pretty: {}", zip_archive_pretty);

            let zip_archive_deserialized: ZipArchiveJsonWriter =
                serde_json::from_str(zip_archive_serialized.as_str()).unwrap();

            let zip_archive_depretty: ZipArchiveJsonWriter =
                serde_json::from_str(zip_archive_serialized.as_str()).unwrap();

            assert_eq!(zip_archive, zip_archive_deserialized);
            assert_eq!(zip_archive, zip_archive_depretty);
        }
    }

    #[test]
    fn test_new_multi_archive_has_empty_map_of_zip_archives() {
        let multi_archive = MultiArchiveJsonWriter::new();
        let empty_hashmap: HashMap<String, ZipArchiveJsonWriter> =
            HashMap::new();

        assert_eq!(empty_hashmap, multi_archive.archives);
    }
}
<|endoftext|>


<commit_before>use crate::instance::siginfo_ext::SiginfoExt;
use crate::instance::{FaultDetails, TerminationDetails, YieldedVal};
use crate::sysdeps::UContext;
use libc::{SIGBUS, SIGSEGV};
use std::any::Any;
use std::ffi::{CStr, CString};

/// The representation of a Lucet instance's state machine.
pub enum State {
    /// The instance is freshly-created, but needs to run the start section before running other entrypoints.
    ///
    /// Transitions to `Running` when the start section is run, and then to `Ready` if it succeeds.
    NotStarted,

    /// The instance is ready to run.
    ///
    /// Transitions to `Running` when the instance is run, or to `Ready` when it's reset.
    Ready,

    /// The instance is running.
    ///
    /// Transitions to `Ready` when the guest function returns normally, or to `Faulted`,
    /// `Terminating`, or `Yielding` if the instance faults, terminates, or yields.
    Running { async_context: bool },

    /// The instance has faulted, potentially fatally.
    ///
    /// Transitions to `Faulted` when filling in additional fault details, to `Running` if
    /// re-running a non-fatally faulted instance, or to `Ready` or `NotStarted` when the instance
    /// is reset.
    Faulted {
        details: FaultDetails,
        siginfo: libc::siginfo_t,
        context: UContext,
    },

    /// The instance is in the process of terminating.
    ///
    /// Transitions only to `Terminated`; the `TerminationDetails` are always extracted into a
    /// `RunResult` before anything else happens to the instance.
    Terminating { details: TerminationDetails },

    /// The instance has terminated, and must be reset before running again.
    ///
    /// Transitions to `Ready` or `NotStarted` if the instance is reset.
    Terminated,

    /// The instance is in the process of yielding.
    ///
    /// Transitions only to `Yielded`; the `YieldedVal` is always extracted into a
    /// `RunResult` before anything else happens to the instance.
    Yielding {
        val: YieldedVal,
        /// A phantom value carrying the type of the expected resumption value.
        ///
        /// Concretely, this should only ever be `Box<PhantomData<R>>` where `R` is the type
        /// the guest expects upon resumption.
        expecting: Box<dyn Any>,
    },

    /// The instance has yielded.
    ///
    /// Transitions to `Running` if the instance is resumed, or to `Ready` or `NotStarted` if the
    /// instance is reset.
    Yielded {
        /// A phantom value carrying the type of the expected resumption value.
        ///
        /// Concretely, this should only ever be `Box<PhantomData<R>>` where `R` is the type
        /// the guest expects upon resumption.
        expecting: Box<dyn Any>,
    },

    /// A placeholder state used with `std::mem::replace()` when a new state must be constructed by
    /// moving values out of an old state.
    ///
    /// This is used so that we do not need a `Clone` impl for this type, which would add
    /// unnecessary constraints to the types of values instances could yield or terminate with.
    ///
    /// It is an error for this state to appear outside of a transition between other states.
    Transitioning,
}

impl std::fmt::Display for State {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            State::NotStarted => write!(f, "not started"),
            State::Ready => write!(f, "ready"),
            State::Running {
                async_context: false,
            } => write!(f, "running"),
            State::Running {
                async_context: true,
            } => write!(f, "running (in async context)"),
            State::Faulted {
                details, siginfo, ..
            } => {
                write!(f, "{}", details)?;
                write!(
                    f,
                    " triggered by {}: ",
                    strsignal_wrapper(siginfo.si_signo)
                        .into_string()
                        .expect("strsignal returns valid UTF-8")
                )?;

                if siginfo.si_signo == SIGSEGV || siginfo.si_signo == SIGBUS {
                    // We know this is inside the heap guard, because by the time we get here,
                    // `lucet_error_verify_trap_safety` will have run and validated it.
                    write!(
                        f,
                        " accessed memory at {:p} (inside heap guard)",
                        siginfo.si_addr_ext()
                    )?;
                }
                Ok(())
            }
            State::Terminated { .. } => write!(f, "terminated"),
            State::Terminating { .. } => write!(f, "terminating"),
            State::Yielding { .. } => write!(f, "yielding"),
            State::Yielded { .. } => write!(f, "yielded"),
            State::Transitioning { .. } => {
                write!(f, "transitioning (IF YOU SEE THIS, THERE'S PROBABLY A BUG)")
            }
        }
    }
}

impl State {
    pub fn is_not_started(&self) -> bool {
        if let State::NotStarted { .. } = self {
            true
        } else {
            false
        }
    }

    pub fn is_ready(&self) -> bool {
        if let State::Ready { .. } = self {
            true
        } else {
            false
        }
    }

    pub fn is_running(&self) -> bool {
        if let State::Running { .. } = self {
            true
        } else {
            false
        }
    }

    pub fn is_running_async(&self) -> bool {
        if let State::Running { async_context } = self {
            *async_context
        } else {
            false
        }
    }

    pub fn is_faulted(&self) -> bool {
        if let State::Faulted { .. } = self {
            true
        } else {
            false
        }
    }

    pub fn is_fatal(&self) -> bool {
        if let State::Faulted {
            details: FaultDetails { fatal, .. },
            ..
        } = self
        {
            *fatal
        } else {
            false
        }
    }

    pub fn is_terminated(&self) -> bool {
        if let State::Terminated { .. } = self {
            true
        } else {
            false
        }
    }

    pub fn is_yielded(&self) -> bool {
        if let State::Yielded { .. } = self {
            true
        } else {
            false
        }
    }

    pub fn is_yielding(&self) -> bool {
        if let State::Yielding { .. } = self {
            true
        } else {
            false
        }
    }
}

// TODO: PR into `libc`
extern "C" {
    #[no_mangle]
    fn strsignal(sig: libc::c_int) -> *mut libc::c_char;
}

// TODO: PR into `nix`
fn strsignal_wrapper(sig: libc::c_int) -> CString {
    unsafe { CStr::from_ptr(strsignal(sig)).to_owned() }
}
<commit_msg>state: add doc comments<commit_after>use crate::instance::siginfo_ext::SiginfoExt;
use crate::instance::{FaultDetails, TerminationDetails, YieldedVal};
use crate::sysdeps::UContext;
use libc::{SIGBUS, SIGSEGV};
use std::any::Any;
use std::ffi::{CStr, CString};

/// The representation of a Lucet instance's state machine.
pub enum State {
    /// The instance is freshly-created, but needs to run the start section before running other entrypoints.
    ///
    /// Transitions to `Running` when the start section is run, and then to `Ready` if it succeeds.
    NotStarted,

    /// The instance is ready to run.
    ///
    /// Transitions to `Running` when the instance is run, or to `Ready` when it's reset.
    Ready,

    /// The instance is running.
    ///
    /// Transitions to `Ready` when the guest function returns normally, or to `Faulted`,
    /// `Terminating`, or `Yielding` if the instance faults, terminates, or yields.
    Running {
        /// Indicates whether the instance is running in an async context (`Instance::run_async`)
        /// or not. Needed by `Vmctx::block_on`.
        async_context: bool,
    },

    /// The instance has faulted, potentially fatally.
    ///
    /// Transitions to `Faulted` when filling in additional fault details, to `Running` if
    /// re-running a non-fatally faulted instance, or to `Ready` or `NotStarted` when the instance
    /// is reset.
    Faulted {
        details: FaultDetails,
        siginfo: libc::siginfo_t,
        context: UContext,
    },

    /// The instance is in the process of terminating.
    ///
    /// Transitions only to `Terminated`; the `TerminationDetails` are always extracted into a
    /// `RunResult` before anything else happens to the instance.
    Terminating { details: TerminationDetails },

    /// The instance has terminated, and must be reset before running again.
    ///
    /// Transitions to `Ready` or `NotStarted` if the instance is reset.
    Terminated,

    /// The instance is in the process of yielding.
    ///
    /// Transitions only to `Yielded`; the `YieldedVal` is always extracted into a
    /// `RunResult` before anything else happens to the instance.
    Yielding {
        val: YieldedVal,
        /// A phantom value carrying the type of the expected resumption value.
        ///
        /// Concretely, this should only ever be `Box<PhantomData<R>>` where `R` is the type
        /// the guest expects upon resumption.
        expecting: Box<dyn Any>,
    },

    /// The instance has yielded.
    ///
    /// Transitions to `Running` if the instance is resumed, or to `Ready` or `NotStarted` if the
    /// instance is reset.
    Yielded {
        /// A phantom value carrying the type of the expected resumption value.
        ///
        /// Concretely, this should only ever be `Box<PhantomData<R>>` where `R` is the type
        /// the guest expects upon resumption.
        expecting: Box<dyn Any>,
    },

    /// A placeholder state used with `std::mem::replace()` when a new state must be constructed by
    /// moving values out of an old state.
    ///
    /// This is used so that we do not need a `Clone` impl for this type, which would add
    /// unnecessary constraints to the types of values instances could yield or terminate with.
    ///
    /// It is an error for this state to appear outside of a transition between other states.
    Transitioning,
}

impl std::fmt::Display for State {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            State::NotStarted => write!(f, "not started"),
            State::Ready => write!(f, "ready"),
            State::Running {
                async_context: false,
            } => write!(f, "running"),
            State::Running {
                async_context: true,
            } => write!(f, "running (in async context)"),
            State::Faulted {
                details, siginfo, ..
            } => {
                write!(f, "{}", details)?;
                write!(
                    f,
                    " triggered by {}: ",
                    strsignal_wrapper(siginfo.si_signo)
                        .into_string()
                        .expect("strsignal returns valid UTF-8")
                )?;

                if siginfo.si_signo == SIGSEGV || siginfo.si_signo == SIGBUS {
                    // We know this is inside the heap guard, because by the time we get here,
                    // `lucet_error_verify_trap_safety` will have run and validated it.
                    write!(
                        f,
                        " accessed memory at {:p} (inside heap guard)",
                        siginfo.si_addr_ext()
                    )?;
                }
                Ok(())
            }
            State::Terminated { .. } => write!(f, "terminated"),
            State::Terminating { .. } => write!(f, "terminating"),
            State::Yielding { .. } => write!(f, "yielding"),
            State::Yielded { .. } => write!(f, "yielded"),
            State::Transitioning { .. } => {
                write!(f, "transitioning (IF YOU SEE THIS, THERE'S PROBABLY A BUG)")
            }
        }
    }
}

impl State {
    pub fn is_not_started(&self) -> bool {
        if let State::NotStarted { .. } = self {
            true
        } else {
            false
        }
    }

    pub fn is_ready(&self) -> bool {
        if let State::Ready { .. } = self {
            true
        } else {
            false
        }
    }

    pub fn is_running(&self) -> bool {
        if let State::Running { .. } = self {
            true
        } else {
            false
        }
    }

    pub fn is_running_async(&self) -> bool {
        if let State::Running { async_context } = self {
            *async_context
        } else {
            false
        }
    }

    pub fn is_faulted(&self) -> bool {
        if let State::Faulted { .. } = self {
            true
        } else {
            false
        }
    }

    pub fn is_fatal(&self) -> bool {
        if let State::Faulted {
            details: FaultDetails { fatal, .. },
            ..
        } = self
        {
            *fatal
        } else {
            false
        }
    }

    pub fn is_terminated(&self) -> bool {
        if let State::Terminated { .. } = self {
            true
        } else {
            false
        }
    }

    pub fn is_yielded(&self) -> bool {
        if let State::Yielded { .. } = self {
            true
        } else {
            false
        }
    }

    pub fn is_yielding(&self) -> bool {
        if let State::Yielding { .. } = self {
            true
        } else {
            false
        }
    }
}

// TODO: PR into `libc`
extern "C" {
    #[no_mangle]
    fn strsignal(sig: libc::c_int) -> *mut libc::c_char;
}

// TODO: PR into `nix`
fn strsignal_wrapper(sig: libc::c_int) -> CString {
    unsafe { CStr::from_ptr(strsignal(sig)).to_owned() }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

extern crate capnp;
pub mod addressbook_capnp {
  include!(concat!(env!("OUT_DIR"), "/addressbook_capnp.rs"));
}

use capnp::message::TypedReader;
use capnp::serialize::OwnedSegments;
use std::sync::mpsc;
use std::thread;

pub mod addressbook {
    use addressbook_capnp::{address_book, person};
    use capnp::{serialize};
    use capnp::message::TypedReader;

    pub fn build_address_book() -> TypedReader<serialize::OwnedSegments, address_book::Owned> {
        let mut message = ::capnp::message::Builder::new_default();
        {
            let address_book = message.init_root::<address_book::Builder>();

            let mut people = address_book.init_people(2);

            {
                let mut alice = people.borrow().get(0);
                alice.set_id(123);
                alice.set_name("Alice");
                alice.set_email("alice@example.com");
                {
                    let mut alice_phones = alice.borrow().init_phones(1);
                    alice_phones.borrow().get(0).set_number("555-1212");
                    alice_phones.borrow().get(0).set_type(person::phone_number::Type::Mobile);
                }
                alice.get_employment().set_school("MIT");
            }

            {
                let mut bob = people.get(1);
                bob.set_id(456);
                bob.set_name("Bob");
                bob.set_email("bob@example.com");
                {
                    let mut bob_phones = bob.borrow().init_phones(2);
                    bob_phones.borrow().get(0).set_number("555-4567");
                    bob_phones.borrow().get(0).set_type(person::phone_number::Type::Home);
                    bob_phones.borrow().get(1).set_number("555-7654");
                    bob_phones.borrow().get(1).set_type(person::phone_number::Type::Work);
                }
                bob.get_employment().set_unemployed(());
            }
        }

        let mut buffer = Vec::new();
        ::capnp::serialize::write_message(&mut buffer, &message).unwrap();

        // Unwrap here is safe because we just created the message above
        let message_reader = ::capnp::serialize::read_message(
            &mut buffer.as_slice(),
            ::capnp::message::ReaderOptions::new()
        ).unwrap();

        TypedReader::new(message_reader)
    }
}

pub fn main() {

    let book = addressbook::build_address_book();

    let (tx_book, rx_book) = mpsc::channel::<TypedReader<OwnedSegments, addressbook_capnp::address_book::Owned>>();
    let (tx_id, rx_id) = mpsc::channel::<u32>();

    thread::spawn(move || {
        let addressbook_reader = rx_book.recv().unwrap();
        let addressbook = addressbook_reader.get().unwrap();
        let first_person = addressbook.get_people().unwrap().get(0);
        let first_id = first_person.get_id();
        tx_id.send(first_id)
    });

    tx_book.send(book).unwrap();
    let first_id = rx_id.recv().unwrap();
    let exit_code = if first_id == 123 {
        0
    } else {
        1
    };

    std::process::exit(exit_code);
}
<commit_msg>Don't use exit codes, just assert_eq!<commit_after>// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

extern crate capnp;
pub mod addressbook_capnp {
  include!(concat!(env!("OUT_DIR"), "/addressbook_capnp.rs"));
}

use capnp::message::TypedReader;
use capnp::serialize::OwnedSegments;
use std::sync::mpsc;
use std::thread;

pub mod addressbook {
    use addressbook_capnp::{address_book, person};
    use capnp::{serialize};
    use capnp::message::TypedReader;

    pub fn build_address_book() -> TypedReader<serialize::OwnedSegments, address_book::Owned> {
        let mut message = ::capnp::message::Builder::new_default();
        {
            let address_book = message.init_root::<address_book::Builder>();

            let mut people = address_book.init_people(2);

            {
                let mut alice = people.borrow().get(0);
                alice.set_id(123);
                alice.set_name("Alice");
                alice.set_email("alice@example.com");
                {
                    let mut alice_phones = alice.borrow().init_phones(1);
                    alice_phones.borrow().get(0).set_number("555-1212");
                    alice_phones.borrow().get(0).set_type(person::phone_number::Type::Mobile);
                }
                alice.get_employment().set_school("MIT");
            }

            {
                let mut bob = people.get(1);
                bob.set_id(456);
                bob.set_name("Bob");
                bob.set_email("bob@example.com");
                {
                    let mut bob_phones = bob.borrow().init_phones(2);
                    bob_phones.borrow().get(0).set_number("555-4567");
                    bob_phones.borrow().get(0).set_type(person::phone_number::Type::Home);
                    bob_phones.borrow().get(1).set_number("555-7654");
                    bob_phones.borrow().get(1).set_type(person::phone_number::Type::Work);
                }
                bob.get_employment().set_unemployed(());
            }
        }

        let mut buffer = Vec::new();
        ::capnp::serialize::write_message(&mut buffer, &message).unwrap();

        // Unwrap here is safe because we just created the message above
        let message_reader = ::capnp::serialize::read_message(
            &mut buffer.as_slice(),
            ::capnp::message::ReaderOptions::new()
        ).unwrap();

        TypedReader::new(message_reader)
    }
}

pub fn main() {

    let book = addressbook::build_address_book();

    let (tx_book, rx_book) = mpsc::channel::<TypedReader<OwnedSegments, addressbook_capnp::address_book::Owned>>();
    let (tx_id, rx_id) = mpsc::channel::<u32>();

    thread::spawn(move || {
        let addressbook_reader = rx_book.recv().unwrap();
        let addressbook = addressbook_reader.get().unwrap();
        let first_person = addressbook.get_people().unwrap().get(0);
        let first_id = first_person.get_id();
        tx_id.send(first_id)
    });

    tx_book.send(book).unwrap();
    let first_id = rx_id.recv().unwrap();
    assert_eq!(first_id, 123);
}
<|endoftext|>


<commit_before>//! A Box can be a field of a heap struct only if the boxed type has 'static lifetime.

// error-pattern: the type `core::option::Option<ThingRef<'a>>` does not fulfill the required lifetime

#[macro_use] extern crate toy_gc;
mod pairs_aux;
use toy_gc::*;
use pairs_aux::*;

gc_ref_type! {
    pub struct Thing / ThingRef / ThingStorage / ThingRefStorage <'a> {
        boxed_ref / set_boxed_ref: Box<Option<ThingRef<'a>>>
    }
}

fn main() {
    with_heap(|heap| {
        let thing_1 = heap.alloc(Thing { boxed_ref: Box::new(None) });
        let thing_2 = heap.alloc(Thing { boxed_ref: Box::new(Some(thing_1)) });
        std::mem::drop(thing_1);
        heap.force_gc();  // Boxes aren't marked; thing_1 is collected!
        let thing_1_revived = (*thing_2.boxed_ref()).unwrap();  // bad
    });
}

<commit_msg>whitespace<commit_after>//! A Box can be a field of a heap struct only if the boxed type has 'static lifetime.

// error-pattern: the type `core::option::Option<ThingRef<'a>>` does not fulfill the required lifetime

#[macro_use] extern crate toy_gc;
mod pairs_aux;
use toy_gc::*;
use pairs_aux::*;

gc_ref_type! {
    pub struct Thing / ThingRef / ThingStorage / ThingRefStorage <'a> {
        boxed_ref / set_boxed_ref: Box<Option<ThingRef<'a>>>
    }
}

fn main() {
    with_heap(|heap| {
        let thing_1 = heap.alloc(Thing { boxed_ref: Box::new(None) });
        let thing_2 = heap.alloc(Thing { boxed_ref: Box::new(Some(thing_1)) });
        std::mem::drop(thing_1);
        heap.force_gc();  // Boxes aren't marked; thing_1 is collected!
        let thing_1_revived = (*thing_2.boxed_ref()).unwrap();  // bad
    });
}
<|endoftext|>


<commit_before>
extern crate python3_sys as pyffi;
extern crate numpy_sys;

use numpy_sys::*;
use std::os::raw::c_void;

unsafe fn get_api(offset: isize) -> *const *const c_void {
    let api = &PyArray_API as *const *const c_void;
    api.offset(offset)
}

/// check link succeeds
#[test]
fn test_link() {
    let res = unsafe {
        let fptr = get_api(0) as (*const extern "C" fn() -> u32);
        (*fptr)()
    };
    println!("ndarray C version = {}", res);
}
<commit_msg>Test for PyArray_Arange (fail)<commit_after>
extern crate python3_sys as pyffi;
extern crate numpy_sys;

use pyffi::*;
use numpy_sys::*;
use std::os::raw::c_void;

unsafe fn get_api(offset: isize) -> *const *const c_void {
    let api = &PyArray_API as *const *const c_void;
    api.offset(offset)
}

#[test]
fn test_no_pyobject() {
    let res = unsafe {
        let fptr = get_api(0) as (*const extern "C" fn() -> u32);
        (*fptr)()
    };
    println!("ndarray C version = {}", res);
}

#[test]
fn test_return_pyobject() {
    let _res = unsafe {
        let fptr = get_api(186) as (*const extern "C" fn(f64, f64, f64, i32) -> *mut PyObject);
        (*fptr)(0.0, 1.0, 0.1, 12)
    };
}
<|endoftext|>


<commit_before>use crate::{assist_context::AssistBuilder, AssistContext, AssistId, Assists};
use ast::{NameOwner, ParamList, TypeAscriptionOwner, TypeParamList, TypeRef};
use ra_syntax::{ast, ast::TypeParamsOwner, AstNode, SyntaxKind, TextRange, TextSize};
use rustc_hash::FxHashSet;

static ASSIST_NAME: &str = "change_lifetime_anon_to_named";
static ASSIST_LABEL: &str = "Give anonymous lifetime a name";

// Assist: change_lifetime_anon_to_named
//
// Change an anonymous lifetime to a named lifetime.
//
// ```
// impl Cursor<'_<|>> {
//     fn node(self) -> &SyntaxNode {
//         match self {
//             Cursor::Replace(node) | Cursor::Before(node) => node,
//         }
//     }
// }
// ```
// ->
// ```
// impl<'a> Cursor<'a> {
//     fn node(self) -> &SyntaxNode {
//         match self {
//             Cursor::Replace(node) | Cursor::Before(node) => node,
//         }
//     }
// }
// ```
// FIXME: How can we handle renaming any one of multiple anonymous lifetimes?
// FIXME: should also add support for the case fun(f: &Foo) -> &<|>Foo
pub(crate) fn change_lifetime_anon_to_named(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let lifetime_token = ctx
        .find_token_at_offset(SyntaxKind::LIFETIME)
        .filter(|lifetime| lifetime.text() == "'_")?;
    if let Some(fn_def) = lifetime_token.ancestors().find_map(ast::FnDef::cast) {
        generate_fn_def_assist(acc, &fn_def, lifetime_token.text_range())
    } else if let Some(impl_def) = lifetime_token.ancestors().find_map(ast::ImplDef::cast) {
        // only allow naming the last anonymous lifetime
        lifetime_token.next_token().filter(|tok| tok.kind() == SyntaxKind::R_ANGLE)?;
        generate_impl_def_assist(acc, &impl_def, lifetime_token.text_range())
    } else {
        None
    }
}

/// Generate the assist for the fn def case
fn generate_fn_def_assist(
    acc: &mut Assists,
    fn_def: &ast::FnDef,
    lifetime_loc: TextRange,
) -> Option<()> {
    let param_list: ParamList = fn_def.param_list()?;
    let new_lifetime_param = generate_unique_lifetime_param_name(&fn_def.type_param_list())?;
    let end_of_fn_ident = fn_def.name()?.ident_token()?.text_range().end();
    let self_param =
        // use the self if it's a reference and has no explicit lifetime
        param_list.self_param().filter(|p| p.lifetime_token().is_none() && p.amp_token().is_some());
    // compute the location which implicitly has the same lifetime as the anonymous lifetime
    let loc_needing_lifetime = if let Some(self_param) = self_param {
        // if we have a self reference, use that
        Some(self_param.self_token()?.text_range().start())
    } else {
        // otherwise, if there's a single reference parameter without a named liftime, use that
        let fn_params_without_lifetime: Vec<_> = param_list
            .params()
            .filter_map(|param| match param.ascribed_type() {
                Some(TypeRef::ReferenceType(ascribed_type))
                    if ascribed_type.lifetime_token() == None =>
                {
                    Some(ascribed_type.amp_token()?.text_range().end())
                }
                _ => None,
            })
            .collect();
        match fn_params_without_lifetime.len() {
            1 => Some(fn_params_without_lifetime.into_iter().nth(0)?),
            0 => None,
            // multiple unnnamed is invalid. assist is not applicable
            _ => return None,
        }
    };
    acc.add(AssistId(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |builder| {
        add_lifetime_param(fn_def, builder, end_of_fn_ident, new_lifetime_param);
        builder.replace(lifetime_loc, format!("'{}", new_lifetime_param));
        loc_needing_lifetime.map(|loc| builder.insert(loc, format!("'{} ", new_lifetime_param)));
    })
}

/// Generate the assist for the impl def case
fn generate_impl_def_assist(
    acc: &mut Assists,
    impl_def: &ast::ImplDef,
    lifetime_loc: TextRange,
) -> Option<()> {
    let new_lifetime_param = generate_unique_lifetime_param_name(&impl_def.type_param_list())?;
    let end_of_impl_kw = impl_def.impl_token()?.text_range().end();
    acc.add(AssistId(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |builder| {
        add_lifetime_param(impl_def, builder, end_of_impl_kw, new_lifetime_param);
        builder.replace(lifetime_loc, format!("'{}", new_lifetime_param));
    })
}

/// Given a type parameter list, generate a unique lifetime parameter name
/// which is not in the list
fn generate_unique_lifetime_param_name(
    existing_type_param_list: &Option<TypeParamList>,
) -> Option<char> {
    match existing_type_param_list {
        Some(type_params) => {
            let used_lifetime_params: FxHashSet<_> = type_params
                .lifetime_params()
                .map(|p| p.syntax().text().to_string()[1..].to_owned())
                .collect();
            (b'a'..=b'z').map(char::from).find(|c| !used_lifetime_params.contains(&c.to_string()))
        }
        None => Some('a'),
    }
}

/// Add the lifetime param to `builder`. If there are type parameters in `type_params_owner`, add it to the end. Otherwise
/// add new type params brackets with the lifetime parameter at `new_type_params_loc`.
fn add_lifetime_param<TypeParamsOwner: ast::TypeParamsOwner>(
    type_params_owner: &TypeParamsOwner,
    builder: &mut AssistBuilder,
    new_type_params_loc: TextSize,
    new_lifetime_param: char,
) {
    match type_params_owner.type_param_list() {
        // add the new lifetime parameter to an existing type param list
        Some(type_params) => {
            builder.insert(
                (u32::from(type_params.syntax().text_range().end()) - 1).into(),
                format!(", '{}", new_lifetime_param),
            );
        }
        // create a new type param list containing only the new lifetime parameter
        None => {
            builder.insert(new_type_params_loc, format!("<'{}>", new_lifetime_param));
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::tests::{check_assist, check_assist_not_applicable};

    #[test]
    fn test_example_case() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"impl Cursor<'_<|>> {
                fn node(self) -> &SyntaxNode {
                    match self {
                        Cursor::Replace(node) | Cursor::Before(node) => node,
                    }
                }
            }"#,
            r#"impl<'a> Cursor<'a> {
                fn node(self) -> &SyntaxNode {
                    match self {
                        Cursor::Replace(node) | Cursor::Before(node) => node,
                    }
                }
            }"#,
        );
    }

    #[test]
    fn test_example_case_simplified() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"impl Cursor<'_<|>> {"#,
            r#"impl<'a> Cursor<'a> {"#,
        );
    }

    #[test]
    fn test_example_case_cursor_after_tick() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"impl Cursor<'<|>_> {"#,
            r#"impl<'a> Cursor<'a> {"#,
        );
    }

    #[test]
    fn test_example_case_cursor_before_tick() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"impl Cursor<<|>'_> {"#,
            r#"impl<'a> Cursor<'a> {"#,
        );
    }

    #[test]
    fn test_not_applicable_cursor_position() {
        check_assist_not_applicable(change_lifetime_anon_to_named, r#"impl Cursor<'_><|> {"#);
        check_assist_not_applicable(change_lifetime_anon_to_named, r#"impl Cursor<|><'_> {"#);
    }

    #[test]
    fn test_not_applicable_lifetime_already_name() {
        check_assist_not_applicable(change_lifetime_anon_to_named, r#"impl Cursor<'a<|>> {"#);
        check_assist_not_applicable(
            change_lifetime_anon_to_named,
            r#"fn my_fun<'a>() -> X<'a<|>>"#,
        );
    }

    #[test]
    fn test_with_type_parameter() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"impl<T> Cursor<T, '_<|>>"#,
            r#"impl<T, 'a> Cursor<T, 'a>"#,
        );
    }

    #[test]
    fn test_with_existing_lifetime_name_conflict() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"impl<'a, 'b> Cursor<'a, 'b, '_<|>>"#,
            r#"impl<'a, 'b, 'c> Cursor<'a, 'b, 'c>"#,
        );
    }

    #[test]
    fn test_function_return_value_anon_lifetime_param() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"fn my_fun() -> X<'_<|>>"#,
            r#"fn my_fun<'a>() -> X<'a>"#,
        );
    }

    #[test]
    fn test_function_return_value_anon_reference_lifetime() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"fn my_fun() -> &'_<|> X"#,
            r#"fn my_fun<'a>() -> &'a X"#,
        );
    }

    #[test]
    fn test_function_param_anon_lifetime() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"fn my_fun(x: X<'_<|>>)"#,
            r#"fn my_fun<'a>(x: X<'a>)"#,
        );
    }

    #[test]
    fn test_function_add_lifetime_to_params() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"fn my_fun(f: &Foo) -> X<'_<|>>"#,
            r#"fn my_fun<'a>(f: &'a Foo) -> X<'a>"#,
        );
    }

    #[test]
    fn test_function_add_lifetime_to_params_in_presence_of_other_lifetime() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"fn my_fun<'other>(f: &Foo, b: &'other Bar) -> X<'_<|>>"#,
            r#"fn my_fun<'other, 'a>(f: &'a Foo, b: &'other Bar) -> X<'a>"#,
        );
    }

    #[test]
    fn test_function_not_applicable_without_self_and_multiple_unnamed_param_lifetimes() {
        // this is not permitted under lifetime elision rules
        check_assist_not_applicable(
            change_lifetime_anon_to_named,
            r#"fn my_fun(f: &Foo, b: &Bar) -> X<'_<|>>"#,
        );
    }

    #[test]
    fn test_function_add_lifetime_to_self_ref_param() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"fn my_fun<'other>(&self, f: &Foo, b: &'other Bar) -> X<'_<|>>"#,
            r#"fn my_fun<'other, 'a>(&'a self, f: &Foo, b: &'other Bar) -> X<'a>"#,
        );
    }

    #[test]
    fn test_function_add_lifetime_to_param_with_non_ref_self() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"fn my_fun<'other>(self, f: &Foo, b: &'other Bar) -> X<'_<|>>"#,
            r#"fn my_fun<'other, 'a>(self, f: &'a Foo, b: &'other Bar) -> X<'a>"#,
        );
    }
}
<commit_msg>Cleanup imports<commit_after>use ra_syntax::{
    ast::{self, NameOwner, TypeAscriptionOwner, TypeParamsOwner},
    AstNode, SyntaxKind, TextRange, TextSize,
};
use rustc_hash::FxHashSet;

use crate::{assist_context::AssistBuilder, AssistContext, AssistId, Assists};

static ASSIST_NAME: &str = "change_lifetime_anon_to_named";
static ASSIST_LABEL: &str = "Give anonymous lifetime a name";

// Assist: change_lifetime_anon_to_named
//
// Change an anonymous lifetime to a named lifetime.
//
// ```
// impl Cursor<'_<|>> {
//     fn node(self) -> &SyntaxNode {
//         match self {
//             Cursor::Replace(node) | Cursor::Before(node) => node,
//         }
//     }
// }
// ```
// ->
// ```
// impl<'a> Cursor<'a> {
//     fn node(self) -> &SyntaxNode {
//         match self {
//             Cursor::Replace(node) | Cursor::Before(node) => node,
//         }
//     }
// }
// ```
// FIXME: How can we handle renaming any one of multiple anonymous lifetimes?
// FIXME: should also add support for the case fun(f: &Foo) -> &<|>Foo
pub(crate) fn change_lifetime_anon_to_named(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let lifetime_token = ctx
        .find_token_at_offset(SyntaxKind::LIFETIME)
        .filter(|lifetime| lifetime.text() == "'_")?;
    if let Some(fn_def) = lifetime_token.ancestors().find_map(ast::FnDef::cast) {
        generate_fn_def_assist(acc, &fn_def, lifetime_token.text_range())
    } else if let Some(impl_def) = lifetime_token.ancestors().find_map(ast::ImplDef::cast) {
        // only allow naming the last anonymous lifetime
        lifetime_token.next_token().filter(|tok| tok.kind() == SyntaxKind::R_ANGLE)?;
        generate_impl_def_assist(acc, &impl_def, lifetime_token.text_range())
    } else {
        None
    }
}

/// Generate the assist for the fn def case
fn generate_fn_def_assist(
    acc: &mut Assists,
    fn_def: &ast::FnDef,
    lifetime_loc: TextRange,
) -> Option<()> {
    let param_list: ast::ParamList = fn_def.param_list()?;
    let new_lifetime_param = generate_unique_lifetime_param_name(&fn_def.type_param_list())?;
    let end_of_fn_ident = fn_def.name()?.ident_token()?.text_range().end();
    let self_param =
        // use the self if it's a reference and has no explicit lifetime
        param_list.self_param().filter(|p| p.lifetime_token().is_none() && p.amp_token().is_some());
    // compute the location which implicitly has the same lifetime as the anonymous lifetime
    let loc_needing_lifetime = if let Some(self_param) = self_param {
        // if we have a self reference, use that
        Some(self_param.self_token()?.text_range().start())
    } else {
        // otherwise, if there's a single reference parameter without a named liftime, use that
        let fn_params_without_lifetime: Vec<_> = param_list
            .params()
            .filter_map(|param| match param.ascribed_type() {
                Some(ast::TypeRef::ReferenceType(ascribed_type))
                    if ascribed_type.lifetime_token() == None =>
                {
                    Some(ascribed_type.amp_token()?.text_range().end())
                }
                _ => None,
            })
            .collect();
        match fn_params_without_lifetime.len() {
            1 => Some(fn_params_without_lifetime.into_iter().nth(0)?),
            0 => None,
            // multiple unnnamed is invalid. assist is not applicable
            _ => return None,
        }
    };
    acc.add(AssistId(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |builder| {
        add_lifetime_param(fn_def, builder, end_of_fn_ident, new_lifetime_param);
        builder.replace(lifetime_loc, format!("'{}", new_lifetime_param));
        loc_needing_lifetime.map(|loc| builder.insert(loc, format!("'{} ", new_lifetime_param)));
    })
}

/// Generate the assist for the impl def case
fn generate_impl_def_assist(
    acc: &mut Assists,
    impl_def: &ast::ImplDef,
    lifetime_loc: TextRange,
) -> Option<()> {
    let new_lifetime_param = generate_unique_lifetime_param_name(&impl_def.type_param_list())?;
    let end_of_impl_kw = impl_def.impl_token()?.text_range().end();
    acc.add(AssistId(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |builder| {
        add_lifetime_param(impl_def, builder, end_of_impl_kw, new_lifetime_param);
        builder.replace(lifetime_loc, format!("'{}", new_lifetime_param));
    })
}

/// Given a type parameter list, generate a unique lifetime parameter name
/// which is not in the list
fn generate_unique_lifetime_param_name(
    existing_type_param_list: &Option<ast::TypeParamList>,
) -> Option<char> {
    match existing_type_param_list {
        Some(type_params) => {
            let used_lifetime_params: FxHashSet<_> = type_params
                .lifetime_params()
                .map(|p| p.syntax().text().to_string()[1..].to_owned())
                .collect();
            (b'a'..=b'z').map(char::from).find(|c| !used_lifetime_params.contains(&c.to_string()))
        }
        None => Some('a'),
    }
}

/// Add the lifetime param to `builder`. If there are type parameters in `type_params_owner`, add it to the end. Otherwise
/// add new type params brackets with the lifetime parameter at `new_type_params_loc`.
fn add_lifetime_param<TypeParamsOwner: ast::TypeParamsOwner>(
    type_params_owner: &TypeParamsOwner,
    builder: &mut AssistBuilder,
    new_type_params_loc: TextSize,
    new_lifetime_param: char,
) {
    match type_params_owner.type_param_list() {
        // add the new lifetime parameter to an existing type param list
        Some(type_params) => {
            builder.insert(
                (u32::from(type_params.syntax().text_range().end()) - 1).into(),
                format!(", '{}", new_lifetime_param),
            );
        }
        // create a new type param list containing only the new lifetime parameter
        None => {
            builder.insert(new_type_params_loc, format!("<'{}>", new_lifetime_param));
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::tests::{check_assist, check_assist_not_applicable};

    #[test]
    fn test_example_case() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"impl Cursor<'_<|>> {
                fn node(self) -> &SyntaxNode {
                    match self {
                        Cursor::Replace(node) | Cursor::Before(node) => node,
                    }
                }
            }"#,
            r#"impl<'a> Cursor<'a> {
                fn node(self) -> &SyntaxNode {
                    match self {
                        Cursor::Replace(node) | Cursor::Before(node) => node,
                    }
                }
            }"#,
        );
    }

    #[test]
    fn test_example_case_simplified() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"impl Cursor<'_<|>> {"#,
            r#"impl<'a> Cursor<'a> {"#,
        );
    }

    #[test]
    fn test_example_case_cursor_after_tick() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"impl Cursor<'<|>_> {"#,
            r#"impl<'a> Cursor<'a> {"#,
        );
    }

    #[test]
    fn test_example_case_cursor_before_tick() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"impl Cursor<<|>'_> {"#,
            r#"impl<'a> Cursor<'a> {"#,
        );
    }

    #[test]
    fn test_not_applicable_cursor_position() {
        check_assist_not_applicable(change_lifetime_anon_to_named, r#"impl Cursor<'_><|> {"#);
        check_assist_not_applicable(change_lifetime_anon_to_named, r#"impl Cursor<|><'_> {"#);
    }

    #[test]
    fn test_not_applicable_lifetime_already_name() {
        check_assist_not_applicable(change_lifetime_anon_to_named, r#"impl Cursor<'a<|>> {"#);
        check_assist_not_applicable(
            change_lifetime_anon_to_named,
            r#"fn my_fun<'a>() -> X<'a<|>>"#,
        );
    }

    #[test]
    fn test_with_type_parameter() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"impl<T> Cursor<T, '_<|>>"#,
            r#"impl<T, 'a> Cursor<T, 'a>"#,
        );
    }

    #[test]
    fn test_with_existing_lifetime_name_conflict() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"impl<'a, 'b> Cursor<'a, 'b, '_<|>>"#,
            r#"impl<'a, 'b, 'c> Cursor<'a, 'b, 'c>"#,
        );
    }

    #[test]
    fn test_function_return_value_anon_lifetime_param() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"fn my_fun() -> X<'_<|>>"#,
            r#"fn my_fun<'a>() -> X<'a>"#,
        );
    }

    #[test]
    fn test_function_return_value_anon_reference_lifetime() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"fn my_fun() -> &'_<|> X"#,
            r#"fn my_fun<'a>() -> &'a X"#,
        );
    }

    #[test]
    fn test_function_param_anon_lifetime() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"fn my_fun(x: X<'_<|>>)"#,
            r#"fn my_fun<'a>(x: X<'a>)"#,
        );
    }

    #[test]
    fn test_function_add_lifetime_to_params() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"fn my_fun(f: &Foo) -> X<'_<|>>"#,
            r#"fn my_fun<'a>(f: &'a Foo) -> X<'a>"#,
        );
    }

    #[test]
    fn test_function_add_lifetime_to_params_in_presence_of_other_lifetime() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"fn my_fun<'other>(f: &Foo, b: &'other Bar) -> X<'_<|>>"#,
            r#"fn my_fun<'other, 'a>(f: &'a Foo, b: &'other Bar) -> X<'a>"#,
        );
    }

    #[test]
    fn test_function_not_applicable_without_self_and_multiple_unnamed_param_lifetimes() {
        // this is not permitted under lifetime elision rules
        check_assist_not_applicable(
            change_lifetime_anon_to_named,
            r#"fn my_fun(f: &Foo, b: &Bar) -> X<'_<|>>"#,
        );
    }

    #[test]
    fn test_function_add_lifetime_to_self_ref_param() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"fn my_fun<'other>(&self, f: &Foo, b: &'other Bar) -> X<'_<|>>"#,
            r#"fn my_fun<'other, 'a>(&'a self, f: &Foo, b: &'other Bar) -> X<'a>"#,
        );
    }

    #[test]
    fn test_function_add_lifetime_to_param_with_non_ref_self() {
        check_assist(
            change_lifetime_anon_to_named,
            r#"fn my_fun<'other>(self, f: &Foo, b: &'other Bar) -> X<'_<|>>"#,
            r#"fn my_fun<'other, 'a>(self, f: &'a Foo, b: &'other Bar) -> X<'a>"#,
        );
    }
}
<|endoftext|>


<commit_before>// edition:2018
#![warn(clippy::wrong_self_convention)]
#![allow(dead_code)]

fn main() {}

mod issue6983 {
    pub struct Thing;
    pub trait Trait {
        fn to_thing(&self) -> Thing;
    }

    impl Trait for u8 {
        // don't trigger, e.g. `ToString` from `std` requires `&self`
        fn to_thing(&self) -> Thing {
            Thing
        }
    }

    trait ToU64 {
        fn to_u64(self) -> u64;
    }

    struct FooNoCopy;
    // don't trigger
    impl ToU64 for FooNoCopy {
        fn to_u64(self) -> u64 {
            2
        }
    }
}

mod issue7032 {
    trait Foo {
        fn from_usize(x: usize) -> Self;
    }
    // don't trigger
    impl Foo for usize {
        fn from_usize(x: usize) -> Self {
            x
        }
    }
}

mod issue7179 {
    pub struct S(i32);

    impl S {
        // don't trigger (`s` is not `self`)
        pub fn from_be(s: Self) -> Self {
            S(i32::from_be(s.0))
        }

        // lint
        pub fn from_be_self(self) -> Self {
            S(i32::from_be(self.0))
        }
    }

    trait T {
        // don't trigger (`s` is not `self`)
        fn from_be(s: Self) -> Self;
        // lint
        fn from_be_self(self) -> Self;
    }

    trait Foo: Sized {
        fn as_byte_slice(slice: &[Self]) -> &[u8];
    }
}
<commit_msg>add 3414 test<commit_after>// edition:2018
#![warn(clippy::wrong_self_convention)]
#![allow(dead_code)]

fn main() {}

mod issue6983 {
    pub struct Thing;
    pub trait Trait {
        fn to_thing(&self) -> Thing;
    }

    impl Trait for u8 {
        // don't trigger, e.g. `ToString` from `std` requires `&self`
        fn to_thing(&self) -> Thing {
            Thing
        }
    }

    trait ToU64 {
        fn to_u64(self) -> u64;
    }

    struct FooNoCopy;
    // don't trigger
    impl ToU64 for FooNoCopy {
        fn to_u64(self) -> u64 {
            2
        }
    }
}

mod issue7032 {
    trait Foo {
        fn from_usize(x: usize) -> Self;
    }
    // don't trigger
    impl Foo for usize {
        fn from_usize(x: usize) -> Self {
            x
        }
    }
}

mod issue7179 {
    pub struct S(i32);

    impl S {
        // don't trigger (`s` is not `self`)
        pub fn from_be(s: Self) -> Self {
            S(i32::from_be(s.0))
        }

        // lint
        pub fn from_be_self(self) -> Self {
            S(i32::from_be(self.0))
        }
    }

    trait T {
        // don't trigger (`s` is not `self`)
        fn from_be(s: Self) -> Self;
        // lint
        fn from_be_self(self) -> Self;
    }

    trait Foo: Sized {
        fn as_byte_slice(slice: &[Self]) -> &[u8];
    }
}

mod issue3414 {
    struct CellLikeThing<T>(T);

    impl<T> CellLikeThing<T> {
        // don't trigger
        fn into_inner(this: Self) -> T {
            this.0
        }
    }

    impl<T> std::ops::Deref for CellLikeThing<T> {
        type Target = T;

        fn deref(&self) -> &T {
            &self.0
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;

use salsa::Database;
use ra_db::{FilesDatabase, CrateGraph};
use relative_path::RelativePath;
use test_utils::assert_eq_text;

use crate::{
    self as hir,
    db::HirDatabase,
    mock::MockDatabase,
};

fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) {
    let (db, pos) = MockDatabase::with_position(fixture);
    let source_root = db.file_source_root(pos.file_id);
    let module = hir::source_binder::module_from_position(&db, pos)
        .unwrap()
        .unwrap();
    let module_id = module.module_id;
    (db.item_map(source_root).unwrap(), module_id)
}

fn check_module_item_map(map: &hir::ItemMap, module_id: hir::ModuleId, expected: &str) {
    let mut lines = map.per_module[&module_id]
        .items
        .iter()
        .map(|(name, res)| format!("{}: {}", name, dump_resolution(res)))
        .collect::<Vec<_>>();
    lines.sort();
    let actual = lines.join("\n");
    let expected = expected
        .trim()
        .lines()
        .map(|it| it.trim())
        .collect::<Vec<_>>()
        .join("\n");
    assert_eq_text!(&actual, &expected);

    fn dump_resolution(resolution: &hir::Resolution) -> &'static str {
        match (
            resolution.def_id.types.is_some(),
            resolution.def_id.values.is_some(),
        ) {
            (true, true) => "t v",
            (true, false) => "t",
            (false, true) => "v",
            (false, false) => "_",
        }
    }
}

#[test]
fn item_map_smoke_test() {
    let (item_map, module_id) = item_map(
        "
        //- /lib.rs
        mod foo;

        use crate::foo::bar::Baz;
        <|>

        //- /foo/mod.rs
        pub mod bar;

        //- /foo/bar.rs
        pub struct Baz;
    ",
    );
    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t v
            foo: t
        ",
    );
}

#[test]
fn item_map_using_self() {
    let (item_map, module_id) = item_map(
        "
            //- /lib.rs
            mod foo;
            use crate::foo::bar::Baz::{self};
            <|>
            //- /foo/mod.rs
            pub mod bar;
            //- /foo/bar.rs
            pub struct Baz;
        ",
    );
    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t v
            foo: t
        ",
    );
}

#[test]
fn item_map_across_crates() {
    let (mut db, sr) = MockDatabase::with_files(
        "
        //- /main.rs
        use test_crate::Baz;

        //- /lib.rs
        pub struct Baz;
    ",
    );
    let main_id = sr.files[RelativePath::new("/main.rs")];
    let lib_id = sr.files[RelativePath::new("/lib.rs")];

    let mut crate_graph = CrateGraph::default();
    let main_crate = crate_graph.add_crate_root(main_id);
    let lib_crate = crate_graph.add_crate_root(lib_id);
    crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate);

    db.set_crate_graph(crate_graph);

    let source_root = db.file_source_root(main_id);
    let module = hir::source_binder::module_from_file_id(&db, main_id)
        .unwrap()
        .unwrap();
    let module_id = module.module_id;
    let item_map = db.item_map(source_root).unwrap();

    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t v
            test_crate: t
        ",
    );
}

#[test]
fn typing_inside_a_function_should_not_invalidate_item_map() {
    let (mut db, pos) = MockDatabase::with_position(
        "
        //- /lib.rs
        mod foo;<|>

        use crate::foo::bar::Baz;

        fn foo() -> i32 {
            1 + 1
        }
        //- /foo/mod.rs
        pub mod bar;

        //- /foo/bar.rs
        pub struct Baz;
    ",
    );
    let source_root = db.file_source_root(pos.file_id);
    {
        let events = db.log_executed(|| {
            db.item_map(source_root).unwrap();
        });
        assert!(format!("{:?}", events).contains("item_map"))
    }

    let new_text = "
        mod foo;

        use crate::foo::bar::Baz;

        fn foo() -> i32 { 92 }
    "
    .to_string();

    db.query_mut(ra_db::FileTextQuery)
        .set(pos.file_id, Arc::new(new_text));

    {
        let events = db.log_executed(|| {
            db.item_map(source_root).unwrap();
        });
        assert!(
            !format!("{:?}", events).contains("_item_map"),
            "{:#?}",
            events
        )
    }
}
<commit_msg>add tests for macro generated items<commit_after>use std::sync::Arc;

use salsa::Database;
use ra_db::{FilesDatabase, CrateGraph};
use relative_path::RelativePath;
use test_utils::assert_eq_text;

use crate::{
    self as hir,
    db::HirDatabase,
    mock::MockDatabase,
};

fn item_map(fixture: &str) -> (Arc<hir::ItemMap>, hir::ModuleId) {
    let (db, pos) = MockDatabase::with_position(fixture);
    let source_root = db.file_source_root(pos.file_id);
    let module = hir::source_binder::module_from_position(&db, pos)
        .unwrap()
        .unwrap();
    let module_id = module.module_id;
    (db.item_map(source_root).unwrap(), module_id)
}

fn check_module_item_map(map: &hir::ItemMap, module_id: hir::ModuleId, expected: &str) {
    let mut lines = map.per_module[&module_id]
        .items
        .iter()
        .map(|(name, res)| format!("{}: {}", name, dump_resolution(res)))
        .collect::<Vec<_>>();
    lines.sort();
    let actual = lines.join("\n");
    let expected = expected
        .trim()
        .lines()
        .map(|it| it.trim())
        .collect::<Vec<_>>()
        .join("\n");
    assert_eq_text!(&actual, &expected);

    fn dump_resolution(resolution: &hir::Resolution) -> &'static str {
        match (
            resolution.def_id.types.is_some(),
            resolution.def_id.values.is_some(),
        ) {
            (true, true) => "t v",
            (true, false) => "t",
            (false, true) => "v",
            (false, false) => "_",
        }
    }
}

#[test]
fn item_map_smoke_test() {
    let (item_map, module_id) = item_map(
        "
        //- /lib.rs
        mod foo;

        use crate::foo::bar::Baz;
        <|>

        //- /foo/mod.rs
        pub mod bar;

        //- /foo/bar.rs
        pub struct Baz;
    ",
    );
    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t v
            foo: t
        ",
    );
}

#[test]
fn item_map_contains_items_from_expansions() {
    let (item_map, module_id) = item_map(
        "
        //- /lib.rs
        mod foo;

        use crate::foo::bar::Baz;
        <|>

        //- /foo/mod.rs
        pub mod bar;

        //- /foo/bar.rs
        salsa::query_group! {
            trait Baz {}
        }
    ",
    );
    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t
            foo: t
        ",
    );
}

#[test]
fn item_map_using_self() {
    let (item_map, module_id) = item_map(
        "
            //- /lib.rs
            mod foo;
            use crate::foo::bar::Baz::{self};
            <|>
            //- /foo/mod.rs
            pub mod bar;
            //- /foo/bar.rs
            pub struct Baz;
        ",
    );
    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t v
            foo: t
        ",
    );
}

#[test]
fn item_map_across_crates() {
    let (mut db, sr) = MockDatabase::with_files(
        "
        //- /main.rs
        use test_crate::Baz;

        //- /lib.rs
        pub struct Baz;
    ",
    );
    let main_id = sr.files[RelativePath::new("/main.rs")];
    let lib_id = sr.files[RelativePath::new("/lib.rs")];

    let mut crate_graph = CrateGraph::default();
    let main_crate = crate_graph.add_crate_root(main_id);
    let lib_crate = crate_graph.add_crate_root(lib_id);
    crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate);

    db.set_crate_graph(crate_graph);

    let source_root = db.file_source_root(main_id);
    let module = hir::source_binder::module_from_file_id(&db, main_id)
        .unwrap()
        .unwrap();
    let module_id = module.module_id;
    let item_map = db.item_map(source_root).unwrap();

    check_module_item_map(
        &item_map,
        module_id,
        "
            Baz: t v
            test_crate: t
        ",
    );
}

#[test]
fn typing_inside_a_function_should_not_invalidate_item_map() {
    let (mut db, pos) = MockDatabase::with_position(
        "
        //- /lib.rs
        mod foo;

        use crate::foo::bar::Baz;

        //- /foo/mod.rs
        pub mod bar;

        //- /foo/bar.rs
        <|>
        salsa::query_group! {
            trait Baz {
                fn foo() -> i32 { 1 + 1 }
            }
        }
        ",
    );
    let source_root = db.file_source_root(pos.file_id);
    {
        let events = db.log_executed(|| {
            db.item_map(source_root).unwrap();
        });
        assert!(format!("{:?}", events).contains("item_map"))
    }

    let new_text = "
        salsa::query_group! {
            trait Baz {
                fn foo() -> i32 { 92 }
            }
        }
    "
    .to_string();

    db.query_mut(ra_db::FileTextQuery)
        .set(pos.file_id, Arc::new(new_text));

    {
        let events = db.log_executed(|| {
            db.item_map(source_root).unwrap();
        });
        assert!(
            !format!("{:?}", events).contains("item_map"),
            "{:#?}",
            events
        )
    }
}

#[test]
fn typing_inside_a_function_inside_a_macro_should_not_invalidate_item_map() {
    let (mut db, pos) = MockDatabase::with_position(
        "
        //- /lib.rs
        mod foo;<|>

        use crate::foo::bar::Baz;

        fn foo() -> i32 {
            1 + 1
        }
        //- /foo/mod.rs
        pub mod bar;

        //- /foo/bar.rs
        pub struct Baz;
    ",
    );
    let source_root = db.file_source_root(pos.file_id);
    {
        let events = db.log_executed(|| {
            db.item_map(source_root).unwrap();
        });
        assert!(format!("{:?}", events).contains("item_map"))
    }

    let new_text = "
        mod foo;

        use crate::foo::bar::Baz;

        fn foo() -> i32 { 92 }
    "
    .to_string();

    db.query_mut(ra_db::FileTextQuery)
        .set(pos.file_id, Arc::new(new_text));

    {
        let events = db.log_executed(|| {
            db.item_map(source_root).unwrap();
        });
        assert!(
            !format!("{:?}", events).contains("item_map"),
            "{:#?}",
            events
        )
    }
}
<|endoftext|>