<commit_before>use std::default::Default;

use keyboard::Key;
use keymap::{ KeyMap, KeyMapState };
use buffer::{ Direction, Mark, WordEdgeMatch };
use textobject::{ TextObject, Offset, Kind, Anchor };
use overlay::OverlayType;

/// Instructions for the Editor.
/// These do NOT alter the text, but may change editor/view state
#[derive(Copy, Debug)]
#[allow(dead_code)]
pub enum Instruction {
    SaveBuffer,
    //FindFile,
    ExitEditor,

    SetMark(Mark),
    SetOverlay(OverlayType),
    // SetMode(...)
}

/// Operations on the Buffer.
/// These DO alter the text, but otherwise may NOT change editor/view state
/// Note that these differ from log::Change in that they are higher-level
/// operations dependent on state (cursor/mark locations, etc.), as opposed
/// to concrete operations on absolute indexes (insert 'a' at index 158, etc.)
#[derive(Copy, Debug)]
#[allow(dead_code)]
pub enum Operation {
    Insert(char), // insert text
    Delete,       // delete some object

    Undo,         // rewind buffer transaction log
    Redo,         // replay buffer transaction log
}

/// Fragments that can be combined to specify a command
#[derive(Copy, Debug)]
#[allow(dead_code)]
pub enum Partial {
    Kind(Kind),
    Anchor(Anchor),
    Offset(Offset),
    Object(TextObject),
    Action(Action),
}

#[derive(Copy, Debug)]
#[allow(dead_code)]
pub enum Action {
    Operation(Operation),
    Instruction(Instruction),
}

/// A complete, actionable command
#[derive(Copy, Debug)]
pub struct Command {
    pub number: i32,        // numeric paramter, line number, repeat count, etc.
    pub action: Action,     // what to do
    pub object: TextObject, // where to do it
}

pub struct Builder {
    number: Option<i32>,
    repeat: Option<usize>,

    action: Option<Action>,
    mark: Option<Mark>,
    kind: Option<Kind>,
    anchor: Option<Anchor>,
    offset: Option<Offset>,
    object: Option<TextObject>,

    reading_number: bool,
    keymap: KeyMap<Partial>,
}

#[derive(Copy, Debug)]
pub enum BuilderEvent {
    Invalid,            // cannot find a valid interpretation
    Incomplete,         // needs more information
    Complete(Command),  // command is finished
}

impl Builder {
    pub fn new() -> Builder {
        Builder {
            number: None,
            repeat: None,
            action: None,
            mark: None,
            kind: None,
            anchor: None,
            offset: None,
            object: None,
            reading_number: false,
            keymap: default_keymap()
        }
    }

    pub fn reset(&mut self) {
        self.number = None;
        self.repeat = None;
        self.action = None;
        self.mark = None;
        self.kind = None;
        self.anchor = None;
        self.object = None;
        self.offset = None;
        self.reading_number = false;
    }

    pub fn check_key(&mut self, key: Key) -> BuilderEvent {
        if let Key::Char(c) = key {
            // '0' might be bound (start of line), and cannot be the start of a number sequence
            if c.is_digit(10) && (self.reading_number || c != '0') {
                let n = c.to_digit(10).unwrap();
                self.reading_number = true;
                self.append_digit(n);
                return BuilderEvent::Incomplete;
            } else if self.reading_number {

                self.reading_number = false;
            }
        }

        match self.keymap.check_key(key) {
            KeyMapState::Match(partial) => self.apply_partial(partial),
            KeyMapState::None           => { self.reset(); return BuilderEvent::Invalid; }
            _ => {},
        }

        if let Some(c) = self.complete_command() {
            self.reset();
            return BuilderEvent::Complete(c)
        } else {
            return BuilderEvent::Incomplete
        }
    }

    fn complete_object(&mut self) -> Option<TextObject> {
        let mut result: Option<TextObject> = if let Some(object) = self.object {
            // we have a complete object ready to go
            Some(object)
        } else if let Some(kind) = self.kind {
            // we have at least a kind
            Some(TextObject {
                kind: kind,
                offset: self.offset.unwrap_or(Offset::Absolute(0)),
            })
        } else {
            None
        };

        if let Some(ref mut object) = result {
            if let Some(number) = self.number {
                object.offset = object.offset.with_num(number as usize);
            }
        }

        result
    }

    fn complete_command(&mut self) -> Option<Command> {
        /* rules for completing commands:
              | action            | number | object | reference    | kind |   | result                                                            |
              | -                 | -      | -      | -            | -    | - | -                                                                 |
              | no                | no     | no     | no           | yes  |   | move cursor to next (default) text object with kind               |
              | no                | no     | no     | yes          | -    |   | move cursor to text object with reference + default anchor        |
              | no                | no     | yes    | -            | -    |   | move cursor to text object                                        |
              | no                | yes    | no     | no           | no   |   | incomplete                                                        |
              | no                | yes    | no     | no           | yes  |   | move cursor to nth instance of kind (from start of buffer)        |
              | no                | yes    | no     | yes (index)  | -    |   | set index to number, cursor to ref + default anchor               |
              | no                | yes    | no     | yes (offset) | -    |   | multiply offset by number, cursor to ref + default anchor         |
              | no                | yes    | no     | yes (mark)   | -    |   | incomplete                                                        |
              | yes (instruction) | -      | -      | -            | -    |   | send instruction to editor with whatever parameters are available |
              | yes (operation)   | no     | no     | no           | no   |   | incomplete                                                        |
              | yes (operation)   | no     | no     | no           | yes  |   | apply operation to kind at cursor (default anchor)                |
              | yes (operation)   | no     | no     | yes          | -    |   | apply operation to reference with default anchor                  |
              | yes (operation)   | no     | yes    | -            | -    |   | apply operation to object                                         |
              | yes (operation)   | yes    | no     | no           | no   |   | incomplete                                                        |
              | yes (operation)   | yes    | no     | no           | yes  |   | apply operation to nth instance of kind                           |
        */

        // editor instructions may not need a text object, go ahead and return immediately
        if let Some(Action::Instruction(i)) = self.action {
            return Some(Command {
                number: self.repeat.unwrap_or(0) as i32,
                action: Action::Instruction(i),
                object: self.complete_object().unwrap_or_default()
            });
        }

        if let Some(to) = self.complete_object() {
            if let Some(Action::Operation(o)) = self.action {
                // we have an object, and an operation
                return Some(Command {
                    number: self.repeat.unwrap_or(0) as i32,
                    action: Action::Operation(o),
                    object: to
                });
            } else {
                // we have just an object, assume move cursor instruction
                return Some(Command {
                    number: self.repeat.unwrap_or(0) as i32,
                    action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
                    object: to
                });
            }
        }
        None
    }

    fn append_digit(&mut self, n: usize) {
        if let Some(current) = self.number {
            self.number = Some((current*10) + n as i32);
        } else {
            self.number = Some(n as i32);
        }
    }

    fn apply_partial(&mut self, partial: Partial) {
        match partial {
            Partial::Kind(k)      => self.kind = Some(k),
            Partial::Anchor(a)    => self.anchor = Some(a),
            Partial::Offset(o)    => self.offset = Some(o),
            Partial::Object(o)    => self.object = Some(o),
            Partial::Action(a)    => {
                self.action = Some(a);
                if !self.reading_number && self.number.is_some() && self.repeat.is_none() {
                    // the first number followed by an action is treated as a repetition
                    self.repeat = Some(self.number.unwrap() as usize);
                    self.number = None;
                }
            }
        }

        // propagate upwards from anchor to object
        // if both an object(a) and an anchor(b) have been applied, the resulting
        // object should be exactly the same as (a), only using (b) as the anchor
        if let Some(anchor) = self.anchor {
            if let Some(kind) = self.kind {
                self.kind = Some(kind.with_anchor(anchor));
            }
            if let Some(object) = self.object {
                self.object = Some(TextObject {
                    kind: object.kind.with_anchor(anchor),
                    offset: object.offset,
                });
            }
        }
        if let Some(kind) = self.kind {
            if let Some(ref mut object) = self.object {
                object.kind = kind;
            }
        }
        if let Some(offset) = self.offset {
            if let Some(ref mut object) = self.object {
                object.offset = offset;
            }
        }

        // propagate downwards from object to unset partials
        if let Some(object) = self.object {
            if self.offset.is_none() { self.offset = Some(object.offset); }
            if self.kind.is_none() { self.kind = Some(object.kind); }
            if self.anchor.is_none() { self.anchor = Some(object.kind.get_anchor()); }
        }

        if self.offset.is_some() && self.kind.is_some() && self.object.is_none() {
            self.object = Some(TextObject {
                kind: self.kind.unwrap(),
                offset: self.offset.unwrap(),
            });
        }
    }
}

