<commit_before>use std::path::Path;
use git2::Repository;
use git2::ObjectType;
use git2::BranchType;
use rand::Rng;
use termion::color;
use rand;

use yaml_rust::yaml::Hash;
use yaml_rust::{Yaml, YamlEmitter};

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct State {
    pub task: String,
    pub focus: String,
    pub filter: Option<Filter>,
    pub message: String,
    pub include: Vec<String>,
    pub property: Vec<Property>,
    pub diff: Vec<String>,
    pub save_update: Option<String>,
    pub new_task: Option<String>,
    pub dragged: Option<String>
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Property {
    pub name: String,
    pub value: String
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Filter {
    pub name: String,
    pub value: String
}

pub enum StateError {
}

impl State {

    pub fn blank() -> State {
        State {
            task: String::from("master"),
            focus: String::new(),
            message: String::new(),
            include: vec![],
            diff: vec![],
            property: vec![],
            save_update: None,
            new_task: None,
            filter: None,
            dragged: None
        }
    }

    pub fn reset(&mut self) {
        self.message = String::new();
        self.property = vec![];
        self.include = vec![];
        self.save_update = None;
        self.new_task = None;
    }

    pub fn reset_with_status(&mut self) {
        self.message = String::new();
        self.property = self.property.iter().filter_map(|p| if p.name == "Status" { Some(p.clone()) } else { None }).collect();
        self.include = vec![];
        self.save_update = None;
        self.new_task = None;
    }

    pub fn apply(&mut self, mut last_state: Option<State>, rng: &mut rand::ThreadRng) -> Result<State, StateError> {
        let new_last_state = self.clone();
        if let Some(ref mut last) = last_state {
            println!("{}{:?}{}", color::Fg(color::LightBlack), last, color::Fg(color::Reset));
            println!("{:?}", self);
            println!("▶ ");
            if self.task != last.task {
                let repo = Repository::discover(".").unwrap();
                println!("  {}Task changing{}  {} => {}", color::Fg(color::LightYellow), color::Fg(color::Reset), last.task, self.task);
                if self.dragged.is_some() {
                    println!("  {}Saving last state due to dragging{}", color::Fg(color::LightGreen), color::Fg(color::Reset));
                    last.save_update(repo, rng);
                    self.reset_with_status();
                } else {
                    let switching_to_task = self.task.clone();
                    self.task = last.task.clone();
                    self.save_update(repo, rng);
                    self.task = switching_to_task;
                    self.reset();
                }
            } else {
                println!("  {}Updating task {}{}", color::Fg(color::LightGreen), self.task, color::Fg(color::Reset));
                self.apply_index();

                if self.save_update.is_some() || self.new_task.is_some() {
                    let repo = Repository::discover(".").unwrap();
                    self.save_update(repo, rng);
                }
            }
        }
        Ok(new_last_state)
    }

    fn save_update(&mut self, repo: Repository, rng: &mut rand::ThreadRng) {
        let branch = repo.find_branch(&self.task, BranchType::Local);
        let head = match branch {
            Ok(branch) => branch.into_reference(),
            _ => repo.head().unwrap()
        };
        let commit = head.peel(ObjectType::Commit).unwrap();
        let mut index = repo.index().unwrap();

        let author = repo.signature().unwrap();
        let mut yaml = String::new();
        {
            // Constructing the properties YAML
            let mut tasks = Hash::new();
            let mut properties = Hash::new();
            let mut emitter = YamlEmitter::new(&mut yaml);
            for property in self.property.clone() {
                properties.insert(Yaml::String(property.name), Yaml::String(property.value));
            }
            tasks.insert(Yaml::String(String::from(head.shorthand().unwrap_or("master"))), Yaml::Hash(properties));
            emitter.dump(&Yaml::Hash(tasks)).unwrap();
        }
        let message = format!("{}\n{}", self.message, yaml);

        index.read(false).unwrap();
        let tree_oid = index.write_tree().unwrap();
        let tree = repo.find_tree(tree_oid).unwrap();
        repo.commit(Some(&head.name().unwrap_or("HEAD")), &author, &author, &message, &tree, &[&commit.as_commit().unwrap()]).unwrap();
        println!("  {}Saved changes to {}{} {:?}", color::Fg(color::LightRed), self.task, color::Fg(color::Reset), self);
        if self.new_task.is_some() {
            let num = rng.gen::<u16>();
            let new_task = format!("{:X}", num);
            println!("  {}Creating task {}{}", color::Fg(color::LightBlue), new_task, color::Fg(color::Reset));
            if let Ok(master_branch) = repo.find_branch("master", BranchType::Local) {
                let master = master_branch.into_reference();
                let commit_obj = master.peel(ObjectType::Commit).unwrap();
                let commit = commit_obj.as_commit().unwrap();
                repo.branch(&new_task, &commit, false).unwrap();
                self.task = new_task;
                self.reset();
            }
        }
    }

    fn apply_index(&self) {
        let repo = Repository::discover(".").unwrap();
        let branch = repo.find_branch(&self.task, BranchType::Local);
        let head = match branch {
            Ok(branch) => branch.into_reference(),
            _ => repo.head().unwrap()
        };
        let commit = head.peel(ObjectType::Commit).unwrap();
        let mut index = repo.index().unwrap();

        // apply git index changes only if task is the working directory
        if self.task == repo.head().unwrap().shorthand().unwrap() {
            let to_remove = index.iter().fold(vec![], |mut acc, entry| {
                let entry_path = String::from_utf8_lossy(entry.path.as_ref());
                match self.include.iter().find(|i| i.as_ref() == entry_path) {
                    None => acc.push(entry_path.into_owned()),
                    _ => {}
                };
                acc
            });
            repo.reset_default(Some(&commit), to_remove.iter()).unwrap();
            for change in &self.include {
                let path = Path::new(&change);
                index.add_path(path).unwrap();
            }
            index.write().unwrap();
        }
    }

}
<commit_msg>Reset after updating task. --- master:    Description: ""   Developer: Jaden Carver   Estimate: "50"   Manager: Jaden Carver   Status: Sprint<commit_after>use std::path::Path;
use git2::Repository;
use git2::ObjectType;
use git2::BranchType;
use rand::Rng;
use termion::color;
use rand;

use yaml_rust::yaml::Hash;
use yaml_rust::{Yaml, YamlEmitter};

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct State {
    pub task: String,
    pub focus: String,
    pub filter: Option<Filter>,
    pub message: String,
    pub include: Vec<String>,
    pub property: Vec<Property>,
    pub diff: Vec<String>,
    pub save_update: Option<String>,
    pub new_task: Option<String>,
    pub dragged: Option<String>
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Property {
    pub name: String,
    pub value: String
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Filter {
    pub name: String,
    pub value: String
}

pub enum StateError {
}

impl State {

    pub fn blank() -> State {
        State {
            task: String::from("master"),
            focus: String::new(),
            message: String::new(),
            include: vec![],
            diff: vec![],
            property: vec![],
            save_update: None,
            new_task: None,
            filter: None,
            dragged: None
        }
    }

    pub fn reset(&mut self) {
        self.message = String::new();
        self.property = vec![];
        self.include = vec![];
        self.save_update = None;
        self.new_task = None;
    }

    pub fn reset_with_status(&mut self) {
        self.message = String::new();
        self.property = self.property.iter().filter_map(|p| if p.name == "Status" { Some(p.clone()) } else { None }).collect();
        self.include = vec![];
        self.save_update = None;
        self.new_task = None;
    }

    pub fn apply(&mut self, mut last_state: Option<State>, rng: &mut rand::ThreadRng) -> Result<State, StateError> {
        let new_last_state = self.clone();
        if let Some(ref mut last) = last_state {
            println!("{}{:?}{}", color::Fg(color::LightBlack), last, color::Fg(color::Reset));
            println!("{:?}", self);
            println!("▶ ");
            if self.task != last.task {
                let repo = Repository::discover(".").unwrap();
                println!("  {}Task changing{}  {} => {}", color::Fg(color::LightYellow), color::Fg(color::Reset), last.task, self.task);
                if self.dragged.is_some() {
                    println!("  {}Saving last state due to dragging{}", color::Fg(color::LightGreen), color::Fg(color::Reset));
                    last.save_update(repo, rng);
                    self.reset_with_status();
                } else {
                    let switching_to_task = self.task.clone();
                    self.task = last.task.clone();
                    self.save_update(repo, rng);
                    self.task = switching_to_task;
                    self.reset();
                }
            } else {
                println!("  {}Updating task {}{}", color::Fg(color::LightGreen), self.task, color::Fg(color::Reset));
                self.apply_index();

                if self.save_update.is_some() || self.new_task.is_some() {
                    let repo = Repository::discover(".").unwrap();
                    self.save_update(repo, rng);
                    self.reset();
                }
            }
        }
        Ok(new_last_state)
    }

    fn save_update(&mut self, repo: Repository, rng: &mut rand::ThreadRng) {
        let branch = repo.find_branch(&self.task, BranchType::Local);
        let head = match branch {
            Ok(branch) => branch.into_reference(),
            _ => repo.head().unwrap()
        };
        let commit = head.peel(ObjectType::Commit).unwrap();
        let mut index = repo.index().unwrap();

        let author = repo.signature().unwrap();
        let mut yaml = String::new();
        {
            // Constructing the properties YAML
            let mut tasks = Hash::new();
            let mut properties = Hash::new();
            let mut emitter = YamlEmitter::new(&mut yaml);
            for property in self.property.clone() {
                properties.insert(Yaml::String(property.name), Yaml::String(property.value));
            }
            tasks.insert(Yaml::String(String::from(head.shorthand().unwrap_or("master"))), Yaml::Hash(properties));
            emitter.dump(&Yaml::Hash(tasks)).unwrap();
        }
        let message = format!("{}\n{}", self.message, yaml);

        index.read(false).unwrap();
        let tree_oid = index.write_tree().unwrap();
        let tree = repo.find_tree(tree_oid).unwrap();
        repo.commit(Some(&head.name().unwrap_or("HEAD")), &author, &author, &message, &tree, &[&commit.as_commit().unwrap()]).unwrap();
        println!("  {}Saved changes to {}{} {:?}", color::Fg(color::LightRed), self.task, color::Fg(color::Reset), self);
        if self.new_task.is_some() {
            let num = rng.gen::<u16>();
            let new_task = format!("{:X}", num);
            println!("  {}Creating task {}{}", color::Fg(color::LightBlue), new_task, color::Fg(color::Reset));
            if let Ok(master_branch) = repo.find_branch("master", BranchType::Local) {
                let master = master_branch.into_reference();
                let commit_obj = master.peel(ObjectType::Commit).unwrap();
                let commit = commit_obj.as_commit().unwrap();
                repo.branch(&new_task, &commit, false).unwrap();
                self.task = new_task;
                self.reset();
            }
        }
    }

    fn apply_index(&self) {
        let repo = Repository::discover(".").unwrap();
        let branch = repo.find_branch(&self.task, BranchType::Local);
        let head = match branch {
            Ok(branch) => branch.into_reference(),
            _ => repo.head().unwrap()
        };
        let commit = head.peel(ObjectType::Commit).unwrap();
        let mut index = repo.index().unwrap();

        // apply git index changes only if task is the working directory
        if self.task == repo.head().unwrap().shorthand().unwrap() {
            let to_remove = index.iter().fold(vec![], |mut acc, entry| {
                let entry_path = String::from_utf8_lossy(entry.path.as_ref());
                match self.include.iter().find(|i| i.as_ref() == entry_path) {
                    None => acc.push(entry_path.into_owned()),
                    _ => {}
                };
                acc
            });
            repo.reset_default(Some(&commit), to_remove.iter()).unwrap();
            for change in &self.include {
                let path = Path::new(&change);
                index.add_path(path).unwrap();
            }
            index.write().unwrap();
        }
    }

}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::io;
use std::rc::Rc;
use mio::{Event, PollOpt, Ready};
use mio::tcp::TcpListener;

use super::client::Client;
use super::selector::Selector;
use super::observer::DeathListener;

const TAG: &'static str = "TunnelServer";

pub struct TunnelServer {
    clients: Vec<Rc<RefCell<Client>>>,
    tcp_listener: TcpListener,
    next_client_id: u32,
}

impl TunnelServer {
    pub fn new(port: u16, selector: &mut Selector) -> io::Result<Rc<RefCell<Self>>> {
        let tcp_listener = TunnelServer::start_socket(port)?;
        let rc = Rc::new(RefCell::new(Self {
            clients: Vec::new(),
            tcp_listener: tcp_listener,
            next_client_id: 0,
        }));
        let rc_clone = rc.clone();
        let handler = move |selector: &mut Selector, ready| {
            let mut self_ref = rc_clone.borrow_mut();
            self_ref.on_ready(&rc_clone, selector, ready);
        };
        selector.register(&rc.borrow().tcp_listener, handler, Ready::readable(), PollOpt::edge())?;
        Ok(rc)
    }

    fn start_socket(port: u16) -> io::Result<TcpListener> {
        let localhost = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
        let addr = SocketAddr::new(localhost, port);
        let server = TcpListener::bind(&addr)?;
        Ok(server)
    }

    fn accept_client(&mut self, self_rc: &Rc<RefCell<Self>>, selector: &mut Selector) -> io::Result<()> {
        let (stream, _) = self.tcp_listener.accept()?;
        let client_id = self.next_client_id;
        self.next_client_id += 1;
        /*let on_client_death = move |target| {
            //self_rc.clone();
        };*/
        struct L;
        impl DeathListener<Client> for L {
            fn on_death(&self, target: &Client) {
            }
        }
        let on_client_death = L;
        let client = Client::new(client_id, selector, stream, on_client_death)?;
        self.clients.push(client);
        info!(target: TAG, "Client #{} connected", client_id);
        Ok(())
    }

    fn on_ready(&mut self, self_rc: &Rc<RefCell<Self>>, selector: &mut Selector, _: Event) {
        if let Err(err) = self.accept_client(self_rc, selector) {
            error!(target: TAG, "Cannot accept client: {}", err);
        }
    }
}
<commit_msg>Use closure for on_client_death<commit_after>use std::cell::RefCell;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::io;
use std::rc::Rc;
use mio::{Event, PollOpt, Ready};
use mio::tcp::TcpListener;

use super::client::Client;
use super::selector::Selector;
use super::observer::DeathListener;

const TAG: &'static str = "TunnelServer";

pub struct TunnelServer {
    clients: Vec<Rc<RefCell<Client>>>,
    tcp_listener: TcpListener,
    next_client_id: u32,
}

impl TunnelServer {
    pub fn new(port: u16, selector: &mut Selector) -> io::Result<Rc<RefCell<Self>>> {
        let tcp_listener = TunnelServer::start_socket(port)?;
        let rc = Rc::new(RefCell::new(Self {
            clients: Vec::new(),
            tcp_listener: tcp_listener,
            next_client_id: 0,
        }));
        let rc_clone = rc.clone();
        let handler = move |selector: &mut Selector, ready| {
            let mut self_ref = rc_clone.borrow_mut();
            self_ref.on_ready(&rc_clone, selector, ready);
        };
        selector.register(&rc.borrow().tcp_listener, handler, Ready::readable(), PollOpt::edge())?;
        Ok(rc)
    }

    fn start_socket(port: u16) -> io::Result<TcpListener> {
        let localhost = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
        let addr = SocketAddr::new(localhost, port);
        let server = TcpListener::bind(&addr)?;
        Ok(server)
    }

    fn accept_client(&mut self, self_rc: &Rc<RefCell<Self>>, selector: &mut Selector) -> io::Result<()> {
        let (stream, _) = self.tcp_listener.accept()?;
        let client_id = self.next_client_id;
        self.next_client_id += 1;
        let weak = Rc::downgrade(self_rc);
        let on_client_death = move |target: &Client| {
            if let Some(rc) = weak.upgrade() {
                let tunnel_server = rc.borrow_mut();
                // TODO remove client from the list
            }
        };
        let client = Client::new(client_id, selector, stream, on_client_death)?;
        self.clients.push(client);
        info!(target: TAG, "Client #{} connected", client_id);
        Ok(())
    }

    fn on_ready(&mut self, self_rc: &Rc<RefCell<Self>>, selector: &mut Selector, _: Event) {
        if let Err(err) = self.accept_client(self_rc, selector) {
            error!(target: TAG, "Cannot accept client: {}", err);
        }
    }
}
<|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 {
        if let Some(response_data) = response {
            panic!(response_data);
        }
        BuilderEvent::Incomplete
        // 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 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>Restore overlay handling functionality<commit_after>use std::path::PathBuf;

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 = PathBuf::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 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>//!
//! This module provides syscall definitions and the necessary resources to parse incoming
//! syscalls

extern crate syscall;

pub use self::syscall::{data, error, flag, io, number, ptrace_event, scheme};

pub use self::driver::*;
pub use self::fs::*;
pub use self::futex::futex;
pub use self::privilege::*;
pub use self::process::*;
pub use self::time::*;
pub use self::validate::*;

use self::data::{SigAction, TimeSpec};
use self::error::{Error, Result, ENOSYS};
use self::flag::{CloneFlags, MapFlags, PhysmapFlags, WaitFlags};
use self::number::*;

use crate::context::ContextId;
use crate::interrupt::InterruptStack;
use crate::scheme::{FileHandle, SchemeNamespace};

/// Debug
pub mod debug;

/// Driver syscalls
pub mod driver;

/// Filesystem syscalls
pub mod fs;

/// Fast userspace mutex
pub mod futex;

/// Privilege syscalls
pub mod privilege;

/// Process syscalls
pub mod process;

/// Time syscalls
pub mod time;

/// Validate input
pub mod validate;

/// This function is the syscall handler of the kernel, it is composed of an inner function that returns a `Result<usize>`. After the inner function runs, the syscall
/// function calls [`Error::mux`] on it.
pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: usize, stack: &mut InterruptStack) -> usize {
    #[inline(always)]
    fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: usize, stack: &mut InterruptStack) -> Result<usize> {
        //SYS_* is declared in kernel/syscall/src/number.rs
        match a & SYS_CLASS {
            SYS_CLASS_FILE => {
                let fd = FileHandle::from(b);
                match a & SYS_ARG {
                    SYS_ARG_SLICE => file_op_slice(a, fd, validate_slice(c as *const u8, d)?),
                    SYS_ARG_MSLICE => file_op_mut_slice(a, fd, validate_slice_mut(c as *mut u8, d)?),
                    _ => match a {
                        SYS_CLOSE => close(fd),
                        SYS_DUP => dup(fd, validate_slice(c as *const u8, d)?).map(FileHandle::into),
                        SYS_DUP2 => dup2(fd, FileHandle::from(c), validate_slice(d as *const u8, e)?).map(FileHandle::into),
                        SYS_FCNTL => fcntl(fd, c, d),
                        SYS_FEXEC => fexec(fd, validate_slice(c as *const [usize; 2], d)?, validate_slice(e as *const [usize; 2], f)?),
                        SYS_FRENAME => frename(fd, validate_slice(c as *const u8, d)?),
                        SYS_FUNMAP => funmap(b),
                        _ => file_op(a, fd, c, d)
                    }
                }
            },
            SYS_CLASS_PATH => match a {
                SYS_OPEN => open(validate_slice(b as *const u8, c)?, d).map(FileHandle::into),
                SYS_CHMOD => chmod(validate_slice(b as *const u8, c)?, d as u16),
                SYS_RMDIR => rmdir(validate_slice(b as *const u8, c)?),
                SYS_UNLINK => unlink(validate_slice(b as *const u8, c)?),
                _ => Err(Error::new(ENOSYS))
            },
            _ => match a {
                SYS_YIELD => sched_yield(),
                SYS_NANOSLEEP => nanosleep(
                    validate_slice(b as *const TimeSpec, 1).map(|req| &req[0])?,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(c as *mut TimeSpec, 1).map(|rem| &mut rem[0])?)
                    }
                ),
                SYS_CLOCK_GETTIME => clock_gettime(b, validate_slice_mut(c as *mut TimeSpec, 1).map(|time| &mut time[0])?),
                SYS_FUTEX => futex(validate_slice_mut(b as *mut i32, 1).map(|uaddr| &mut uaddr[0])?, c, d as i32, e, f as *mut i32),
                SYS_BRK => brk(b),
                SYS_GETPID => getpid().map(ContextId::into),
                SYS_GETPGID => getpgid(ContextId::from(b)).map(ContextId::into),
                SYS_GETPPID => getppid().map(ContextId::into),
                SYS_CLONE => {
                    let b = CloneFlags::from_bits_truncate(b);
                    let old_rsp = stack.iret.rsp;
                    if b.contains(flag::CLONE_STACK) {
                        stack.iret.rsp = c;
                    }
                    let ret = clone(b, bp).map(ContextId::into);
                    stack.iret.rsp = old_rsp;
                    ret
                },
                SYS_EXIT => exit((b & 0xFF) << 8),
                SYS_KILL => kill(ContextId::from(b), c),
                SYS_WAITPID => waitpid(ContextId::from(b), c, WaitFlags::from_bits_truncate(d)).map(ContextId::into),
                SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?),
                SYS_IOPL => iopl(b, stack),
                SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?),
                SYS_GETEGID => getegid(),
                SYS_GETENS => getens(),
                SYS_GETEUID => geteuid(),
                SYS_GETGID => getgid(),
                SYS_GETNS => getns(),
                SYS_GETUID => getuid(),
                SYS_MPROTECT => mprotect(b, c, MapFlags::from_bits_truncate(d)),
                SYS_MKNS => mkns(validate_slice(b as *const [usize; 2], c)?),
                SYS_SETPGID => setpgid(ContextId::from(b), ContextId::from(c)),
                SYS_SETREUID => setreuid(b as u32, c as u32),
                SYS_SETRENS => setrens(SchemeNamespace::from(b), SchemeNamespace::from(c)),
                SYS_SETREGID => setregid(b as u32, c as u32),
                SYS_SIGACTION => sigaction(
                    b,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice(c as *const SigAction, 1).map(|act| &act[0])?)
                    },
                    if d == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(d as *mut SigAction, 1).map(|oldact| &mut oldact[0])?)
                    },
                    e
                ),
                SYS_SIGPROCMASK => sigprocmask(
                    b,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice(c as *const [u64; 2], 1).map(|s| &s[0])?)
                    },
                    if d == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(d as *mut [u64; 2], 1).map(|s| &mut s[0])?)
                    }
                ),
                SYS_SIGRETURN => sigreturn(),
                SYS_PIPE2 => pipe2(validate_slice_mut(b as *mut usize, 2)?, c),
                SYS_PHYSALLOC => physalloc(b),
                SYS_PHYSALLOC3 => physalloc3(b, c, &mut validate_slice_mut(d as *mut usize, 1)?[0]),
                SYS_PHYSFREE => physfree(b, c),
                SYS_PHYSMAP => physmap(b, c, PhysmapFlags::from_bits_truncate(d)),
                SYS_PHYSUNMAP => physunmap(b),
                SYS_UMASK => umask(b),
                SYS_VIRTTOPHYS => virttophys(b),
                _ => Err(Error::new(ENOSYS))
            }
        }
    }

    let debug = {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            let name_raw = context.name.lock();
            let name = unsafe { core::str::from_utf8_unchecked(&name_raw) };
            if name == "file:/lib/ld64.so.1" || name == "file:/bin/ld" {
                true
            } else {
                false
            }
        } else {
            false
        }
    };

    if debug {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            print!("{} ({}): ", unsafe { core::str::from_utf8_unchecked(&context.name.lock()) }, context.id.into());
        }

        println!("{}", debug::format_call(a, b, c, d, e, f));
    }

    // The next lines set the current syscall in the context struct, then once the inner() function
    // completes, we set the current syscall to none.
    //
    // When the code below falls out of scope it will release the lock
    // see the spin crate for details
    {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let mut context = context_lock.write();
            context.syscall = Some((a, b, c, d, e, f));
        }
    }

    let result = inner(a, b, c, d, e, f, bp, stack);

    {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let mut context = context_lock.write();
            context.syscall = None;
        }
    }

    if debug {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            print!("{} ({}): ", unsafe { core::str::from_utf8_unchecked(&context.name.lock()) }, context.id.into());
        }

        print!("{} = ", debug::format_call(a, b, c, d, e, f));

        match result {
            Ok(ref ok) => {
                println!("Ok({} ({:#X}))", ok, ok);
            },
            Err(ref err) => {
                println!("Err({} ({:#X}))", err, err.errno);
            }
        }
    }

    // errormux turns Result<usize> into -errno
    Error::mux(result)
}
<commit_msg>Reverse mod/syscall.rs<commit_after>//!
//! This module provides syscall definitions and the necessary resources to parse incoming
//! syscalls