fn default_keymap() -> KeyMap<Partial> {
    let mut keymap = KeyMap::new();

    // next/previous char
    keymap.bind_key(Key::Char('l'), Partial::Object(TextObject {
        kind: Kind::Char,
        offset: Offset::Forward(1, Mark::Cursor(0))
    }));
    keymap.bind_key(Key::Char('h'), Partial::Object(TextObject {
        kind: Kind::Char,
        offset: Offset::Backward(1, Mark::Cursor(0))
    }));

    // next/previous line
    keymap.bind_key(Key::Char('j'), Partial::Object(TextObject {
        kind: Kind::Line(Anchor::Same),
        offset: Offset::Forward(1, Mark::Cursor(0))
    }));
    keymap.bind_key(Key::Char('k'), Partial::Object(TextObject {
        kind: Kind::Line(Anchor::Same),
        offset: Offset::Backward(1, Mark::Cursor(0))
    }));

    // next/previous word
    keymap.bind_key(Key::Char('w'), Partial::Object(TextObject {
        kind: Kind::Word(Anchor::Before),
        offset: Offset::Forward(1, Mark::Cursor(0))
    }));
    keymap.bind_key(Key::Char('b'), Partial::Object(TextObject {
        kind: Kind::Word(Anchor::Before),
        offset: Offset::Backward(1, Mark::Cursor(0))
    }));

    // kinds
    keymap.bind_keys(&[Key::Char('`'), Key::Char('c')], Partial::Kind(Kind::Char));
    keymap.bind_keys(&[Key::Char('`'), Key::Char('w')], Partial::Kind(Kind::Word(Anchor::Before)));
    keymap.bind_keys(&[Key::Char('`'), Key::Char('l')], Partial::Kind(Kind::Line(Anchor::Before)));

    // anchors
    keymap.bind_key(Key::Char(','), Partial::Anchor(Anchor::Before));
    keymap.bind_key(Key::Char('.'), Partial::Anchor(Anchor::After));

    // actions
    keymap.bind_key(Key::Char('d'), Partial::Action(Action::Operation(Operation::Delete)));
    keymap.bind_key(Key::Char(':'), Partial::Action(Action::Instruction(Instruction::SetOverlay(OverlayType::Prompt))));

    keymap
}
<commit_msg>Added shortcuts to create commonly used commands<commit_after>use std::default::Default;

use keyboard::Key;
use keymap::{ KeyMap, KeyMapState };
use buffer::{ Direction, Mark, WordEdgeMatch };
use textobject::{ TextObject, Offset, Kind, Anchor };
use overlay::OverlayType;

/// Instructions for the Editor.
/// These do NOT alter the text, but may change editor/view state
#[derive(Copy, Debug)]
#[allow(dead_code)]
pub enum Instruction {
    SaveBuffer,
    //FindFile,
    ExitEditor,

    SetMark(Mark),
    SetOverlay(OverlayType),
    // SetMode(...)
}

/// Operations on the Buffer.
/// These DO alter the text, but otherwise may NOT change editor/view state
/// Note that these differ from log::Change in that they are higher-level
/// operations dependent on state (cursor/mark locations, etc.), as opposed
/// to concrete operations on absolute indexes (insert 'a' at index 158, etc.)
#[derive(Copy, Debug)]
#[allow(dead_code)]
pub enum Operation {
    Insert(char), // insert text
    Delete,       // delete some object

    Undo,         // rewind buffer transaction log
    Redo,         // replay buffer transaction log
}

/// Fragments that can be combined to specify a command
#[derive(Copy, Debug)]
#[allow(dead_code)]
pub enum Partial {
    Kind(Kind),
    Anchor(Anchor),
    Offset(Offset),
    Object(TextObject),
    Action(Action),
}

#[derive(Copy, Debug)]
#[allow(dead_code)]
pub enum Action {
    Operation(Operation),
    Instruction(Instruction),
}

/// A complete, actionable command
#[derive(Copy, Debug)]
pub struct Command {
    pub number: i32,        // numeric paramter, line number, repeat count, etc.
    pub action: Action,     // what to do
    pub object: TextObject, // where to do it
}

impl Command {
    /// Shortcut to create an ExitEditor command
    pub fn exit_editor() -> Command {
        Command {
            action: Action::Instruction(Instruction::ExitEditor),
            number: 0,
            object: TextObject {
                kind: Kind::Char,
                offset: Offset::Absolute(0),
            },
        }
    }

    /// Shortcut to create a SaveBuffer command
    pub fn save_buffer() -> Command {
        Command {
            action: Action::Instruction(Instruction::SaveBuffer),
            number: 0,
            object: TextObject {
                kind: Kind::Char,
                offset: Offset::Absolute(0),
            },
        }
    }
}

pub struct Builder {
    number: Option<i32>,
    repeat: Option<usize>,

    action: Option<Action>,
    mark: Option<Mark>,
    kind: Option<Kind>,
    anchor: Option<Anchor>,
    offset: Option<Offset>,
    object: Option<TextObject>,

    reading_number: bool,
    keymap: KeyMap<Partial>,
}

#[derive(Copy, Debug)]
pub enum BuilderEvent {
    Invalid,            // cannot find a valid interpretation
    Incomplete,         // needs more information
    Complete(Command),  // command is finished
}

impl Builder {
    pub fn new() -> Builder {
        Builder {
            number: None,
            repeat: None,
            action: None,
            mark: None,
            kind: None,
            anchor: None,
            offset: None,
            object: None,
            reading_number: false,
            keymap: default_keymap()
        }
    }

    pub fn reset(&mut self) {
        self.number = None;
        self.repeat = None;
        self.action = None;
        self.mark = None;
        self.kind = None;
        self.anchor = None;
        self.object = None;
        self.offset = None;
        self.reading_number = false;
    }

    pub fn check_key(&mut self, key: Key) -> BuilderEvent {
        if let Key::Char(c) = key {
            // '0' might be bound (start of line), and cannot be the start of a number sequence
            if c.is_digit(10) && (self.reading_number || c != '0') {
                let n = c.to_digit(10).unwrap();
                self.reading_number = true;
                self.append_digit(n);
                return BuilderEvent::Incomplete;
            } else if self.reading_number {

                self.reading_number = false;
            }
        }

        match self.keymap.check_key(key) {
            KeyMapState::Match(partial) => self.apply_partial(partial),
            KeyMapState::None           => { self.reset(); return BuilderEvent::Invalid; }
            _ => {},
        }

        if let Some(c) = self.complete_command() {
            self.reset();
            return BuilderEvent::Complete(c)
        } else {
            return BuilderEvent::Incomplete
        }
    }

    fn complete_object(&mut self) -> Option<TextObject> {
        let mut result: Option<TextObject> = if let Some(object) = self.object {
            // we have a complete object ready to go
            Some(object)
        } else if let Some(kind) = self.kind {
            // we have at least a kind
            Some(TextObject {
                kind: kind,
                offset: self.offset.unwrap_or(Offset::Absolute(0)),
            })
        } else {
            None
        };

        if let Some(ref mut object) = result {
            if let Some(number) = self.number {
                object.offset = object.offset.with_num(number as usize);
            }
        }

        result
    }

    fn complete_command(&mut self) -> Option<Command> {
        /* rules for completing commands:
              | action            | number | object | reference    | kind |   | result                                                            |
              | -                 | -      | -      | -            | -    | - | -                                                                 |
              | no                | no     | no     | no           | yes  |   | move cursor to next (default) text object with kind               |
              | no                | no     | no     | yes          | -    |   | move cursor to text object with reference + default anchor        |
              | no                | no     | yes    | -            | -    |   | move cursor to text object                                        |
              | no                | yes    | no     | no           | no   |   | incomplete                                                        |
              | no                | yes    | no     | no           | yes  |   | move cursor to nth instance of kind (from start of buffer)        |
              | no                | yes    | no     | yes (index)  | -    |   | set index to number, cursor to ref + default anchor               |
              | no                | yes    | no     | yes (offset) | -    |   | multiply offset by number, cursor to ref + default anchor         |
              | no                | yes    | no     | yes (mark)   | -    |   | incomplete                                                        |
              | yes (instruction) | -      | -      | -            | -    |   | send instruction to editor with whatever parameters are available |
              | yes (operation)   | no     | no     | no           | no   |   | incomplete                                                        |
              | yes (operation)   | no     | no     | no           | yes  |   | apply operation to kind at cursor (default anchor)                |
              | yes (operation)   | no     | no     | yes          | -    |   | apply operation to reference with default anchor                  |
              | yes (operation)   | no     | yes    | -            | -    |   | apply operation to object                                         |
              | yes (operation)   | yes    | no     | no           | no   |   | incomplete                                                        |
              | yes (operation)   | yes    | no     | no           | yes  |   | apply operation to nth instance of kind                           |
        */

        // editor instructions may not need a text object, go ahead and return immediately
        if let Some(Action::Instruction(i)) = self.action {
            return Some(Command {
                number: self.repeat.unwrap_or(0) as i32,
                action: Action::Instruction(i),
                object: self.complete_object().unwrap_or_default()
            });
        }

        if let Some(to) = self.complete_object() {
            if let Some(Action::Operation(o)) = self.action {
                // we have an object, and an operation
                return Some(Command {
                    number: self.repeat.unwrap_or(0) as i32,
                    action: Action::Operation(o),
                    object: to
                });
            } else {
                // we have just an object, assume move cursor instruction
                return Some(Command {
                    number: self.repeat.unwrap_or(0) as i32,
                    action: Action::Instruction(Instruction::SetMark(Mark::Cursor(0))),
                    object: to
                });
            }
        }
        None
    }