extern crate syscall;

pub use self::syscall::{data, error, flag, io, number, ptrace_event, scheme};

pub use self::driver::*;
pub use self::fs::*;
pub use self::futex::futex;
pub use self::privilege::*;
pub use self::process::*;
pub use self::time::*;
pub use self::validate::*;

use self::data::{SigAction, TimeSpec};
use self::error::{Error, Result, ENOSYS};
use self::flag::{CloneFlags, MapFlags, PhysmapFlags, WaitFlags};
use self::number::*;

use crate::context::ContextId;
use crate::interrupt::InterruptStack;
use crate::scheme::{FileHandle, SchemeNamespace};

/// Debug
pub mod debug;

/// Driver syscalls
pub mod driver;

/// Filesystem syscalls
pub mod fs;

/// Fast userspace mutex
pub mod futex;

/// Privilege syscalls
pub mod privilege;

/// Process syscalls
pub mod process;

/// Time syscalls
pub mod time;

/// Validate input
pub mod validate;

/// This function is the syscall handler of the kernel, it is composed of an inner function that returns a `Result<usize>`. After the inner function runs, the syscall
/// function calls [`Error::mux`] on it.
pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: usize, stack: &mut InterruptStack) -> usize {
    #[inline(always)]
    fn inner(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: usize, stack: &mut InterruptStack) -> Result<usize> {
        //SYS_* is declared in kernel/syscall/src/number.rs
        match a & SYS_CLASS {
            SYS_CLASS_FILE => {
                let fd = FileHandle::from(b);
                match a & SYS_ARG {
                    SYS_ARG_SLICE => file_op_slice(a, fd, validate_slice(c as *const u8, d)?),
                    SYS_ARG_MSLICE => file_op_mut_slice(a, fd, validate_slice_mut(c as *mut u8, d)?),
                    _ => match a {
                        SYS_CLOSE => close(fd),
                        SYS_DUP => dup(fd, validate_slice(c as *const u8, d)?).map(FileHandle::into),
                        SYS_DUP2 => dup2(fd, FileHandle::from(c), validate_slice(d as *const u8, e)?).map(FileHandle::into),
                        SYS_FCNTL => fcntl(fd, c, d),
                        SYS_FEXEC => fexec(fd, validate_slice(c as *const [usize; 2], d)?, validate_slice(e as *const [usize; 2], f)?),
                        SYS_FRENAME => frename(fd, validate_slice(c as *const u8, d)?),
                        SYS_FUNMAP => funmap(b),
                        _ => file_op(a, fd, c, d)
                    }
                }
            },
            SYS_CLASS_PATH => match a {
                SYS_OPEN => open(validate_slice(b as *const u8, c)?, d).map(FileHandle::into),
                SYS_CHMOD => chmod(validate_slice(b as *const u8, c)?, d as u16),
                SYS_RMDIR => rmdir(validate_slice(b as *const u8, c)?),
                SYS_UNLINK => unlink(validate_slice(b as *const u8, c)?),
                _ => Err(Error::new(ENOSYS))
            },
            _ => match a {
                SYS_YIELD => sched_yield(),
                SYS_NANOSLEEP => nanosleep(
                    validate_slice(b as *const TimeSpec, 1).map(|req| &req[0])?,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(c as *mut TimeSpec, 1).map(|rem| &mut rem[0])?)
                    }
                ),
                SYS_CLOCK_GETTIME => clock_gettime(b, validate_slice_mut(c as *mut TimeSpec, 1).map(|time| &mut time[0])?),
                SYS_FUTEX => futex(validate_slice_mut(b as *mut i32, 1).map(|uaddr| &mut uaddr[0])?, c, d as i32, e, f as *mut i32),
                SYS_BRK => brk(b),
                SYS_GETPID => getpid().map(ContextId::into),
                SYS_GETPGID => getpgid(ContextId::from(b)).map(ContextId::into),
                SYS_GETPPID => getppid().map(ContextId::into),
                SYS_CLONE => {
                    let b = CloneFlags::from_bits_truncate(b);
                    let old_rsp = stack.iret.rsp;
                    if b.contains(flag::CLONE_STACK) {
                        stack.iret.rsp = c;
                    }
                    let ret = clone(b, bp).map(ContextId::into);
                    stack.iret.rsp = old_rsp;
                    ret
                },
                SYS_EXIT => exit((b & 0xFF) << 8),
                SYS_KILL => kill(ContextId::from(b), c),
                SYS_WAITPID => waitpid(ContextId::from(b), c, WaitFlags::from_bits_truncate(d)).map(ContextId::into),
                SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?),
                SYS_IOPL => iopl(b, stack),
                SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?),
                SYS_GETEGID => getegid(),
                SYS_GETENS => getens(),
                SYS_GETEUID => geteuid(),
                SYS_GETGID => getgid(),
                SYS_GETNS => getns(),
                SYS_GETUID => getuid(),
                SYS_MPROTECT => mprotect(b, c, MapFlags::from_bits_truncate(d)),
                SYS_MKNS => mkns(validate_slice(b as *const [usize; 2], c)?),
                SYS_SETPGID => setpgid(ContextId::from(b), ContextId::from(c)),
                SYS_SETREUID => setreuid(b as u32, c as u32),
                SYS_SETRENS => setrens(SchemeNamespace::from(b), SchemeNamespace::from(c)),
                SYS_SETREGID => setregid(b as u32, c as u32),
                SYS_SIGACTION => sigaction(
                    b,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice(c as *const SigAction, 1).map(|act| &act[0])?)
                    },
                    if d == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(d as *mut SigAction, 1).map(|oldact| &mut oldact[0])?)
                    },
                    e
                ),
                SYS_SIGPROCMASK => sigprocmask(
                    b,
                    if c == 0 {
                        None
                    } else {
                        Some(validate_slice(c as *const [u64; 2], 1).map(|s| &s[0])?)
                    },
                    if d == 0 {
                        None
                    } else {
                        Some(validate_slice_mut(d as *mut [u64; 2], 1).map(|s| &mut s[0])?)
                    }
                ),
                SYS_SIGRETURN => sigreturn(),
                SYS_PIPE2 => pipe2(validate_slice_mut(b as *mut usize, 2)?, c),
                SYS_PHYSALLOC => physalloc(b),
                SYS_PHYSALLOC3 => physalloc3(b, c, &mut validate_slice_mut(d as *mut usize, 1)?[0]),
                SYS_PHYSFREE => physfree(b, c),
                SYS_PHYSMAP => physmap(b, c, PhysmapFlags::from_bits_truncate(d)),
                SYS_PHYSUNMAP => physunmap(b),
                SYS_UMASK => umask(b),
                SYS_VIRTTOPHYS => virttophys(b),
                _ => Err(Error::new(ENOSYS))
            }
        }
    }

    /*
    let debug = {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            let name_raw = context.name.lock();
            let name = unsafe { core::str::from_utf8_unchecked(&name_raw) };
            if name == "file:/bin/cargo" || name == "file:/bin/rustc" {
                if a == SYS_CLOCK_GETTIME {
                    false
                } else if (a == SYS_WRITE || a == SYS_FSYNC) && (b == 1 || b == 2) {
                    false
                } else {
                    true
                }
            } else {
                false
            }
        } else {
            false
        }
    };

    if debug {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            print!("{} ({}): ", unsafe { core::str::from_utf8_unchecked(&context.name.lock()) }, context.id.into());
        }

        println!("{}", debug::format_call(a, b, c, d, e, f));
    }
    */

    // The next lines set the current syscall in the context struct, then once the inner() function
    // completes, we set the current syscall to none.
    //
    // When the code below falls out of scope it will release the lock
    // see the spin crate for details
    {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let mut context = context_lock.write();
            context.syscall = Some((a, b, c, d, e, f));
        }
    }

    let result = inner(a, b, c, d, e, f, bp, stack);

    {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let mut context = context_lock.write();
            context.syscall = None;
        }
    }

    /*
    if debug {
        let contexts = crate::context::contexts();
        if let Some(context_lock) = contexts.current() {
            let context = context_lock.read();
            print!("{} ({}): ", unsafe { core::str::from_utf8_unchecked(&context.name.lock()) }, context.id.into());
        }

        print!("{} = ", debug::format_call(a, b, c, d, e, f));

        match result {
            Ok(ref ok) => {
                println!("Ok({} ({:#X}))", ok, ok);
            },
            Err(ref err) => {
                println!("Err({} ({:#X}))", err, err.errno);
            }
        }
    }
    */

    // errormux turns Result<usize> into -errno
    Error::mux(result)
}
<|endoftext|>