    fn append_digit(&mut self, n: usize) {
        if let Some(current) = self.number {
            self.number = Some((current*10) + n as i32);
        } else {
            self.number = Some(n as i32);
        }
    }

    fn apply_partial(&mut self, partial: Partial) {
        match partial {
            Partial::Kind(k)      => self.kind = Some(k),
            Partial::Anchor(a)    => self.anchor = Some(a),
            Partial::Offset(o)    => self.offset = Some(o),
            Partial::Object(o)    => self.object = Some(o),
            Partial::Action(a)    => {
                self.action = Some(a);
                if !self.reading_number && self.number.is_some() && self.repeat.is_none() {
                    // the first number followed by an action is treated as a repetition
                    self.repeat = Some(self.number.unwrap() as usize);
                    self.number = None;
                }
            }
        }

        // propagate upwards from anchor to object
        // if both an object(a) and an anchor(b) have been applied, the resulting
        // object should be exactly the same as (a), only using (b) as the anchor
        if let Some(anchor) = self.anchor {
            if let Some(kind) = self.kind {
                self.kind = Some(kind.with_anchor(anchor));
            }
            if let Some(object) = self.object {
                self.object = Some(TextObject {
                    kind: object.kind.with_anchor(anchor),
                    offset: object.offset,
                });
            }
        }
        if let Some(kind) = self.kind {
            if let Some(ref mut object) = self.object {
                object.kind = kind;
            }
        }
        if let Some(offset) = self.offset {
            if let Some(ref mut object) = self.object {
                object.offset = offset;
            }
        }

        // propagate downwards from object to unset partials
        if let Some(object) = self.object {
            if self.offset.is_none() { self.offset = Some(object.offset); }
            if self.kind.is_none() { self.kind = Some(object.kind); }
            if self.anchor.is_none() { self.anchor = Some(object.kind.get_anchor()); }
        }

        if self.offset.is_some() && self.kind.is_some() && self.object.is_none() {
            self.object = Some(TextObject {
                kind: self.kind.unwrap(),
                offset: self.offset.unwrap(),
            });
        }
    }
}

fn default_keymap() -> KeyMap<Partial> {
    let mut keymap = KeyMap::new();

    // next/previous char
    keymap.bind_key(Key::Char('l'), Partial::Object(TextObject {
        kind: Kind::Char,
        offset: Offset::Forward(1, Mark::Cursor(0))
    }));
    keymap.bind_key(Key::Char('h'), Partial::Object(TextObject {
        kind: Kind::Char,
        offset: Offset::Backward(1, Mark::Cursor(0))
    }));

    // next/previous line
    keymap.bind_key(Key::Char('j'), Partial::Object(TextObject {
        kind: Kind::Line(Anchor::Same),
        offset: Offset::Forward(1, Mark::Cursor(0))
    }));
    keymap.bind_key(Key::Char('k'), Partial::Object(TextObject {
        kind: Kind::Line(Anchor::Same),
        offset: Offset::Backward(1, Mark::Cursor(0))
    }));

    // next/previous word
    keymap.bind_key(Key::Char('w'), Partial::Object(TextObject {
        kind: Kind::Word(Anchor::Before),
        offset: Offset::Forward(1, Mark::Cursor(0))
    }));
    keymap.bind_key(Key::Char('b'), Partial::Object(TextObject {
        kind: Kind::Word(Anchor::Before),
        offset: Offset::Backward(1, Mark::Cursor(0))
    }));

    // kinds
    keymap.bind_keys(&[Key::Char('`'), Key::Char('c')], Partial::Kind(Kind::Char));
    keymap.bind_keys(&[Key::Char('`'), Key::Char('w')], Partial::Kind(Kind::Word(Anchor::Before)));
    keymap.bind_keys(&[Key::Char('`'), Key::Char('l')], Partial::Kind(Kind::Line(Anchor::Before)));

    // anchors
    keymap.bind_key(Key::Char(','), Partial::Anchor(Anchor::Before));
    keymap.bind_key(Key::Char('.'), Partial::Anchor(Anchor::After));

    // actions
    keymap.bind_key(Key::Char('d'), Partial::Action(Action::Operation(Operation::Delete)));
    keymap.bind_key(Key::Char(':'), Partial::Action(Action::Instruction(Instruction::SetOverlay(OverlayType::Prompt))));

    keymap
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015-2016 Torrie Fischer <tdfischer@hackerbots.net>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use std::str::FromStr;

#[derive(Debug)]
pub enum Command {
    Nick,
    User,
    Join,
    Part,
    Quit,
    Ping,
    Mode,
    Pong,
    Pass,
    Privmsg,
    Topic,
    Numeric(u32),
    Unknown(String)
}

impl Command {
    pub fn as_string(&self) -> String {
        match self {
            &Command::Nick => "NICK".to_string(),
            &Command::Join => "JOIN".to_string(),
            &Command::Part => "PART".to_string(),
            &Command::Pong => "PONG".to_string(),
            &Command::Privmsg => "PRIVMSG".to_string(),
            &Command::User => "USER".to_string(),
            &Command::Quit => "QUIT".to_string(),
            &Command::Ping => "PING".to_string(),
            &Command::Mode => "MODE".to_string(),
            &Command::Pass => "PASS".to_string(),
            &Command::Topic => "TOPIC".to_string(),
            &Command::Numeric(n)=> format!("{:0>3}", n),
            &Command::Unknown(ref s) => s.clone()
        }
    }
}

impl Message {
    pub fn to_string(&self) -> String {
        let mut ret = String::new();
        match self.prefix {
            Some(ref pfx) => {
                ret.push(':');
                ret.push_str(pfx.trim());
                ret.push(' ');
            },
            None => ()
        };
        ret.push_str(self.command.as_string().trim());
        for ref arg in self.args.iter() {
            ret.push(' ');
            ret.push_str(arg.trim());
        }

        match self.suffix {
            Some(ref sfx) => {
                ret.push_str(" :");
                ret.push_str(sfx.trim());
            },
            None => ()
        };

        return ret;
    }

    fn split_parts(line: &str) -> (Option<String>, &str, Option<String>) {
        let mut prefix_end = 0;
        let mut args_end = 0;
        if line.chars().nth(0).unwrap() == ':' {
            for c in line[1..].chars() {
                prefix_end += 1;
                if c == ' ' {
                    break
                }
            }
        }

        let mut found_space = false;
        for c in line[prefix_end..].chars() {
            if c == ' ' {
                found_space = true;
            } else if c == ':' && found_space {
                args_end -= 1;
                break
            } else {
                found_space = false;
            }
            args_end += 1;
        }

        let prefix = match prefix_end {
            0 => None,
            _ => Some(line[1..prefix_end].to_string())
        };
        let args = &line[prefix_end..args_end].trim();
        let len = line.len();
        let suffix = if args_end == len {
            None
        } else {
            Some(line[args_end+2..].to_string())
        };

        (prefix, args, suffix)
    }

    pub fn from_str(line: &str) -> Self {
        let parts = Self::split_parts(line.trim());
        let split: Vec<&str> = parts.1.split(" ").collect();
        let mut args = Vec::new();
        for s in split[1..].iter() {
            args.push(s.to_string());
        }
        let parsed_command: Result<Command, Command> = split[0].parse();
        Message{
            prefix: parts.0,
            command: parsed_command.ok().unwrap(),
            args: args,
            suffix: parts.2
        }
    }
}

impl From<Command> for Message {
    fn from(c: Command) -> Message {
        Message {
            prefix: None,
            command: c,
            args: vec![],
            suffix: None
        }
    }
}

impl FromStr for Command {
    type Err = Command;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "NICK" => Ok(Command::Nick),
            "USER" => Ok(Command::User),
            "JOIN" => Ok(Command::Join),
            "PART" => Ok(Command::Part),
            "QUIT" => Ok(Command::Quit),
            "PING" => Ok(Command::Ping),
            "MODE" => Ok(Command::Mode),
            "PASS" => Ok(Command::Pass),
            "TOPIC" => Ok(Command::Topic),
            "PRIVMSG" => Ok(Command::Privmsg),
            _ => Ok(Command::Unknown(s.to_string()))
        }
    }
}