<commit_before>use super::{ParallelExtend, IntoParallelIterator, ParallelIterator};

use std::borrow::Cow;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::hash::{BuildHasher, Hash};
use std::collections::LinkedList;
use std::collections::{BinaryHeap, VecDeque};

/// Perform a generic `par_extend` by collecting to a `LinkedList<Vec<_>>` in
/// parallel, then extending the collection sequentially.
fn extend<C, I, F>(collection: &mut C, par_iter: I, reserve: F)
    where I: IntoParallelIterator,
          F: FnOnce(&mut C, &LinkedList<Vec<I::Item>>),
          C: Extend<I::Item>
{
    let list = par_iter
        .into_par_iter()
        .fold(Vec::new, |mut vec, elem| {
            vec.push(elem);
            vec
        })
        .map(|vec| {
            let mut list = LinkedList::new();
            list.push_back(vec);
            list
        })
        .reduce(LinkedList::new, |mut list1, mut list2| {
            list1.append(&mut list2);
            list1
        });

    reserve(collection, &list);
    for vec in list {
        collection.extend(vec);
    }
}

/// Compute the total length of a `LinkedList<Vec<_>>`.
fn len<T>(list: &LinkedList<Vec<T>>) -> usize {
    list.iter().map(Vec::len).sum()
}

/// Compute the total string length of a `LinkedList<Vec<AsRef<str>>>`.
fn str_len<T>(list: &LinkedList<Vec<T>>) -> usize
    where T: AsRef<str>
{
    list.iter()
        .flat_map(|vec| vec.iter().map(|s| s.as_ref().len()))
        .sum()
}

/// Extend a binary heap with items from a parallel iterator.
impl<T> ParallelExtend<T> for BinaryHeap<T>
    where T: Ord + Send
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = T>
    {
        extend(self, par_iter, |heap, list| heap.reserve(len(list)));
    }
}

/// Extend a binary heap with copied items from a parallel iterator.
impl<'a, T> ParallelExtend<&'a T> for BinaryHeap<T>
    where T: 'a + Copy + Ord + Send + Sync
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = &'a T>
    {
        extend(self, par_iter, |heap, list| heap.reserve(len(list)));
    }
}

/// Extend a B-tree map with items from a parallel iterator.
impl<K, V> ParallelExtend<(K, V)> for BTreeMap<K, V>
    where K: Ord + Send,
          V: Send
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = (K, V)>
    {
        extend(self, par_iter, |_, _| {});
    }
}

/// Extend a B-tree map with copied items from a parallel iterator.
impl<'a, K, V> ParallelExtend<(&'a K, &'a V)> for BTreeMap<K, V>
    where K: Copy + Ord + Send + Sync,
          V: Copy + Send + Sync
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = (&'a K, &'a V)>
    {
        extend(self, par_iter, |_, _| {});
    }
}