#[derive(Debug)]
pub struct Message {
    pub prefix: Option<String>,
    pub command: Command,
    pub args: Vec<String>,
    pub suffix: Option<String>
}
<commit_msg>Add a basic IRC parsing test.<commit_after>/*
 * Copyright 2015-2016 Torrie Fischer <tdfischer@hackerbots.net>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use std::str::FromStr;

#[derive(Debug,PartialEq,Eq)]
pub enum Command {
    Nick,
    User,
    Join,
    Part,
    Quit,
    Ping,
    Mode,
    Pong,
    Pass,
    Privmsg,
    Topic,
    Numeric(u32),
    Unknown(String)
}

impl Command {
    pub fn as_string(&self) -> String {
        match self {
            &Command::Nick => "NICK".to_string(),
            &Command::Join => "JOIN".to_string(),
            &Command::Part => "PART".to_string(),
            &Command::Pong => "PONG".to_string(),
            &Command::Privmsg => "PRIVMSG".to_string(),
            &Command::User => "USER".to_string(),
            &Command::Quit => "QUIT".to_string(),
            &Command::Ping => "PING".to_string(),
            &Command::Mode => "MODE".to_string(),
            &Command::Pass => "PASS".to_string(),
            &Command::Topic => "TOPIC".to_string(),
            &Command::Numeric(n)=> format!("{:0>3}", n),
            &Command::Unknown(ref s) => s.clone()
        }
    }
}

impl Message {
    pub fn to_string(&self) -> String {
        let mut ret = String::new();
        match self.prefix {
            Some(ref pfx) => {
                ret.push(':');
                ret.push_str(pfx.trim());
                ret.push(' ');
            },
            None => ()
        };
        ret.push_str(self.command.as_string().trim());
        for ref arg in self.args.iter() {
            ret.push(' ');
            ret.push_str(arg.trim());
        }

        match self.suffix {
            Some(ref sfx) => {
                ret.push_str(" :");
                ret.push_str(sfx.trim());
            },
            None => ()
        };

        return ret;
    }

    fn split_parts(line: &str) -> (Option<String>, &str, Option<String>) {
        let mut prefix_end = 0;
        let mut args_end = 0;
        if line.chars().nth(0).unwrap() == ':' {
            for c in line[1..].chars() {
                prefix_end += 1;
                if c == ' ' {
                    break
                }
            }
        }

        let mut found_space = false;
        for c in line[prefix_end..].chars() {
            if c == ' ' {
                found_space = true;
            } else if c == ':' && found_space {
                args_end -= 1;
                break
            } else {
                found_space = false;
            }
            args_end += 1;
        }

        let prefix = match prefix_end {
            0 => None,
            _ => Some(line[1..prefix_end].to_string())
        };
        let args = &line[prefix_end..args_end].trim();
        let len = line.len();
        let suffix = if args_end == len {
            None
        } else {
            Some(line[args_end+2..].to_string())
        };

        (prefix, args, suffix)
    }

    pub fn from_str(line: &str) -> Self {
        let parts = Self::split_parts(line.trim());
        let split: Vec<&str> = parts.1.split(" ").collect();
        let mut args = Vec::new();
        for s in split[1..].iter() {
            args.push(s.to_string());
        }
        let parsed_command: Result<Command, Command> = split[0].parse();
        Message{
            prefix: parts.0,
            command: parsed_command.ok().unwrap(),
            args: args,
            suffix: parts.2
        }
    }
}

impl From<Command> for Message {
    fn from(c: Command) -> Message {
        Message {
            prefix: None,
            command: c,
            args: vec![],
            suffix: None
        }
    }
}

impl FromStr for Command {
    type Err = Command;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "NICK" => Ok(Command::Nick),
            "USER" => Ok(Command::User),
            "JOIN" => Ok(Command::Join),
            "PART" => Ok(Command::Part),
            "QUIT" => Ok(Command::Quit),
            "PING" => Ok(Command::Ping),
            "MODE" => Ok(Command::Mode),
            "PASS" => Ok(Command::Pass),
            "TOPIC" => Ok(Command::Topic),
            "PRIVMSG" => Ok(Command::Privmsg),
            _ => Ok(Command::Unknown(s.to_string()))
        }
    }
}

#[derive(Debug)]
pub struct Message {
    pub prefix: Option<String>,
    pub command: Command,
    pub args: Vec<String>,
    pub suffix: Option<String>
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn classic_irc_session() {
        let msg = Message::from_str("USER nick 0 * hostname");
        assert_eq!(msg.prefix, None);
        assert_eq!(msg.command, Command::User);
        assert_eq!(msg.args, &["nick", "0", "*", "hostname"]);
        assert_eq!(msg.suffix, None);

        let msg = Message::from_str("NICK nick");
        assert_eq!(msg.prefix, None);
        assert_eq!(msg.command, Command::Nick);
        assert_eq!(msg.args, &["nick"]);
        assert_eq!(msg.suffix, None);

        let msg = Message::from_str(":nick!nick@hostname JOIN #foo");
        assert_eq!(msg.prefix, Some("nick!nick@hostname".to_owned()));
        assert_eq!(msg.command, Command::Join);
        assert_eq!(msg.args, &["#foo"]);
        assert_eq!(msg.suffix, None);

        let msg = Message::from_str(":nick!nick@hostname PRIVMSG #foo :Hello World!");
        assert_eq!(msg.prefix, Some("nick!nick@hostname".to_owned()));
        assert_eq!(msg.command, Command::Privmsg);
        assert_eq!(msg.args, &["#foo"]);
        assert_eq!(msg.suffix, Some("Hello World!".to_owned()));
    }

    #[test]
    fn weird_cases() {
        let msg = Message::from_str("USER nick:name 0 * hostname");
        assert_eq!(msg.prefix, None);
        assert_eq!(msg.command, Command::User);
        assert_eq!(msg.args, &["nick:name", "0", "*", "hostname"]);
        assert_eq!(msg.suffix, None);

        let msg = Message::from_str("USER  nick  0  *  hostname");
        assert_eq!(msg.prefix, None);
        assert_eq!(msg.command, Command::User);
        assert_eq!(msg.args, &["", "nick", "", "0", "", "*", "", "hostname"]);
        assert_eq!(msg.suffix, None);
    }
}<|endoftext|>


<commit_before>use std::collections::{BitSet, BTreeSet};
use std::cell::{RefCell, Ref, RefMut};

use value::{Id};
use relation::{Change, Relation};
use view::{View, Table};
use compiler;

#[derive(Clone, Debug)]
pub struct Node {
    pub id: Id,
    pub view: View,
    pub upstream: Vec<usize>,
    pub downstream: Vec<usize>,
}

pub type Changes = Vec<(Id, Change)>;

#[derive(Clone, Debug)]
pub struct Flow {
    pub nodes: Vec<Node>,
    pub outputs: Vec<RefCell<Relation>>,
    pub dirty: BitSet,
    pub needs_recompile: bool,
}

impl Flow {
    pub fn new() -> Self {
        let mut flow = Flow {
            nodes: Vec::new(),
            outputs: Vec::new(),
            dirty: BitSet::new(),
            needs_recompile: true,
        };
        compiler::bootstrap(&mut flow);
        flow
    }

    pub fn get_ix(&self, id: &str) -> Option<usize> {
        self.nodes.iter().position(|node| &node.id[..] == id)
    }

    pub fn get_node(&self, id: &str) -> &Node {
        self.nodes.iter().find(|node| &node.id[..] == id).unwrap()
    }

    pub fn get_output(&self, id: &str) -> Ref<Relation> {
        self.outputs[self.get_ix(id).unwrap()].borrow()
    }

    pub fn get_output_mut(&self, id: &str) -> RefMut<Relation> {
        self.outputs[self.get_ix(id).unwrap()].borrow_mut()
    }

    pub fn overwrite_output(&self, id: &str) -> RefMut<Relation> {
        let mut output = self.get_output_mut(id);
        output.index = BTreeSet::new();
        output
    }

    pub fn change(&mut self, changes: Changes) {
        let code_schema = compiler::code_schema();
        for (id, change) in changes.into_iter() {
            match self.get_ix(&*id) {
                Some(ix) => {
                    match self.nodes[ix].view {
                        View::Table(_) => (),
                        _ => println!("Warning: changing a non-table view with id: {:?}", id),
                    }
                    // TODO should we be checking diffs after the fact?
                    self.outputs[ix].borrow_mut().change(change);
                    if code_schema.iter().find(|&&(ref code_id, _)| **code_id == id).is_some() {
                        self.needs_recompile = true;
                    }
                    for ix in self.nodes[ix].downstream.iter() {
                        self.dirty.insert(*ix);
                    }
                }
                None => {
                    println!("Warning: creating a dummy view because you tried to change a non-existing view with id: {:?}", id);
                    self.nodes.push(Node{
                        id: id.to_owned(),
                        view: View::Table(Table{
                            insert:None,
                            remove:None,
                        }),
                        upstream: Vec::new(),
                        downstream: Vec::new(),
                    });
                    let fields = change.fields.clone();
                    // compiler tables will never be missing, so it's safe to just put dummy names in here
                    let names = change.fields.iter().map(|_| "".to_owned()).collect();
                    self.outputs.push(RefCell::new(Relation::new(id.to_owned(), fields, names)));
                    self.outputs[self.outputs.len()-1].borrow_mut().change(change);
                }
            }
        }
    }

    pub fn as_changes(&self) -> Changes {
        (0..self.nodes.len()).map(|ix|
            (
                self.nodes[ix].id.clone(),
                self.outputs[ix].borrow().as_insert()
            )
        ).collect()
    }

    pub fn changes_from(&self, old_self: Self) -> Changes {
        let mut changes = Vec::new();
        for (ix, node) in self.nodes.iter().enumerate() {
            match old_self.get_ix(&node.id[..]) {
                Some(old_ix) => {
                    let new_output = self.outputs[ix].borrow();
                    let old_output = old_self.outputs[old_ix].borrow();
                    if new_output.fields == old_output.fields {
                        let change = new_output.change_from(&*old_output);
                        changes.push((node.id.clone(), change));
                    } else {
                        changes.push((node.id.clone(), old_output.as_remove()));
                        changes.push((node.id.clone(), new_output.as_insert()));
                    }
                }
                None => {
                    let new_output = self.outputs[ix].borrow();
                    changes.push((node.id.clone(), new_output.as_insert()));
                }
            }
        }
        for (old_ix, old_node) in old_self.nodes.iter().enumerate() {
            match self.get_ix(&old_node.id[..]) {
                Some(_) => {
                    () // already handled above
                }
                None => {
                    let old_output = old_self.outputs[old_ix].borrow();
                    changes.push((old_node.id.clone(), old_output.as_remove()));
                }
            }
        }
        changes
    }

    pub fn recalculate(&mut self) {
        let Flow{ref nodes, ref mut outputs, ref mut dirty, ..} = *self;
        let code_schema = compiler::code_schema();
        while let Some(ix) = dirty.iter().next() {
            dirty.remove(&ix);
            let node = &nodes[ix];
            let new_output = {
                let upstream = node.upstream.iter().map(|&ix| outputs[ix].borrow()).collect::<Vec<_>>();
                let inputs = upstream.iter().map(|borrowed| &**borrowed).collect::<Vec<_>>();
                node.view.run(&*outputs[ix].borrow(), &inputs[..])
            };
            match new_output {
                None => (), // view does not want to update
                Some(new_output) => {
                    let change = new_output.change_from(&*outputs[ix].borrow());
                    if (change.insert.len() != 0) || (change.remove.len() != 0) {
                        if code_schema.iter().find(|&&(ref code_id, _)| **code_id == node.id).is_some() {
                            self.needs_recompile = true;
                        }
                        for ix in node.downstream.iter() {
                            dirty.insert(*ix);
                        }
                    }
                    outputs[ix] = RefCell::new(new_output);
                }
            }
        }
    }

    pub fn tick(&mut self) -> bool {
        let code_schema = compiler::code_schema();
        let mut flow_changed = false;
        for (ix, node) in self.nodes.iter().enumerate() {
            match node.view {
                View::Table(Table{ref insert, ref remove}) => {
                    let mut view_changed = false;
                    {
                        let upstream = node.upstream.iter().map(|ix| self.outputs[*ix].borrow()).collect::<Vec<_>>();
                        let inputs = upstream.iter().map(|borrowed| &**borrowed).collect::<Vec<_>>();
                        let mut inserts = match *insert {
                            Some(ref select) => select.select(&inputs[..]),
                            None => vec![],
                        };
                        let mut removes = match *remove {
                            Some(ref select) => select.select(&inputs[..]),
                            None => vec![],
                        };
                        inserts.sort();
                        removes.sort();
                        inserts.retain(|insert| removes.binary_search(&insert).is_err());
                        removes.retain(|remove| inserts.binary_search(&remove).is_err());
                        let mut output = self.outputs[ix].borrow_mut();
                        let mut index = &mut output.index;
                        for insert in inserts {
                            view_changed = view_changed || index.insert(insert);
                        }
                        for remove in removes {
                            view_changed = view_changed || index.remove(&remove);
                        }
                    }
                    if view_changed {
                        if code_schema.iter().find(|&&(ref code_id, _)| **code_id == node.id).is_some() {
                            self.needs_recompile = true;
                        }
                        for ix in node.downstream.iter() {
                            self.dirty.insert(*ix);
                        }
                    }
                    flow_changed = flow_changed || view_changed;
                }
                _ => () // only tables tick
            }
        }
        flow_changed
    }

    pub fn quiesce(&mut self, changes: Changes)  {
        time!("changing", {
            self.change(changes);
        });
        loop {
            if self.needs_recompile {
                time!("compiling", {
                    compiler::recompile(self);
                });
            }
            time!("calculating", {
                self.recalculate();
            });
            let changed = time!("ticking", {
                self.tick()
            });
            if !changed {
                break
            }
        }
    }
}
<commit_msg>Bugfix - boolean operators are lazy<commit_after>use std::collections::{BitSet, BTreeSet};
use std::cell::{RefCell, Ref, RefMut};

use value::{Id};
use relation::{Change, Relation};
use view::{View, Table};
use compiler;

#[derive(Clone, Debug)]
pub struct Node {
    pub id: Id,
    pub view: View,
    pub upstream: Vec<usize>,
    pub downstream: Vec<usize>,
}

pub type Changes = Vec<(Id, Change)>;

#[derive(Clone, Debug)]
pub struct Flow {
    pub nodes: Vec<Node>,
    pub outputs: Vec<RefCell<Relation>>,
    pub dirty: BitSet,
    pub needs_recompile: bool,
}

impl Flow {
    pub fn new() -> Self {
        let mut flow = Flow {
            nodes: Vec::new(),
            outputs: Vec::new(),
            dirty: BitSet::new(),
            needs_recompile: true,
        };
        compiler::bootstrap(&mut flow);
        flow
    }

    pub fn get_ix(&self, id: &str) -> Option<usize> {
        self.nodes.iter().position(|node| &node.id[..] == id)
    }

    pub fn get_node(&self, id: &str) -> &Node {
        self.nodes.iter().find(|node| &node.id[..] == id).unwrap()
    }

    pub fn get_output(&self, id: &str) -> Ref<Relation> {
        self.outputs[self.get_ix(id).unwrap()].borrow()
    }

    pub fn get_output_mut(&self, id: &str) -> RefMut<Relation> {
        self.outputs[self.get_ix(id).unwrap()].borrow_mut()
    }

    pub fn overwrite_output(&self, id: &str) -> RefMut<Relation> {
        let mut output = self.get_output_mut(id);
        output.index = BTreeSet::new();
        output
    }

    pub fn change(&mut self, changes: Changes) {
        let code_schema = compiler::code_schema();
        for (id, change) in changes.into_iter() {
            match self.get_ix(&*id) {
                Some(ix) => {
                    match self.nodes[ix].view {
                        View::Table(_) => (),
                        _ => println!("Warning: changing a non-table view with id: {:?}", id),
                    }
                    // TODO should we be checking diffs after the fact?
                    self.outputs[ix].borrow_mut().change(change);
                    if code_schema.iter().find(|&&(ref code_id, _)| **code_id == id).is_some() {
                        self.needs_recompile = true;
                    }
                    for ix in self.nodes[ix].downstream.iter() {
                        self.dirty.insert(*ix);
                    }
                }
                None => {
                    println!("Warning: creating a dummy view because you tried to change a non-existing view with id: {:?}", id);
                    self.nodes.push(Node{
                        id: id.to_owned(),
                        view: View::Table(Table{
                            insert:None,
                            remove:None,
                        }),
                        upstream: Vec::new(),
                        downstream: Vec::new(),
                    });
                    let fields = change.fields.clone();
                    // compiler tables will never be missing, so it's safe to just put dummy names in here
                    let names = change.fields.iter().map(|_| "".to_owned()).collect();
                    self.outputs.push(RefCell::new(Relation::new(id.to_owned(), fields, names)));
                    self.outputs[self.outputs.len()-1].borrow_mut().change(change);
                }
            }
        }
    }

    pub fn as_changes(&self) -> Changes {
        (0..self.nodes.len()).map(|ix|
            (
                self.nodes[ix].id.clone(),
                self.outputs[ix].borrow().as_insert()
            )
        ).collect()
    }

    pub fn changes_from(&self, old_self: Self) -> Changes {
        let mut changes = Vec::new();
        for (ix, node) in self.nodes.iter().enumerate() {
            match old_self.get_ix(&node.id[..]) {
                Some(old_ix) => {
                    let new_output = self.outputs[ix].borrow();
                    let old_output = old_self.outputs[old_ix].borrow();
                    if new_output.fields == old_output.fields {
                        let change = new_output.change_from(&*old_output);
                        changes.push((node.id.clone(), change));
                    } else {
                        changes.push((node.id.clone(), old_output.as_remove()));
                        changes.push((node.id.clone(), new_output.as_insert()));
                    }
                }
                None => {
                    let new_output = self.outputs[ix].borrow();
                    changes.push((node.id.clone(), new_output.as_insert()));
                }
            }
        }
        for (old_ix, old_node) in old_self.nodes.iter().enumerate() {
            match self.get_ix(&old_node.id[..]) {
                Some(_) => {
                    () // already handled above
                }
                None => {
                    let old_output = old_self.outputs[old_ix].borrow();
                    changes.push((old_node.id.clone(), old_output.as_remove()));
                }
            }
        }
        changes
    }

    pub fn recalculate(&mut self) {
        let Flow{ref nodes, ref mut outputs, ref mut dirty, ..} = *self;
        let code_schema = compiler::code_schema();
        while let Some(ix) = dirty.iter().next() {
            dirty.remove(&ix);
            let node = &nodes[ix];
            let new_output = {
                let upstream = node.upstream.iter().map(|&ix| outputs[ix].borrow()).collect::<Vec<_>>();
                let inputs = upstream.iter().map(|borrowed| &**borrowed).collect::<Vec<_>>();
                node.view.run(&*outputs[ix].borrow(), &inputs[..])
            };
            match new_output {
                None => (), // view does not want to update
                Some(new_output) => {
                    let change = new_output.change_from(&*outputs[ix].borrow());
                    if (change.insert.len() != 0) || (change.remove.len() != 0) {
                        if code_schema.iter().find(|&&(ref code_id, _)| **code_id == node.id).is_some() {
                            self.needs_recompile = true;
                        }
                        for ix in node.downstream.iter() {
                            dirty.insert(*ix);
                        }
                    }
                    outputs[ix] = RefCell::new(new_output);
                }
            }
        }
    }

    pub fn tick(&mut self) -> bool {
        let code_schema = compiler::code_schema();
        let mut flow_changed = false;
        for (ix, node) in self.nodes.iter().enumerate() {
            match node.view {
                View::Table(Table{ref insert, ref remove}) => {
                    let mut view_changed = false;
                    {
                        let upstream = node.upstream.iter().map(|ix| self.outputs[*ix].borrow()).collect::<Vec<_>>();
                        let inputs = upstream.iter().map(|borrowed| &**borrowed).collect::<Vec<_>>();
                        let mut inserts = match *insert {
                            Some(ref select) => select.select(&inputs[..]),
                            None => vec![],
                        };
                        let mut removes = match *remove {
                            Some(ref select) => select.select(&inputs[..]),
                            None => vec![],
                        };
                        inserts.sort();
                        removes.sort();
                        inserts.retain(|insert| removes.binary_search(&insert).is_err());
                        removes.retain(|remove| inserts.binary_search(&remove).is_err());
                        let mut output = self.outputs[ix].borrow_mut();
                        let mut index = &mut output.index;
                        for insert in inserts {
                            let inserted = index.insert(insert);
                            view_changed = view_changed || inserted;
                        }
                        for remove in removes {
                            let removed = index.remove(&remove);
                            view_changed = view_changed || removed;
                        }
                    }
                    if view_changed {
                        if code_schema.iter().find(|&&(ref code_id, _)| **code_id == node.id).is_some() {
                            self.needs_recompile = true;
                        }
                        for ix in node.downstream.iter() {
                            self.dirty.insert(*ix);
                        }
                    }
                    flow_changed = flow_changed || view_changed;
                }
                _ => () // only tables tick
            }
        }
        flow_changed
    }

    pub fn quiesce(&mut self, changes: Changes)  {
        time!("changing", {
            self.change(changes);
        });
        loop {
            if self.needs_recompile {
                time!("compiling", {
                    compiler::recompile(self);
                });
            }
            time!("calculating", {
                self.recalculate();
            });
            let changed = time!("ticking", {
                self.tick()
            });
            if !changed {
                break
            }
        }
    }
}
<|endoftext|>


<commit_before>// A variation on event-loop.rs.
//
// Here we:
//
// - Have the event loop be run by a `Resolver`, hiding away the event loop
// details from the writer of `main()`.
//
// - Transform the callback-based c-ares interface into a futures-style.
#[cfg(unix)]
mod example {
    extern crate c_ares;
    extern crate futures;
    extern crate mio;
    extern crate mio_extras;
    extern crate tokio;

    use std::collections::HashSet;
    use std::error::Error;
    use std::sync::{Arc, Mutex};
    use std::thread;
    use std::time::Duration;

    use self::futures::Future;
    use self::futures::future::lazy;
    use self::tokio::executor::current_thread;

    // The EventLoop will set up a mio::Poll and use it to wait for the following:
    //
    // -  messages telling it which file descriptors it should be interested in.
    //    These file descriptors are then registered (or deregistered) with the
    //    mio::Poll as required.
    //
    // -  events telling it that something has happened on one of these file
    //    descriptors.  When this happens, it tells the c_ares::Channel about it.
    //
    // -  a message telling it to shut down.
    struct EventLoop {
        poll: mio::Poll,
        msg_channel: mio_extras::channel::Receiver<Message>,
        tracked_fds: HashSet<c_ares::Socket>,
        ares_channel: Arc<Mutex<c_ares::Channel>>,
        quit: bool,
    }

    // Messages for the event loop.
    #[derive(Debug)]
    enum Message {
        // 'Notify me when this file descriptor becomes readable, or writable'.
        // The first bool is for 'readable' and the second is for 'writable'.  It's
        // allowed to set both of these - or neither, meaning 'I am no longer
        // interested in this file descriptor'.
        RegisterInterest(c_ares::Socket, bool, bool),

        // 'Shut down'.
        ShutDown,
    }

    // A token identifying that the message channel has become available for reading.
    //
    // We use Token(fd) for file descriptors, so this relies on zero not being a
    // valid file descriptor for c-ares to use.  Zero is stdin, so that's true.
    const CHANNEL: mio::Token = mio::Token(0);

    impl EventLoop {
        // Create a new event loop.
        pub fn new(
            ares_channel: Arc<Mutex<c_ares::Channel>>,
            rx: mio_extras::channel::Receiver<Message>,
        ) -> EventLoop {
            let poll = mio::Poll::new().expect("Failed to create poll");
            poll.register(&rx, CHANNEL, mio::Ready::readable(), mio::PollOpt::edge())
                .expect("failed to register channel with poll");

            EventLoop {
                poll,
                msg_channel: rx,
                tracked_fds: HashSet::<c_ares::Socket>::new(),
                ares_channel,
                quit: false,
            }
        }

        // Run the event loop.
        pub fn run(self) -> thread::JoinHandle<()> {
            thread::spawn(|| self.event_loop_thread())
        }

        // Event loop thread - waits for events, and handles them.
        fn event_loop_thread(mut self) {
            let mut events = mio::Events::with_capacity(16);
            loop {
                // Wait for something to happen.
                let timeout = Duration::from_millis(500);
                let results = self.poll
                    .poll(&mut events, Some(timeout))
                    .expect("poll failed");

                // Process whatever happened.
                match results {
                    0 => {
                        // No events - must be a timeout.  Tell c-ares about it.
                        self.ares_channel
                            .lock()
                            .unwrap()
                            .process_fd(c_ares::SOCKET_BAD, c_ares::SOCKET_BAD);
                    }
                    _ => {
                        // Process events.  One of them might have asked us to quit.
                        for event in &events {
                            self.handle_event(&event);
                            if self.quit {
                                return;
                            }
                        }
                    }
                }
            }
        }

        // Handle a single event.
        fn handle_event(&mut self, event: &mio::Event) {
            match event.token() {
                CHANNEL => {
                    // The channel is readable.
                    self.handle_messages()
                }

                mio::Token(fd) => {
                    // Sockets became readable or writable - tell c-ares.
                    let rfd = if event.readiness().is_readable() {
                        fd as c_ares::Socket
                    } else {
                        c_ares::SOCKET_BAD
                    };
                    let wfd = if event.readiness().is_writable() {
                        fd as c_ares::Socket
                    } else {
                        c_ares::SOCKET_BAD
                    };
                    self.ares_channel.lock().unwrap().process_fd(rfd, wfd);
                }
            }
        }

        // Process messages incoming on the channel.
        fn handle_messages(&mut self) {
            loop {
                match self.msg_channel.try_recv() {
                    Ok(Message::RegisterInterest(fd, readable, writable)) => {
                        // Instruction to do something with a file descriptor.
                        let efd = mio::unix::EventedFd(&fd);
                        if !readable && !writable {
                            self.tracked_fds.remove(&fd);
                            self.poll
                                .deregister(&efd)
                                .expect("failed to deregister interest");
                        } else {
                            let token = mio::Token(fd as usize);
                            let mut interest = mio::Ready::empty();
                            if readable {
                                interest.insert(mio::Ready::readable())
                            }
                            if writable {
                                interest.insert(mio::Ready::writable())
                            }
                            let register_result = if !self.tracked_fds.insert(fd) {
                                self.poll
                                    .reregister(&efd, token, interest, mio::PollOpt::level())
                            } else {
                                self.poll
                                    .register(&efd, token, interest, mio::PollOpt::level())
                            };
                            register_result.expect("failed to register interest");
                        }
                    }

                    Ok(Message::ShutDown) => {
                        // Instruction to shut down.
                        self.quit = true;
                        break;
                    }

                    // No more instructions.
                    Err(_) => break,
                }
            }
        }
    }

    // The type of future returned by methods on the Resolver.
    pub struct CAresFuture<T> {
        inner: futures::sync::oneshot::Receiver<c_ares::Result<T>>,
    }

    impl<T> CAresFuture<T> {
        fn new(promise: futures::sync::oneshot::Receiver<c_ares::Result<T>>) -> Self {
            CAresFuture { inner: promise }
        }
    }

    impl<T> Future for CAresFuture<T> {
        type Item = T;
        type Error = c_ares::Error;

        fn poll(&mut self) -> futures::Poll<Self::Item, Self::Error> {
            match self.inner.poll() {
                Ok(futures::Async::NotReady) => Ok(futures::Async::NotReady),
                Err(_) => Err(c_ares::Error::ECANCELLED),
                Ok(futures::Async::Ready(res)) => match res {
                    Ok(r) => Ok(futures::Async::Ready(r)),
                    Err(e) => Err(e),
                },
            }
        }
    }

    // The Resolver is the interface by which users make DNS queries.
    struct Resolver {
        ares_channel: Arc<Mutex<c_ares::Channel>>,
        event_loop_channel: mio_extras::channel::Sender<Message>,
        event_loop_handle: Option<thread::JoinHandle<()>>,
    }

    impl Resolver {
        // Create a new Resolver.
        pub fn new() -> Resolver {
            // Whenever c-ares tells us what to do with a file descriptor, we'll
            // send that request along, in a message to the event loop thread.
            let (tx, rx) = mio_extras::channel::channel();
            let tx_clone = tx.clone();
            let sock_callback = move |fd: c_ares::Socket, readable: bool, writable: bool| {
                let _ = tx_clone.send(Message::RegisterInterest(fd, readable, writable));
            };

            // Create a c_ares::Channel.
            let mut options = c_ares::Options::new();
            options
                .set_socket_state_callback(sock_callback)
                .set_flags(c_ares::Flags::STAYOPEN | c_ares::Flags::EDNS)
                .set_timeout(500)
                .set_tries(3);
            let mut ares_channel =
                c_ares::Channel::with_options(options).expect("Failed to create channel");
            ares_channel
                .set_servers(&["8.8.8.8"])
                .expect("Failed to set servers");
            let locked_channel = Arc::new(Mutex::new(ares_channel));

            // Create and run the event loop.
            let channel_clone = Arc::clone(&locked_channel);
            let event_loop = EventLoop::new(channel_clone, rx);
            let handle = event_loop.run();

            // Return the Resolver.
            Resolver {
                ares_channel: locked_channel,
                event_loop_channel: tx,
                event_loop_handle: Some(handle),
            }
        }

        // A CNAME query.  Returns a future that will resolve to hold the result.
        pub fn query_cname(&self, name: &str) -> CAresFuture<c_ares::CNameResults> {
            let (c, p) = futures::oneshot();
            self.ares_channel
                .lock()
                .unwrap()
                .query_cname(name, move |result| {
                    let _ = c.send(result);
                });
            CAresFuture::new(p)
        }

        // An MX query.  Returns a future that will resolve to hold the result.
        pub fn query_mx(&self, name: &str) -> CAresFuture<c_ares::MXResults> {
            let (c, p) = futures::oneshot();
            self.ares_channel
                .lock()
                .unwrap()
                .query_mx(name, move |result| {
                    let _ = c.send(result);
                });
            CAresFuture::new(p)
        }

        // A NAPTR query.  Returns a future that will resolve to hold the result.
        pub fn query_naptr(&self, name: &str) -> CAresFuture<c_ares::NAPTRResults> {
            let (c, p) = futures::oneshot();
            self.ares_channel
                .lock()
                .unwrap()
                .query_naptr(name, move |result| {
                    let _ = c.send(result);
                });
            CAresFuture::new(p)
        }
    }

    impl Drop for Resolver {
        fn drop(&mut self) {
            // Shut down the event loop and wait for it to finish.
            self.event_loop_channel
                .send(Message::ShutDown)
                .expect("failed to request event loop to shut down");
            if let Some(handle) = self.event_loop_handle.take() {
                handle.join().expect("failed to shut down event loop");
            }
        }
    }

    pub fn main() {
        // Create a Resolver, and some queries.
        let resolver = Resolver::new();
        let cname_query = resolver
            .query_cname("dimbleby.github.io")
            .map_err(|e| println!("CNAME lookup failed with error '{}'", e.description()))
            .map(|results| {
                println!();
                println!("Successful CNAME lookup...");
                println!("Hostname: {}", results.hostname());
                for alias in results.aliases() {
                    println!("Alias: {}", alias);
                }
                println!();
            });

        let mx_query = resolver
            .query_mx("gmail.com")
            .map_err(|e| println!("MX lookup failed with error '{}'", e.description()))
            .map(|results| {
                println!();
                println!("Successful MX lookup...");
                for result in &results {
                    println!("host {}, priority {}", result.host(), result.priority());
                }
                println!();
            });

        let naptr_query = resolver
            .query_naptr("apple.com")
            .map_err(|e| println!("NAPTR lookup failed with error '{}'", e.description()))
            .map(|results| {
                println!();
                println!("Successful NAPTR lookup...");
                for result in &results {
                    println!("flags: {}", result.flags());
                    println!("service name: {}", result.service_name());
                    println!("regular expression: {}", result.reg_exp());
                    println!("replacement pattern: {}", result.replacement_pattern());
                    println!("order: {}", result.order());
                    println!("preference: {}", result.preference());
                }
                println!();
            });

        // Execute the queries.
        current_thread::block_on_all(lazy(|| {
            current_thread::spawn(cname_query);
            current_thread::spawn(mx_query);
            current_thread::spawn(naptr_query);
            Ok::<(), ()>(())
        })).unwrap();
    }
}

#[cfg(unix)]
pub fn main() {
    example::main();
}

#[cfg(not(unix))]
pub fn main() {
    println!("this example is not supported on this platform");
}
<commit_msg>reference c-ares-resolver from futures example<commit_after>// A variation on event-loop.rs.
//
// Here we:
//
// - Have the event loop be run by a `Resolver`, hiding away the event loop
// details from the writer of `main()`.
//
// - Transform the callback-based c-ares interface into a futures-style.
//
// This example is fleshed out in the
// [c-ares-resolver](https://github.com/dimbleby/c-ares-resolver) crate.
#[cfg(unix)]
mod example {
    extern crate c_ares;
    extern crate futures;
    extern crate mio;
    extern crate mio_extras;
    extern crate tokio;

    use std::collections::HashSet;
    use std::error::Error;
    use std::sync::{Arc, Mutex};
    use std::thread;
    use std::time::Duration;

    use self::futures::Future;
    use self::futures::future::lazy;
    use self::tokio::executor::current_thread;

    // The EventLoop will set up a mio::Poll and use it to wait for the following:
    //
    // -  messages telling it which file descriptors it should be interested in.
    //    These file descriptors are then registered (or deregistered) with the
    //    mio::Poll as required.
    //
    // -  events telling it that something has happened on one of these file
    //    descriptors.  When this happens, it tells the c_ares::Channel about it.
    //
    // -  a message telling it to shut down.
    struct EventLoop {
        poll: mio::Poll,
        msg_channel: mio_extras::channel::Receiver<Message>,
        tracked_fds: HashSet<c_ares::Socket>,
        ares_channel: Arc<Mutex<c_ares::Channel>>,
        quit: bool,
    }

    // Messages for the event loop.
    #[derive(Debug)]
    enum Message {
        // 'Notify me when this file descriptor becomes readable, or writable'.
        // The first bool is for 'readable' and the second is for 'writable'.  It's
        // allowed to set both of these - or neither, meaning 'I am no longer
        // interested in this file descriptor'.
        RegisterInterest(c_ares::Socket, bool, bool),

        // 'Shut down'.
        ShutDown,
    }

    // A token identifying that the message channel has become available for reading.
    //
    // We use Token(fd) for file descriptors, so this relies on zero not being a
    // valid file descriptor for c-ares to use.  Zero is stdin, so that's true.
    const CHANNEL: mio::Token = mio::Token(0);

    impl EventLoop {
        // Create a new event loop.
        pub fn new(
            ares_channel: Arc<Mutex<c_ares::Channel>>,
            rx: mio_extras::channel::Receiver<Message>,
        ) -> EventLoop {
            let poll = mio::Poll::new().expect("Failed to create poll");
            poll.register(&rx, CHANNEL, mio::Ready::readable(), mio::PollOpt::edge())
                .expect("failed to register channel with poll");

            EventLoop {
                poll,
                msg_channel: rx,
                tracked_fds: HashSet::<c_ares::Socket>::new(),
                ares_channel,
                quit: false,
            }
        }

        // Run the event loop.
        pub fn run(self) -> thread::JoinHandle<()> {
            thread::spawn(|| self.event_loop_thread())
        }

        // Event loop thread - waits for events, and handles them.
        fn event_loop_thread(mut self) {
            let mut events = mio::Events::with_capacity(16);
            loop {
                // Wait for something to happen.
                let timeout = Duration::from_millis(500);
                let results = self.poll
                    .poll(&mut events, Some(timeout))
                    .expect("poll failed");

                // Process whatever happened.
                match results {
                    0 => {
                        // No events - must be a timeout.  Tell c-ares about it.
                        self.ares_channel
                            .lock()
                            .unwrap()
                            .process_fd(c_ares::SOCKET_BAD, c_ares::SOCKET_BAD);
                    }
                    _ => {
                        // Process events.  One of them might have asked us to quit.
                        for event in &events {
                            self.handle_event(&event);
                            if self.quit {
                                return;
                            }
                        }
                    }
                }
            }
        }

        // Handle a single event.
        fn handle_event(&mut self, event: &mio::Event) {
            match event.token() {
                CHANNEL => {
                    // The channel is readable.
                    self.handle_messages()
                }

                mio::Token(fd) => {
                    // Sockets became readable or writable - tell c-ares.
                    let rfd = if event.readiness().is_readable() {
                        fd as c_ares::Socket
                    } else {
                        c_ares::SOCKET_BAD
                    };
                    let wfd = if event.readiness().is_writable() {
                        fd as c_ares::Socket
                    } else {
                        c_ares::SOCKET_BAD
                    };
                    self.ares_channel.lock().unwrap().process_fd(rfd, wfd);
                }
            }
        }

        // Process messages incoming on the channel.
        fn handle_messages(&mut self) {
            loop {
                match self.msg_channel.try_recv() {
                    Ok(Message::RegisterInterest(fd, readable, writable)) => {
                        // Instruction to do something with a file descriptor.
                        let efd = mio::unix::EventedFd(&fd);
                        if !readable && !writable {
                            self.tracked_fds.remove(&fd);
                            self.poll
                                .deregister(&efd)
                                .expect("failed to deregister interest");
                        } else {
                            let token = mio::Token(fd as usize);
                            let mut interest = mio::Ready::empty();
                            if readable {
                                interest.insert(mio::Ready::readable())
                            }
                            if writable {
                                interest.insert(mio::Ready::writable())
                            }
                            let register_result = if !self.tracked_fds.insert(fd) {
                                self.poll
                                    .reregister(&efd, token, interest, mio::PollOpt::level())
                            } else {
                                self.poll
                                    .register(&efd, token, interest, mio::PollOpt::level())
                            };
                            register_result.expect("failed to register interest");
                        }
                    }

                    Ok(Message::ShutDown) => {
                        // Instruction to shut down.
                        self.quit = true;
                        break;
                    }

                    // No more instructions.
                    Err(_) => break,
                }
            }
        }
    }

    // The type of future returned by methods on the Resolver.
    pub struct CAresFuture<T> {
        inner: futures::sync::oneshot::Receiver<c_ares::Result<T>>,
    }

    impl<T> CAresFuture<T> {
        fn new(promise: futures::sync::oneshot::Receiver<c_ares::Result<T>>) -> Self {
            CAresFuture { inner: promise }
        }
    }

    impl<T> Future for CAresFuture<T> {
        type Item = T;
        type Error = c_ares::Error;

        fn poll(&mut self) -> futures::Poll<Self::Item, Self::Error> {
            match self.inner.poll() {
                Ok(futures::Async::NotReady) => Ok(futures::Async::NotReady),
                Err(_) => Err(c_ares::Error::ECANCELLED),
                Ok(futures::Async::Ready(res)) => match res {
                    Ok(r) => Ok(futures::Async::Ready(r)),
                    Err(e) => Err(e),
                },
            }
        }
    }

    // The Resolver is the interface by which users make DNS queries.
    struct Resolver {
        ares_channel: Arc<Mutex<c_ares::Channel>>,
        event_loop_channel: mio_extras::channel::Sender<Message>,
        event_loop_handle: Option<thread::JoinHandle<()>>,
    }

    impl Resolver {
        // Create a new Resolver.
        pub fn new() -> Resolver {
            // Whenever c-ares tells us what to do with a file descriptor, we'll
            // send that request along, in a message to the event loop thread.
            let (tx, rx) = mio_extras::channel::channel();
            let tx_clone = tx.clone();
            let sock_callback = move |fd: c_ares::Socket, readable: bool, writable: bool| {
                let _ = tx_clone.send(Message::RegisterInterest(fd, readable, writable));
            };

            // Create a c_ares::Channel.
            let mut options = c_ares::Options::new();
            options
                .set_socket_state_callback(sock_callback)
                .set_flags(c_ares::Flags::STAYOPEN | c_ares::Flags::EDNS)
                .set_timeout(500)
                .set_tries(3);
            let mut ares_channel =
                c_ares::Channel::with_options(options).expect("Failed to create channel");
            ares_channel
                .set_servers(&["8.8.8.8"])
                .expect("Failed to set servers");
            let locked_channel = Arc::new(Mutex::new(ares_channel));

            // Create and run the event loop.
            let channel_clone = Arc::clone(&locked_channel);
            let event_loop = EventLoop::new(channel_clone, rx);
            let handle = event_loop.run();

            // Return the Resolver.
            Resolver {
                ares_channel: locked_channel,
                event_loop_channel: tx,
                event_loop_handle: Some(handle),
            }
        }

        // A CNAME query.  Returns a future that will resolve to hold the result.
        pub fn query_cname(&self, name: &str) -> CAresFuture<c_ares::CNameResults> {
            let (c, p) = futures::oneshot();
            self.ares_channel
                .lock()
                .unwrap()
                .query_cname(name, move |result| {
                    let _ = c.send(result);
                });
            CAresFuture::new(p)
        }

        // An MX query.  Returns a future that will resolve to hold the result.
        pub fn query_mx(&self, name: &str) -> CAresFuture<c_ares::MXResults> {
            let (c, p) = futures::oneshot();
            self.ares_channel
                .lock()
                .unwrap()
                .query_mx(name, move |result| {
                    let _ = c.send(result);
                });
            CAresFuture::new(p)
        }

        // A NAPTR query.  Returns a future that will resolve to hold the result.
        pub fn query_naptr(&self, name: &str) -> CAresFuture<c_ares::NAPTRResults> {
            let (c, p) = futures::oneshot();
            self.ares_channel
                .lock()
                .unwrap()
                .query_naptr(name, move |result| {
                    let _ = c.send(result);
                });
            CAresFuture::new(p)
        }
    }

    impl Drop for Resolver {
        fn drop(&mut self) {
            // Shut down the event loop and wait for it to finish.
            self.event_loop_channel
                .send(Message::ShutDown)
                .expect("failed to request event loop to shut down");
            if let Some(handle) = self.event_loop_handle.take() {
                handle.join().expect("failed to shut down event loop");
            }
        }
    }

    pub fn main() {
        // Create a Resolver, and some queries.
        let resolver = Resolver::new();
        let cname_query = resolver
            .query_cname("dimbleby.github.io")
            .map_err(|e| println!("CNAME lookup failed with error '{}'", e.description()))
            .map(|results| {
                println!();
                println!("Successful CNAME lookup...");
                println!("Hostname: {}", results.hostname());
                for alias in results.aliases() {
                    println!("Alias: {}", alias);
                }
                println!();
            });

        let mx_query = resolver
            .query_mx("gmail.com")
            .map_err(|e| println!("MX lookup failed with error '{}'", e.description()))
            .map(|results| {
                println!();
                println!("Successful MX lookup...");
                for result in &results {
                    println!("host {}, priority {}", result.host(), result.priority());
                }
                println!();
            });

        let naptr_query = resolver
            .query_naptr("apple.com")
            .map_err(|e| println!("NAPTR lookup failed with error '{}'", e.description()))
            .map(|results| {
                println!();
                println!("Successful NAPTR lookup...");
                for result in &results {
                    println!("flags: {}", result.flags());
                    println!("service name: {}", result.service_name());
                    println!("regular expression: {}", result.reg_exp());
                    println!("replacement pattern: {}", result.replacement_pattern());
                    println!("order: {}", result.order());
                    println!("preference: {}", result.preference());
                }
                println!();
            });

        // Execute the queries.
        current_thread::block_on_all(lazy(|| {
            current_thread::spawn(cname_query);
            current_thread::spawn(mx_query);
            current_thread::spawn(naptr_query);
            Ok::<(), ()>(())
        })).unwrap();
    }
}

#[cfg(unix)]
pub fn main() {
    example::main();
}

#[cfg(not(unix))]
pub fn main() {
    println!("this example is not supported on this platform");
}
<|endoftext|>