/// Extend a B-tree set with items from a parallel iterator.
impl<T> ParallelExtend<T> for BTreeSet<T>
    where T: Ord + Send
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = T>
    {
        extend(self, par_iter, |_, _| {});
    }
}

/// Extend a B-tree set with copied items from a parallel iterator.
impl<'a, T> ParallelExtend<&'a T> for BTreeSet<T>
    where T: 'a + Copy + Ord + Send + Sync
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = &'a T>
    {
        extend(self, par_iter, |_, _| {});
    }
}

/// Extend a hash map with items from a parallel iterator.
impl<K, V, S> ParallelExtend<(K, V)> for HashMap<K, V, S>
    where K: Eq + Hash + Send,
          V: Send,
          S: BuildHasher + Send
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = (K, V)>
    {
        // See the map_collect benchmarks in rayon-demo for different strategies.
        extend(self, par_iter, |map, list| map.reserve(len(list)));
    }
}

/// Extend a hash map with copied items from a parallel iterator.
impl<'a, K, V, S> ParallelExtend<(&'a K, &'a V)> for HashMap<K, V, S>
    where K: Copy + Eq + Hash + Send + Sync,
          V: Copy + Send + Sync,
          S: BuildHasher + Send
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = (&'a K, &'a V)>
    {
        extend(self, par_iter, |map, list| map.reserve(len(list)));
    }
}

/// Extend a hash set with items from a parallel iterator.
impl<T, S> ParallelExtend<T> for HashSet<T, S>
    where T: Eq + Hash + Send,
          S: BuildHasher + Send
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = T>
    {
        extend(self, par_iter, |set, list| set.reserve(len(list)));
    }
}

/// Extend a hash set with copied items from a parallel iterator.
impl<'a, T, S> ParallelExtend<&'a T> for HashSet<T, S>
    where T: 'a + Copy + Eq + Hash + Send + Sync,
          S: BuildHasher + Send
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = &'a T>
    {
        extend(self, par_iter, |set, list| set.reserve(len(list)));
    }
}

/// Extend a linked list with items from a parallel iterator.
impl<T> ParallelExtend<T> for LinkedList<T>
    where T: Send
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = T>
    {
        let mut list = par_iter
            .into_par_iter()
            .fold(LinkedList::new, |mut list, elem| {
                list.push_back(elem);
                list
            })
            .reduce(LinkedList::new, |mut list1, mut list2| {
                list1.append(&mut list2);
                list1
            });
        self.append(&mut list);
    }
}

/// Extend a linked list with copied items from a parallel iterator.
impl<'a, T> ParallelExtend<&'a T> for LinkedList<T>
    where T: 'a + Copy + Send + Sync
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = &'a T>
    {
        self.par_extend(par_iter.into_par_iter().cloned())
    }
}

/// Extend a string with characters from a parallel iterator.
impl ParallelExtend<char> for String {
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = char>
    {
        // This is like `extend`, but `Vec<char>` is less efficient to deal
        // with than `String`, so instead collect to `LinkedList<String>`.
        let list: LinkedList<_> = par_iter
            .into_par_iter()
            .fold(String::new, |mut string, ch| {
                string.push(ch);
                string
            })
            .map(|vec| {
                let mut list = LinkedList::new();
                list.push_back(vec);
                list
            })
            .reduce(LinkedList::new, |mut list1, mut list2| {
                list1.append(&mut list2);
                list1
            });

        self.reserve(list.iter().map(String::len).sum());
        self.extend(list)
    }
}

/// Extend a string with copied characters from a parallel iterator.
impl<'a> ParallelExtend<&'a char> for String {
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = &'a char>
    {
        self.par_extend(par_iter.into_par_iter().cloned())
    }
}

/// Extend a string with string slices from a parallel iterator.
impl<'a> ParallelExtend<&'a str> for String {
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = &'a str>
    {
        extend(self, par_iter, |string, list| string.reserve(str_len(list)));
    }
}

/// Extend a string with strings from a parallel iterator.
impl ParallelExtend<String> for String {
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = String>
    {
        extend(self, par_iter, |string, list| string.reserve(str_len(list)));
    }
}

/// Extend a string with string slices from a parallel iterator.
impl<'a> ParallelExtend<Cow<'a, str>> for String {
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = Cow<'a, str>>
    {
        extend(self, par_iter, |string, list| string.reserve(str_len(list)));
    }
}

/// Extend a deque with items from a parallel iterator.
impl<T> ParallelExtend<T> for VecDeque<T>
    where T: Send
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = T>
    {
        extend(self, par_iter, |deque, list| deque.reserve(len(list)));
    }
}

/// Extend a deque with copied items from a parallel iterator.
impl<'a, T> ParallelExtend<&'a T> for VecDeque<T>
    where T: 'a + Copy + Send + Sync
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = &'a T>
    {
        extend(self, par_iter, |deque, list| deque.reserve(len(list)));
    }
}

// See the `collect` module for the `Vec<T>` implementation.
// impl<T> ParallelExtend<T> for Vec<T>

/// Extend a vector with copied items from a parallel iterator.
impl<'a, T> ParallelExtend<&'a T> for Vec<T>
    where T: 'a + Copy + Send + Sync
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = &'a T>
    {
        self.par_extend(par_iter.into_par_iter().cloned())
    }
}
<commit_msg>Avoid `Extend<Cow>` to support Rust < 1.19<commit_after>use super::{ParallelExtend, IntoParallelIterator, ParallelIterator};

use std::borrow::Cow;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::hash::{BuildHasher, Hash};
use std::collections::LinkedList;
use std::collections::{BinaryHeap, VecDeque};

/// Perform a generic `par_extend` by collecting to a `LinkedList<Vec<_>>` in
/// parallel, then extending the collection sequentially.
fn extend<C, I, F>(collection: &mut C, par_iter: I, reserve: F)
    where I: IntoParallelIterator,
          F: FnOnce(&mut C, &LinkedList<Vec<I::Item>>),
          C: Extend<I::Item>
{
    let list = par_iter
        .into_par_iter()
        .fold(Vec::new, |mut vec, elem| {
            vec.push(elem);
            vec
        })
        .map(|vec| {
            let mut list = LinkedList::new();
            list.push_back(vec);
            list
        })
        .reduce(LinkedList::new, |mut list1, mut list2| {
            list1.append(&mut list2);
            list1
        });

    reserve(collection, &list);
    for vec in list {
        collection.extend(vec);
    }
}

/// Compute the total length of a `LinkedList<Vec<_>>`.
fn len<T>(list: &LinkedList<Vec<T>>) -> usize {
    list.iter().map(Vec::len).sum()
}

/// Compute the total string length of a `LinkedList<Vec<AsRef<str>>>`.
fn str_len<T>(list: &LinkedList<Vec<T>>) -> usize
    where T: AsRef<str>
{
    list.iter()
        .flat_map(|vec| vec.iter().map(|s| s.as_ref().len()))
        .sum()
}

/// Extend a binary heap with items from a parallel iterator.
impl<T> ParallelExtend<T> for BinaryHeap<T>
    where T: Ord + Send
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = T>
    {
        extend(self, par_iter, |heap, list| heap.reserve(len(list)));
    }
}

/// Extend a binary heap with copied items from a parallel iterator.
impl<'a, T> ParallelExtend<&'a T> for BinaryHeap<T>
    where T: 'a + Copy + Ord + Send + Sync
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = &'a T>
    {
        extend(self, par_iter, |heap, list| heap.reserve(len(list)));
    }
}

/// Extend a B-tree map with items from a parallel iterator.
impl<K, V> ParallelExtend<(K, V)> for BTreeMap<K, V>
    where K: Ord + Send,
          V: Send
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = (K, V)>
    {
        extend(self, par_iter, |_, _| {});
    }
}

/// Extend a B-tree map with copied items from a parallel iterator.
impl<'a, K, V> ParallelExtend<(&'a K, &'a V)> for BTreeMap<K, V>
    where K: Copy + Ord + Send + Sync,
          V: Copy + Send + Sync
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = (&'a K, &'a V)>
    {
        extend(self, par_iter, |_, _| {});
    }
}

/// Extend a B-tree set with items from a parallel iterator.
impl<T> ParallelExtend<T> for BTreeSet<T>
    where T: Ord + Send
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = T>
    {
        extend(self, par_iter, |_, _| {});
    }
}

/// Extend a B-tree set with copied items from a parallel iterator.
impl<'a, T> ParallelExtend<&'a T> for BTreeSet<T>
    where T: 'a + Copy + Ord + Send + Sync
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = &'a T>
    {
        extend(self, par_iter, |_, _| {});
    }
}

/// Extend a hash map with items from a parallel iterator.
impl<K, V, S> ParallelExtend<(K, V)> for HashMap<K, V, S>
    where K: Eq + Hash + Send,
          V: Send,
          S: BuildHasher + Send
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = (K, V)>
    {
        // See the map_collect benchmarks in rayon-demo for different strategies.
        extend(self, par_iter, |map, list| map.reserve(len(list)));
    }
}

/// Extend a hash map with copied items from a parallel iterator.
impl<'a, K, V, S> ParallelExtend<(&'a K, &'a V)> for HashMap<K, V, S>
    where K: Copy + Eq + Hash + Send + Sync,
          V: Copy + Send + Sync,
          S: BuildHasher + Send
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = (&'a K, &'a V)>
    {
        extend(self, par_iter, |map, list| map.reserve(len(list)));
    }
}

/// Extend a hash set with items from a parallel iterator.
impl<T, S> ParallelExtend<T> for HashSet<T, S>
    where T: Eq + Hash + Send,
          S: BuildHasher + Send
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = T>
    {
        extend(self, par_iter, |set, list| set.reserve(len(list)));
    }
}

/// Extend a hash set with copied items from a parallel iterator.
impl<'a, T, S> ParallelExtend<&'a T> for HashSet<T, S>
    where T: 'a + Copy + Eq + Hash + Send + Sync,
          S: BuildHasher + Send
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = &'a T>
    {
        extend(self, par_iter, |set, list| set.reserve(len(list)));
    }
}

/// Extend a linked list with items from a parallel iterator.
impl<T> ParallelExtend<T> for LinkedList<T>
    where T: Send
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = T>
    {
        let mut list = par_iter
            .into_par_iter()
            .fold(LinkedList::new, |mut list, elem| {
                list.push_back(elem);
                list
            })
            .reduce(LinkedList::new, |mut list1, mut list2| {
                list1.append(&mut list2);
                list1
            });
        self.append(&mut list);
    }
}

/// Extend a linked list with copied items from a parallel iterator.
impl<'a, T> ParallelExtend<&'a T> for LinkedList<T>
    where T: 'a + Copy + Send + Sync
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = &'a T>
    {
        self.par_extend(par_iter.into_par_iter().cloned())
    }
}

/// Extend a string with characters from a parallel iterator.
impl ParallelExtend<char> for String {
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = char>
    {
        // This is like `extend`, but `Vec<char>` is less efficient to deal
        // with than `String`, so instead collect to `LinkedList<String>`.
        let list: LinkedList<_> = par_iter
            .into_par_iter()
            .fold(String::new, |mut string, ch| {
                string.push(ch);
                string
            })
            .map(|vec| {
                let mut list = LinkedList::new();
                list.push_back(vec);
                list
            })
            .reduce(LinkedList::new, |mut list1, mut list2| {
                list1.append(&mut list2);
                list1
            });

        self.reserve(list.iter().map(String::len).sum());
        self.extend(list)
    }
}

/// Extend a string with copied characters from a parallel iterator.
impl<'a> ParallelExtend<&'a char> for String {
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = &'a char>
    {
        self.par_extend(par_iter.into_par_iter().cloned())
    }
}

/// Extend a string with string slices from a parallel iterator.
impl<'a> ParallelExtend<&'a str> for String {
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = &'a str>
    {
        extend(self, par_iter, |string, list| string.reserve(str_len(list)));
    }
}

/// Extend a string with strings from a parallel iterator.
impl ParallelExtend<String> for String {
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = String>
    {
        extend(self, par_iter, |string, list| string.reserve(str_len(list)));
    }
}

/// Extend a string with string slices from a parallel iterator.
impl<'a> ParallelExtend<Cow<'a, str>> for String {
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = Cow<'a, str>>
    {
        // This is like `extend`, but `Extend<Cow<'a, str>> for String`
        // wasn't added until Rust 1.19, so we can't use it directly yet.
        let list = par_iter
            .into_par_iter()
            .fold(Vec::new, |mut vec, elem| {
                vec.push(elem);
                vec
            })
        .map(|vec| {
            let mut list = LinkedList::new();
            list.push_back(vec);
            list
        })
        .reduce(LinkedList::new, |mut list1, mut list2| {
            list1.append(&mut list2);
            list1
        });

        self.reserve(str_len(&list));
        for vec in list {
            self.extend(vec.iter().map(|cow| &**cow));
        }
    }
}

/// Extend a deque with items from a parallel iterator.
impl<T> ParallelExtend<T> for VecDeque<T>
    where T: Send
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = T>
    {
        extend(self, par_iter, |deque, list| deque.reserve(len(list)));
    }
}

/// Extend a deque with copied items from a parallel iterator.
impl<'a, T> ParallelExtend<&'a T> for VecDeque<T>
    where T: 'a + Copy + Send + Sync
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = &'a T>
    {
        extend(self, par_iter, |deque, list| deque.reserve(len(list)));
    }
}

// See the `collect` module for the `Vec<T>` implementation.
// impl<T> ParallelExtend<T> for Vec<T>

/// Extend a vector with copied items from a parallel iterator.
impl<'a, T> ParallelExtend<&'a T> for Vec<T>
    where T: 'a + Copy + Send + Sync
{
    fn par_extend<I>(&mut self, par_iter: I)
        where I: IntoParallelIterator<Item = &'a T>
    {
        self.par_extend(par_iter.into_par_iter().cloned())
    }
}
<|endoftext|>


<commit_before>//! A Trivial File Transfer (TFTP) protocol client implementation.
//!
//! This module contains the ability to read data from or write data to a remote TFTP server.
use std::io::{IoResult};
use std::io::net::ip::{SocketAddr, Ipv4Addr};
use std::io::net::udp::UdpSocket;

use packet::{Mode, RequestPacket, DataPacketOctet, AckPacket, EncodePacket, RawPacket};

static MAX_DATA_SIZE: uint = 512;

/// A Trivial File Transfer Protocol client.
pub struct Client {
    socket: UdpSocket,
    remote_addr: SocketAddr,
}

impl Client {
    /// Creates a new client and binds an UDP socket.
    pub fn new(remote_addr: SocketAddr) -> IoResult<Client> {
        // FIXME: port should not be hardcoded
        let addr = SocketAddr{
            ip: Ipv4Addr(127, 0, 0, 1),
            port: 41000
        };
        UdpSocket::bind(addr).map(|socket| {
            Client{ socket: socket, remote_addr: remote_addr }
        })
    }

    /// A TFTP read request
    ///
    /// Get a file `path` from the server using a `mode`. Received data is written to
    /// the `writer`.
    pub fn get(&mut self, path: &Path, mode: Mode, writer: &mut Writer) -> IoResult<()> {
        let mut bufs = Vec::from_fn(2, |_| Vec::from_elem(MAX_DATA_SIZE + 4, 0));

        let read_request = RequestPacket::read_request(path.as_str().expect("utf-8 path"), mode);
        let encoded = read_request.encode_using(bufs.pop().unwrap());
        try!(self.socket.send_to(encoded.packet_buf(), self.remote_addr));

        bufs.push(encoded.get_buffer());
        let mut first_packet = true;
        let mut current_id = 1;
        loop {
            let mut buf = bufs.pop().unwrap();
            match self.socket.recv_from(buf.as_mut_slice()) {
                Ok((n, from)) => {
                    if first_packet && self.remote_addr.ip == from.ip {
                        self.remote_addr.port = from.port;
                        first_packet = false;
                    }
                    if from != self.remote_addr {
                        bufs.push(buf);
                        continue
                    }
                    let packet = RawPacket::new(buf, n);
                    {
                        let data_packet: Option<DataPacketOctet> = packet.decode();
                        match data_packet {
                            Some(dp) => {
                                if current_id == dp.block_id() {
                                    try!(writer.write(dp.data()));
                                    let ack = AckPacket::new(dp.block_id());
                                    let buf = bufs.pop().unwrap();
                                    let encoded = ack.encode_using(buf);
                                    try!(self.socket.send_to(encoded.packet_buf(), self.remote_addr));
                                    if dp.data().len() < MAX_DATA_SIZE {
                                        println!("done");
                                        break;
                                    }
                                    bufs.push(encoded.get_buffer());
                                    current_id += 1;
                                } else {
                                    println!("wrong packet id");
                                }
                            }
                            None => fail!("not a data packet")
                        }
                    }
                    bufs.push(packet.get_buffer());
                }
                Err(ref e) => fail!("error = {}", e)
            }
        }
        return Ok(())
    }

    /// A TFTP write request
    ///
    /// Put a file `path` to the server using a `mode`.
    pub fn put(&mut self, path: &Path, mode: Mode, reader: &mut Reader) -> IoResult<()> {
        let mut bufs = Vec::from_fn(2, |_| Vec::from_elem(MAX_DATA_SIZE + 4, 0));
        let mut read_buffer = Vec::from_elem(MAX_DATA_SIZE, 0);

        let read_request = RequestPacket::write_request(path.as_str().expect("utf-8 path"), mode);
        let encoded = read_request.encode_using(bufs.pop().unwrap());
        try!(self.socket.send_to(encoded.packet_buf(), self.remote_addr));

        bufs.push(encoded.get_buffer());
        let mut first_packet = true;
        let mut last_packet = false;
        let mut current_id = 0;
        loop {
            let mut buf = bufs.pop().unwrap();
            match self.socket.recv_from(buf.as_mut_slice()) {
                Ok((n, from)) => {
                    if first_packet && self.remote_addr.ip == from.ip {
                        self.remote_addr.port = from.port;
                        first_packet = false;
                    }
                    if from != self.remote_addr {
                        bufs.push(buf);
                        continue
                    }
                    let packet = RawPacket::new(buf, n);
                    {
                        let ack_packet: Option<AckPacket> = packet.decode();
                        match ack_packet {
                            Some(dp) => {
                                if current_id == dp.block_id() {
                                    if last_packet {
                                        println!("done");
                                        break
                                    }
                                    let bytes_read = try!(reader.read(read_buffer.as_mut_slice()));
                                    if bytes_read < MAX_DATA_SIZE {
                                        last_packet = true;
                                    }
                                    let ack = DataPacketOctet::from_slice(dp.block_id() + 1, read_buffer.slice_to(bytes_read));
                                    let buf = bufs.pop().unwrap();
                                    let encoded = ack.encode_using(buf);
                                    try!(self.socket.send_to(encoded.packet_buf(), self.remote_addr));
                                    bufs.push(encoded.get_buffer());
                                    current_id += 1;
                                } else {
                                    println!("wrong packet id");
                                }
                            }
                            None => fail!("not a data packet")
                        }
                    }
                    bufs.push(packet.get_buffer());
                }
                Err(ref e) => fail!("error = {}", e)
            }
        }
        return Ok(())
    }
}
<commit_msg>Properly handle EOF error when reading from a file<commit_after>//! A Trivial File Transfer (TFTP) protocol client implementation.
//!
//! This module contains the ability to read data from or write data to a remote TFTP server.
use std::io;
use std::io::{IoResult};
use std::io::net::ip::{SocketAddr, Ipv4Addr};
use std::io::net::udp::UdpSocket;

use packet::{Mode, RequestPacket, DataPacketOctet, AckPacket, EncodePacket, RawPacket};

static MAX_DATA_SIZE: uint = 512;

/// A Trivial File Transfer Protocol client.
pub struct Client {
    socket: UdpSocket,
    remote_addr: SocketAddr,
}

impl Client {
    /// Creates a new client and binds an UDP socket.
    pub fn new(remote_addr: SocketAddr) -> IoResult<Client> {
        // FIXME: port should not be hardcoded
        let addr = SocketAddr{
            ip: Ipv4Addr(127, 0, 0, 1),
            port: 41000
        };
        UdpSocket::bind(addr).map(|socket| {
            Client{ socket: socket, remote_addr: remote_addr }
        })
    }

    /// A TFTP read request
    ///
    /// Get a file `path` from the server using a `mode`. Received data is written to
    /// the `writer`.
    pub fn get(&mut self, path: &Path, mode: Mode, writer: &mut Writer) -> IoResult<()> {
        let mut bufs = Vec::from_fn(2, |_| Vec::from_elem(MAX_DATA_SIZE + 4, 0));

        let read_request = RequestPacket::read_request(path.as_str().expect("utf-8 path"), mode);
        let encoded = read_request.encode_using(bufs.pop().unwrap());
        try!(self.socket.send_to(encoded.packet_buf(), self.remote_addr));

        bufs.push(encoded.get_buffer());
        let mut first_packet = true;
        let mut current_id = 1;
        loop {
            let mut buf = bufs.pop().unwrap();
            match self.socket.recv_from(buf.as_mut_slice()) {
                Ok((n, from)) => {
                    if first_packet && self.remote_addr.ip == from.ip {
                        self.remote_addr.port = from.port;
                        first_packet = false;
                    }
                    if from != self.remote_addr {
                        bufs.push(buf);
                        continue
                    }
                    let packet = RawPacket::new(buf, n);
                    {
                        let data_packet: Option<DataPacketOctet> = packet.decode();
                        match data_packet {
                            Some(dp) => {
                                if current_id == dp.block_id() {
                                    try!(writer.write(dp.data()));
                                    let ack = AckPacket::new(dp.block_id());
                                    let buf = bufs.pop().unwrap();
                                    let encoded = ack.encode_using(buf);
                                    try!(self.socket.send_to(encoded.packet_buf(), self.remote_addr));
                                    if dp.data().len() < MAX_DATA_SIZE {
                                        println!("done");
                                        break;
                                    }
                                    bufs.push(encoded.get_buffer());
                                    current_id += 1;
                                } else {
                                    println!("wrong packet id");
                                }
                            }
                            None => fail!("not a data packet")
                        }
                    }
                    bufs.push(packet.get_buffer());
                }
                Err(ref e) => fail!("error = {}", e)
            }
        }
        return Ok(())
    }

    /// A TFTP write request
    ///
    /// Put a file `path` to the server using a `mode`.
    pub fn put(&mut self, path: &Path, mode: Mode, reader: &mut Reader) -> IoResult<()> {
        let mut bufs = Vec::from_fn(2, |_| Vec::from_elem(MAX_DATA_SIZE + 4, 0));
        let mut read_buffer = Vec::from_elem(MAX_DATA_SIZE, 0);

        let read_request = RequestPacket::write_request(path.as_str().expect("utf-8 path"), mode);
        let encoded = read_request.encode_using(bufs.pop().unwrap());
        try!(self.socket.send_to(encoded.packet_buf(), self.remote_addr));

        bufs.push(encoded.get_buffer());
        let mut first_packet = true;
        let mut last_packet = false;
        let mut current_id = 0;
        loop {
            let mut buf = bufs.pop().unwrap();
            match self.socket.recv_from(buf.as_mut_slice()) {
                Ok((n, from)) => {
                    if first_packet && self.remote_addr.ip == from.ip {
                        self.remote_addr.port = from.port;
                        first_packet = false;
                    }
                    if from != self.remote_addr {
                        bufs.push(buf);
                        continue
                    }
                    let packet = RawPacket::new(buf, n);
                    {
                        let ack_packet: Option<AckPacket> = packet.decode();
                        match ack_packet {
                            Some(dp) => {
                                if current_id == dp.block_id() {
                                    if last_packet {
                                        println!("done");
                                        break
                                    }
                                    let bytes_read = try!(self.read_block(reader, read_buffer.as_mut_slice()));
                                    if bytes_read < MAX_DATA_SIZE {
                                        last_packet = true;
                                    }
                                    let ack = DataPacketOctet::from_slice(dp.block_id() + 1, read_buffer.slice_to(bytes_read));
                                    let buf = bufs.pop().unwrap();
                                    let encoded = ack.encode_using(buf);
                                    try!(self.socket.send_to(encoded.packet_buf(), self.remote_addr));
                                    bufs.push(encoded.get_buffer());
                                    current_id += 1;
                                } else {
                                    println!("wrong packet id");
                                }
                            }
                            None => fail!("not a data packet")
                        }
                    }
                    bufs.push(packet.get_buffer());
                }
                Err(ref e) => fail!("error = {}", e)
            }
        }
        return Ok(())
    }

    fn read_block(&mut self, reader: &mut Reader, buf: &mut [u8]) -> IoResult<uint> {
        reader.read(buf).or_else(|e| {
            if e.kind == io::EndOfFile {
                Ok(0u)
            } else {
                Err(e)
            }
        })
    }
}
<|endoftext|>


<commit_before>extern crate hs100;

use hs100::SmartPlug;

const HOST: &'static str = "192.168.0.37:9999";

fn main() {
    let api = SmartPlug::new(HOST);

    let resp = api.sysinfo();
    println!("[sysinfo]: {}\n", resp);

    let resp = api.meterinfo();
    println!("[meterinfo]: {}", resp);
}
<commit_msg>add more examples<commit_after>extern crate hs100;

use hs100::SmartPlug;

const HOST: &'static str = "192.168.0.37:9999";

fn main() {
    let api = SmartPlug::new(HOST);

    let resp = api.sysinfo();
    println!("[sysinfo]: {}\n", resp);

    let resp = api.meterinfo();
    println!("[meterinfo]: {}\n", resp);

    let resp = api.dailystats(7, 2017);
    println!("[dailystats]: {}", resp);

    //
    // Avoid these if the HS100 is plugged to your computer :)
    //

    // let resp = api.off();
    // let resp = api.on();
}
<|endoftext|>