<commit_before>//
// FlightVars
// Copyright (c) 2015, 2016 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::fmt;
use std::io;
use std::str::FromStr;

use byteorder::{BigEndian, ReadBytesExt};
use hex::FromHex;

#[derive(Debug, PartialEq)]
pub struct OffsetAddr(u16);

impl FromHex for OffsetAddr {
    type Error = io::Error;
    fn from_hex(s: &str) -> Result<Self, Self::Error> {
        let error = || io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("invalid FSUIPC offset address in '{}'", s));
        let buf: Vec<u8> = try!(FromHex::from_hex(s).map_err(|_| error()));
        if buf.len() > 2 { Err(error()) }
        else {
            (&buf[..]).read_u16::<BigEndian>()
                .map(|v| OffsetAddr(v))
                .map_err(|_| error())
        }
    }
}

impl fmt::Display for OffsetAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{:x}", self.0)
    }
}

#[derive(Debug, PartialEq)]
pub enum OffsetLen { Ub, Sb, Uw, Sw, Ud, Sd }

impl fmt::Display for OffsetLen {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            OffsetLen::Ub => write!(f, "UB"),
            OffsetLen::Sb => write!(f, "SB"),
            OffsetLen::Uw => write!(f, "UW"),
            OffsetLen::Sw => write!(f, "SW"),
            OffsetLen::Ud => write!(f, "UD"),
            OffsetLen::Sd => write!(f, "SD"),
        }
    }
}

impl FromStr for OffsetLen {
    type Err = io::Error;
    fn from_str(s: &str) -> Result<OffsetLen, io::Error> {
        match s {
            "UB" => Ok(OffsetLen::Ub),
            "SB" => Ok(OffsetLen::Sb),
            "UW" => Ok(OffsetLen::Uw),
            "SW" => Ok(OffsetLen::Sw),
            "UD" => Ok(OffsetLen::Ud),
            "SD" => Ok(OffsetLen::Sd),
            _ => Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("invalid FSUIPC offset length in '{}'", s))),
        }
    }
}

#[derive(Debug, PartialEq)]
pub struct Offset(OffsetAddr, OffsetLen);

impl fmt::Display for Offset {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}:{}", self.0, self.1)
    }
}

impl FromStr for Offset {
    type Err = io::Error;
    fn from_str(s: &str) -> Result<Offset, io::Error> {
        let pair: Vec<&str> = s.split(":").collect();
        if pair.len() == 2 {
            let addr = try!(OffsetAddr::from_hex(pair[0]));
            let len = try!(OffsetLen::from_str(pair[1]));
            Ok(Offset(addr, len))
        } else {
            Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("invalid FSUIPC offset in '{}'", s)))
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum Message {
    Begin { version: u16, client_id: String },
    WriteLvar { lvar: String, value: i64 },
    WriteOffset { offset: Offset, value: i64 },
    ObserveLvar { lvar: String },
    ObserveOffset { offset: Offset }
}

impl Message {

    pub fn begin(version: u16, client_id: &str) -> Message {
        Message::Begin { version: version, client_id: client_id.to_string() }
    }

    pub fn write_lvar(lvar: &str, value: i64) -> Message {
        Message::WriteLvar { lvar: lvar.to_string(), value: value }
    }

    pub fn write_offset(offset: Offset, value: i64) -> Message {
        Message::WriteOffset { offset: offset, value: value }
    }

    pub fn obs_lvar(lvar: &str) -> Message {
        Message::ObserveLvar { lvar: lvar.to_string() }
    }

    pub fn obs_offset(offset: Offset) -> Message {
        Message::ObserveOffset { offset: offset }
    }
}

impl fmt::Display for Message {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            &Message::Begin { version, ref client_id } =>
                write!(f, "BEGIN {} {}", version, client_id),
            &Message::WriteLvar { ref lvar, value} =>
                write!(f, "WRITE_LVAR {} {}", lvar, value),
            &Message::WriteOffset { ref offset, value } =>
                write!(f, "WRITE_OFFSET {} {}", offset, value),
            &Message::ObserveLvar { ref lvar } =>
                write!(f, "OBS_LVAR {}", lvar),
            &Message::ObserveOffset { ref offset } =>
                write!(f, "OBS_OFFSET {}", offset),
        }
    }
}

impl FromStr for Message {
    type Err = io::Error;
    fn from_str(s: &str) -> Result<Message, io::Error> {
        let deco = MessageParser::new(s);
        deco.parse()
    }
}

pub struct MessageParser<'a> {
    input: &'a str
}

impl<'a> MessageParser<'a> {
    pub fn new(input: &'a str) -> MessageParser {
        MessageParser { input: input }
    }

    pub fn parse(self) -> io::Result<Message> {
        let args: Vec<&str> = self.input.split_whitespace().collect();
        let cmd = args[0];
        let args = &args[1..];
        match &cmd.to_uppercase()[..] {
            "BEGIN" => self.parse_begin(&args),
            "WRITE_LVAR" => self.parse_write_lvar(&args),
            "WRITE_OFFSET" => self.parse_write_offset(&args),
            "OBS_LVAR" => self.parse_obs_lvar(&args),
            "OBS_OFFSET" => self.parse_obs_offset(&args),
            _ => Err(self.input_error()),
        }
    }

    fn parse_begin(self, args: &[&str]) -> io::Result<Message> {
        try!(self.require_argc(args, 2));
        let ver = try!(args[0].parse().map_err(|_| self.input_error()));
        Ok(Message::begin(ver, args[1]))
    }

    fn parse_write_lvar(self, args: &[&str]) -> io::Result<Message> {
        try!(self.require_argc(args, 2));
        let lvar = args[0];
        let value = try!(args[1].parse().map_err(|_| self.input_error()));
        Ok(Message::write_lvar(&lvar, value))
    }

    fn parse_write_offset(self, args: &[&str]) -> io::Result<Message> {
        try!(self.require_argc(args, 2));
        let offset = try!(args[0].parse());
        let value = try!(args[1].parse().map_err(|_| self.input_error()));
        Ok(Message::write_offset(offset, value))
    }

    fn parse_obs_lvar(self, args: &[&str]) -> io::Result<Message> {
        try!(self.require_argc(args, 1));
        Ok(Message::obs_lvar(args[0]))
    }

    fn parse_obs_offset(self, args: &[&str]) -> io::Result<Message> {
        try!(self.require_argc(args, 1));
        Ok(Message::obs_offset(try!(args[0].parse())))
    }

    fn require_argc(&self, args: &[&str], expected: usize) -> io::Result<()> {
        if args.len() == expected { Ok(()) }
        else { Err(self.input_error()) }
    }

    fn input_error(&self) -> io::Error {
        io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("invalid oacsp message in '{}'", self.input))
    }
}

#[cfg(test)]
mod tests {
    use std::str::FromStr;

    use super::*;

    #[test]
    fn should_display_begin_msg() {
        let msg = Message::begin(1, "arduino");
        let buf = format!("{}", msg);
        assert_eq!(buf, "BEGIN 1 arduino")
    }

    #[test]
    fn should_parse_begin_msg() {
        let buf = "BEGIN 1 arduino";
        let msg = Message::from_str(&buf).unwrap();
        assert_eq!(msg, Message::begin(1, "arduino"));
    }

    #[test]
    fn should_display_write_lvar_msg() {
        let msg = Message::write_lvar("foobar", 42);
        let buf = format!("{}", msg);
        assert_eq!(buf, "WRITE_LVAR foobar 42")
    }

    #[test]
    fn should_parse_write_lvar_msg() {
        let buf = "WRITE_LVAR foobar 42";
        let msg = Message::from_str(&buf).unwrap();
        assert_eq!(msg, Message::write_lvar("foobar", 42));
    }

    #[test]
    fn should_display_write_offset_msg() {
        let msg = Message::write_offset(Offset(OffsetAddr(0x1234), OffsetLen::Uw), 42);
        let buf = format!("{}", msg);
        assert_eq!(buf, "WRITE_OFFSET 1234:UW 42")
    }

    #[test]
    fn should_parse_write_offset_msg() {
        let buf = "WRITE_OFFSET 1234:UW 42";
        let msg = Message::from_str(&buf).unwrap();
        assert_eq!(msg, Message::write_offset(Offset(OffsetAddr(0x1234), OffsetLen::Uw), 42));
    }

    #[test]
    fn should_display_obs_lvar_msg() {
        let msg = Message::obs_lvar("foobar");
        let buf = format!("{}", msg);
        assert_eq!(buf, "OBS_LVAR foobar")
    }

    #[test]
    fn should_parse_obs_lvar_msg() {
        let buf = "OBS_LVAR foobar";
        let msg = Message::from_str(&buf).unwrap();
        assert_eq!(msg, Message::obs_lvar("foobar"));
    }

    #[test]
    fn should_display_obs_offset_msg() {
        let msg = Message::obs_offset(Offset(OffsetAddr(0x1234), OffsetLen::Uw));
        let buf = format!("{}", msg);
        assert_eq!(buf, "OBS_OFFSET 1234:UW")
    }

    #[test]
    fn should_parse_obs_offset_msg() {
        let buf = "OBS_OFFSET 1234:UW";
        let msg = Message::from_str(&buf).unwrap();
        assert_eq!(msg, Message::obs_offset(Offset(OffsetAddr(0x1234), OffsetLen::Uw)));
    }
}
<commit_msg>Introduce `EventLvar` message in `oacsp` mod<commit_after>//
// FlightVars
// Copyright (c) 2015, 2016 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::fmt;
use std::io;
use std::str::FromStr;

use byteorder::{BigEndian, ReadBytesExt};
use hex::FromHex;

#[derive(Debug, PartialEq)]
pub struct OffsetAddr(u16);

impl FromHex for OffsetAddr {
    type Error = io::Error;
    fn from_hex(s: &str) -> Result<Self, Self::Error> {
        let error = || io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("invalid FSUIPC offset address in '{}'", s));
        let buf: Vec<u8> = try!(FromHex::from_hex(s).map_err(|_| error()));
        if buf.len() > 2 { Err(error()) }
        else {
            (&buf[..]).read_u16::<BigEndian>()
                .map(|v| OffsetAddr(v))
                .map_err(|_| error())
        }
    }
}

impl fmt::Display for OffsetAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{:x}", self.0)
    }
}

#[derive(Debug, PartialEq)]
pub enum OffsetLen { Ub, Sb, Uw, Sw, Ud, Sd }

impl fmt::Display for OffsetLen {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            OffsetLen::Ub => write!(f, "UB"),
            OffsetLen::Sb => write!(f, "SB"),
            OffsetLen::Uw => write!(f, "UW"),
            OffsetLen::Sw => write!(f, "SW"),
            OffsetLen::Ud => write!(f, "UD"),
            OffsetLen::Sd => write!(f, "SD"),
        }
    }
}

impl FromStr for OffsetLen {
    type Err = io::Error;
    fn from_str(s: &str) -> Result<OffsetLen, io::Error> {
        match s {
            "UB" => Ok(OffsetLen::Ub),
            "SB" => Ok(OffsetLen::Sb),
            "UW" => Ok(OffsetLen::Uw),
            "SW" => Ok(OffsetLen::Sw),
            "UD" => Ok(OffsetLen::Ud),
            "SD" => Ok(OffsetLen::Sd),
            _ => Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("invalid FSUIPC offset length in '{}'", s))),
        }
    }
}

#[derive(Debug, PartialEq)]
pub struct Offset(OffsetAddr, OffsetLen);

impl fmt::Display for Offset {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}:{}", self.0, self.1)
    }
}

impl FromStr for Offset {
    type Err = io::Error;
    fn from_str(s: &str) -> Result<Offset, io::Error> {
        let pair: Vec<&str> = s.split(":").collect();
        if pair.len() == 2 {
            let addr = try!(OffsetAddr::from_hex(pair[0]));
            let len = try!(OffsetLen::from_str(pair[1]));
            Ok(Offset(addr, len))
        } else {
            Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("invalid FSUIPC offset in '{}'", s)))
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum Message {
    Begin { version: u16, client_id: String },
    WriteLvar { lvar: String, value: i64 },
    WriteOffset { offset: Offset, value: i64 },
    ObserveLvar { lvar: String },
    ObserveOffset { offset: Offset },
    EventLvar { lvar: String, value: i64 }
}

impl Message {

    pub fn begin(version: u16, client_id: &str) -> Message {
        Message::Begin { version: version, client_id: client_id.to_string() }
    }

    pub fn write_lvar(lvar: &str, value: i64) -> Message {
        Message::WriteLvar { lvar: lvar.to_string(), value: value }
    }

    pub fn write_offset(offset: Offset, value: i64) -> Message {
        Message::WriteOffset { offset: offset, value: value }
    }

    pub fn obs_lvar(lvar: &str) -> Message {
        Message::ObserveLvar { lvar: lvar.to_string() }
    }

    pub fn obs_offset(offset: Offset) -> Message {
        Message::ObserveOffset { offset: offset }
    }

    pub fn event_lvar(lvar: &str, value: i64) -> Message {
        Message::EventLvar { lvar: lvar.to_string(), value: value }
    }
}

impl fmt::Display for Message {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            &Message::Begin { version, ref client_id } =>
                write!(f, "BEGIN {} {}", version, client_id),
            &Message::WriteLvar { ref lvar, value} =>
                write!(f, "WRITE_LVAR {} {}", lvar, value),
            &Message::WriteOffset { ref offset, value } =>
                write!(f, "WRITE_OFFSET {} {}", offset, value),
            &Message::ObserveLvar { ref lvar } =>
                write!(f, "OBS_LVAR {}", lvar),
            &Message::ObserveOffset { ref offset } =>
                write!(f, "OBS_OFFSET {}", offset),
            &Message::EventLvar { ref lvar, value } =>
                write!(f, "EVENT_LVAR {} {}", lvar, value),
        }
    }
}

impl FromStr for Message {
    type Err = io::Error;
    fn from_str(s: &str) -> Result<Message, io::Error> {
        let deco = MessageParser::new(s);
        deco.parse()
    }
}

pub struct MessageParser<'a> {
    input: &'a str
}

impl<'a> MessageParser<'a> {
    pub fn new(input: &'a str) -> MessageParser {
        MessageParser { input: input }
    }

    pub fn parse(self) -> io::Result<Message> {
        let args: Vec<&str> = self.input.split_whitespace().collect();
        let cmd = args[0];
        let args = &args[1..];
        match &cmd.to_uppercase()[..] {
            "BEGIN" => self.parse_begin(&args),
            "WRITE_LVAR" => self.parse_write_lvar(&args),
            "WRITE_OFFSET" => self.parse_write_offset(&args),
            "OBS_LVAR" => self.parse_obs_lvar(&args),
            "OBS_OFFSET" => self.parse_obs_offset(&args),
            "EVENT_LVAR" => self.parse_event_lvar(&args),
            _ => Err(self.input_error()),
        }
    }

    fn parse_begin(self, args: &[&str]) -> io::Result<Message> {
        try!(self.require_argc(args, 2));
        let ver = try!(args[0].parse().map_err(|_| self.input_error()));
        Ok(Message::begin(ver, args[1]))
    }

    fn parse_write_lvar(self, args: &[&str]) -> io::Result<Message> {
        try!(self.require_argc(args, 2));
        let lvar = args[0];
        let value = try!(args[1].parse().map_err(|_| self.input_error()));
        Ok(Message::write_lvar(&lvar, value))
    }

    fn parse_write_offset(self, args: &[&str]) -> io::Result<Message> {
        try!(self.require_argc(args, 2));
        let offset = try!(args[0].parse());
        let value = try!(args[1].parse().map_err(|_| self.input_error()));
        Ok(Message::write_offset(offset, value))
    }

    fn parse_obs_lvar(self, args: &[&str]) -> io::Result<Message> {
        try!(self.require_argc(args, 1));
        Ok(Message::obs_lvar(args[0]))
    }

    fn parse_obs_offset(self, args: &[&str]) -> io::Result<Message> {
        try!(self.require_argc(args, 1));
        Ok(Message::obs_offset(try!(args[0].parse())))
    }

    fn parse_event_lvar(self, args: &[&str]) -> io::Result<Message> {
        try!(self.require_argc(args, 2));
        let lvar = args[0];
        let value = try!(args[1].parse().map_err(|_| self.input_error()));
        Ok(Message::event_lvar(lvar, value))
    }

    fn require_argc(&self, args: &[&str], expected: usize) -> io::Result<()> {
        if args.len() == expected { Ok(()) }
        else { Err(self.input_error()) }
    }

    fn input_error(&self) -> io::Error {
        io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("invalid oacsp message in '{}'", self.input))
    }
}

#[cfg(test)]
mod tests {
    use std::str::FromStr;

    use super::*;

    #[test]
    fn should_display_begin_msg() {
        let msg = Message::begin(1, "arduino");
        let buf = format!("{}", msg);
        assert_eq!(buf, "BEGIN 1 arduino")
    }

    #[test]
    fn should_parse_begin_msg() {
        let buf = "BEGIN 1 arduino";
        let msg = Message::from_str(&buf).unwrap();
        assert_eq!(msg, Message::begin(1, "arduino"));
    }

    #[test]
    fn should_display_write_lvar_msg() {
        let msg = Message::write_lvar("foobar", 42);
        let buf = format!("{}", msg);
        assert_eq!(buf, "WRITE_LVAR foobar 42")
    }

    #[test]
    fn should_parse_write_lvar_msg() {
        let buf = "WRITE_LVAR foobar 42";
        let msg = Message::from_str(&buf).unwrap();
        assert_eq!(msg, Message::write_lvar("foobar", 42));
    }

    #[test]
    fn should_display_write_offset_msg() {
        let msg = Message::write_offset(Offset(OffsetAddr(0x1234), OffsetLen::Uw), 42);
        let buf = format!("{}", msg);
        assert_eq!(buf, "WRITE_OFFSET 1234:UW 42")
    }

    #[test]
    fn should_parse_write_offset_msg() {
        let buf = "WRITE_OFFSET 1234:UW 42";
        let msg = Message::from_str(&buf).unwrap();
        assert_eq!(msg, Message::write_offset(Offset(OffsetAddr(0x1234), OffsetLen::Uw), 42));
    }

    #[test]
    fn should_display_obs_lvar_msg() {
        let msg = Message::obs_lvar("foobar");
        let buf = format!("{}", msg);
        assert_eq!(buf, "OBS_LVAR foobar")
    }

    #[test]
    fn should_parse_obs_lvar_msg() {
        let buf = "OBS_LVAR foobar";
        let msg = Message::from_str(&buf).unwrap();
        assert_eq!(msg, Message::obs_lvar("foobar"));
    }

    #[test]
    fn should_display_obs_offset_msg() {
        let msg = Message::obs_offset(Offset(OffsetAddr(0x1234), OffsetLen::Uw));
        let buf = format!("{}", msg);
        assert_eq!(buf, "OBS_OFFSET 1234:UW")
    }

    #[test]
    fn should_parse_obs_offset_msg() {
        let buf = "OBS_OFFSET 1234:UW";
        let msg = Message::from_str(&buf).unwrap();
        assert_eq!(msg, Message::obs_offset(Offset(OffsetAddr(0x1234), OffsetLen::Uw)));
    }

    #[test]
    fn should_display_event_lvar_msg() {
        let msg = Message::event_lvar("foobar", 42);
        let buf = format!("{}", msg);
        assert_eq!(buf, "EVENT_LVAR foobar 42")
    }

    #[test]
    fn should_parse_event_lvar_msg() {
        let buf = "EVENT_LVAR foobar 42";
        let msg = Message::from_str(&buf).unwrap();
        assert_eq!(msg, Message::event_lvar("foobar", 42));
    }
}
<|endoftext|>


<commit_before>use super::config::{Config, Capture};
use std::collections::HashMap;
use std::io::{BufRead, Write};

#[derive(Debug, Clone, Copy)]
pub enum OutputFormat {
    LittleEndian,
    BigEndian,
    HexList,
}

struct Replacement {
    // Line for purposes of printing errors.
    line: usize,
    // Left shift amount
    shift: i32,
    // Segment to add the value to.
    add_segment: usize,
    // The index in the add_segment to add the value.
    index: usize,
    // The tag to retrieve the position to add.
    tag: String,
    // The segment for which we are retrieving the position from the tag.
    pos_segment: usize,
    // The offset we add after retrieving the value from the tag.
    pos_offset: isize,
}

pub struct Parser<'a> {
    config: &'a Config,
    segments: Vec<Vec<u64>>,
    tags: HashMap<String, Vec<usize>>,
    plus_tags: Vec<(usize, Vec<usize>)>,
    minus_tags: Vec<(usize, Vec<usize>)>,
    replacements: Vec<Replacement>,
}

fn shift_left_or_right(a: u64, shift: i32) -> u64 {
    if shift < 0 {
        a >> (-shift)
    } else {
        a << shift
    }
}

impl<'a> Parser<'a> {
    pub fn new(config: &'a Config) -> Self {
        Parser {
            config: config,
            segments: {
                let mut v = Vec::new();
                for _ in 0..config.segment_widths.len() {
                    v.push(Vec::new());
                }
                v
            },
            tags: HashMap::new(),
            plus_tags: Vec::new(),
            minus_tags: Vec::new(),
            replacements: Vec::new(),
        }
    }

    pub fn link(&mut self) {
        // Iterate through every replacement.
        'outer: for r in &self.replacements {
            if r.tag.chars().all(|c| c == '+') {
                for e in &self.plus_tags {
                    // Ensure they have the same amount of pluses and that the relevant segment is at least as high.
                    if e.0 == r.tag.len() && e.1[r.add_segment] >= r.index {
                        self.segments[r.add_segment][r.index] +=
                            shift_left_or_right((e.1[r.pos_segment] as isize + r.pos_offset) as u64, r.shift);

                        break 'outer;
                    }
                }
                panic!("Error: Forward + tag used on line {} was never defined.",
                       r.line);
            } else if r.tag.chars().all(|c| c == '-') {
                for e in self.minus_tags.iter().rev() {
                    // Ensure they have the same amount of minuses and that the relevant segment is at least as low.
                    if e.0 == r.tag.len() && e.1[r.add_segment] < r.index {
                        self.segments[r.add_segment][r.index] +=
                            shift_left_or_right((e.1[r.pos_segment] as isize + r.pos_offset) as u64, r.shift);

                        break 'outer;
                    }
                }
                panic!("Error: Forward + tag used on line {} was never defined.",
                       r.line);
            } else {
                // Get the tag offset vector corresponding to the replacement.
                let tag = self.tags.get(&r.tag).unwrap_or_else(|| {
                    panic!("Error: Tag \"{}\" used on line {} never defined.",
                           r.tag,
                           r.line);
                });
                self.segments[r.add_segment][r.index] +=
                    shift_left_or_right((tag[r.pos_segment] as isize + r.pos_offset) as u64,
                                        r.shift);
            }
        }
    }

    pub fn parse<B>(&mut self, bufread: B)
        where B: BufRead
    {
        for (index, line) in bufread.lines().enumerate() {
            let line = line.unwrap_or_else(|e| panic!("Error: Failed to read from buffer: {}", e));

            // Remove everything after the first #, which denotes a comment.
            let line = line.splitn(2, '#').next().unwrap();

            if self.config.split_whitespace {
                for word in line.split_whitespace() {
                    self.parse_segment(word, index + 1);
                }
            } else {
                self.parse_segment(line, index + 1);
            }
        }
    }

    pub fn output<W>(&self, format: OutputFormat, segment: usize, w: &mut W)
        where W: Write
    {
        use byteorder::{ByteOrder, LittleEndian, BigEndian};
        match format {
            OutputFormat::LittleEndian => {
                // Allocate enough bytes to store a u64
                let mut bytes = [0; 8];
                let width = self.config.segment_widths[segment];
                for val in &self.segments[segment] {
                    LittleEndian::write_u64(&mut bytes, *val);
                    w.write_all(&bytes[0..width]).unwrap_or_else(|e| {
                        panic!("Error: Writing to output file for segment {} failed: {}",
                               segment,
                               e);
                    });
                }
            }
            OutputFormat::BigEndian => {
                // Allocate enough bytes to store a u64
                let mut bytes = [0; 8];
                let width = self.config.segment_widths[segment];
                for val in &self.segments[segment] {
                    BigEndian::write_u64(&mut bytes, *val);
                    w.write_all(&bytes[0..width]).unwrap_or_else(|e| {
                        panic!("Error: Writing to output file for segment {} failed: {}",
                               segment,
                               e);
                    });
                }
            }
            OutputFormat::HexList => {
                use std::iter::FromIterator;
                // Allocate enough bytes to store a u64
                let mut bytes = [0u8; 8];
                let width = self.config.segment_widths[segment];
                for val in &self.segments[segment] {
                    BigEndian::write_u64(&mut bytes, *val);
                    w.write_all((String::from_iter(bytes[(8 - width)..8]
                                .iter()
                                .map(|&b| format!("{:02X}", b))) +
                                    "\n")
                            .as_bytes())
                        .unwrap_or_else(|e| {
                            panic!("Error: Writing to output file for segment {} failed: {}",
                                   segment,
                                   e);
                        });
                }
            }
        }
    }

    pub fn parse_segment(&mut self, segment: &str, line: usize) {
        if segment.is_empty() {
            return;
        }
        if self.attempt_tag_create(segment, line) {
            return;
        }
        if self.attempt_rules(segment, line) {
            return;
        }
        panic!("Error: Unrecognized symbol \"{}\" on line {}.",
               segment,
               line);
    }

    fn attempt_tag_create(&mut self, segment: &str, line: usize) -> bool {
        for tc in &self.config.tag_creates {
            if let Some(caps) = tc.regex.as_ref().unwrap().captures(segment) {
                let s = caps.at(1).unwrap();
                if s.chars().all(|c| c == '+') {
                    self.plus_tags.push((s.len(),
                                         self.segments
                        .iter()
                        .map(|v| v.len())
                        .collect()));
                } else if s.chars().all(|c| c == '-') {
                    self.minus_tags.push((s.len(),
                                          self.segments
                        .iter()
                        .map(|v| v.len())
                        .collect()));
                } else {
                    use std::collections::hash_map::Entry;
                    match self.tags.entry(s.to_string()) {
                        Entry::Occupied(_) => {
                            panic!("Attempted to create duplicate tag \"{}\" on line {}",
                                   s,
                                   line)
                        }
                        Entry::Vacant(v) => {
                            v.insert(self.segments
                                .iter()
                                .map(|v| v.len())
                                .collect());
                        }
                    }
                }
                return true;
            } else {
                return false;
            }
        }
        false
    }

    fn attempt_rules(&mut self, segment: &str, line: usize) -> bool {
        let config = &self.config;
        for rule in &config.rules {
            if let Some(caps) = rule.regex.as_ref().unwrap().captures(segment) {
                let mut segvals = rule.segment_values.clone();
                for self_reference in &rule.self_references {
                    segvals[self_reference.add_segment][self_reference.add_index] +=
                        if self_reference.shift < 0 {
                            (self.segments[self_reference.from_segment].len() as u64) >>
                            ((-self_reference.shift) as u32)
                        } else {
                            (self.segments[self_reference.from_segment].len() as u64) <<
                            (self_reference.shift as u32)
                        };
                }
                for (index, capture) in rule.captures.iter().enumerate() {
                    use std::mem::transmute;
                    let cap_string = caps.at(index + 1).unwrap();
                    match *capture {
                        Capture::Tag { ref feedbacks } => {
                            for feedback in feedbacks {
                                self.replacements.push(Replacement {
                                    line: line,
                                    shift: feedback.shift,
                                    add_segment: feedback.add_segment,
                                    index: self.segments[feedback.add_segment].len() +
                                           feedback.add_index,
                                    tag: String::from(cap_string),
                                    pos_segment: feedback.from_segment,
                                    pos_offset: if feedback.relative {
                                        feedback.offset -
                                        self.segments[feedback.from_segment].len() as isize
                                    } else {
                                        feedback.offset
                                    },
                                });
                            }
                        }
                        Capture::Str { add_segment } => {
                            for c in cap_string.chars() {
                                self.segments[add_segment].push(c as u64);
                            }
                        }
                        Capture::Num { ref feedbacks, ref base } => {
                            let pval = i64::from_str_radix(cap_string, *base).unwrap_or_else(|e| {
                                panic!("Error: Failed to parse captured string \"{}\" from \
                                        \"{}\": {}",
                                       cap_string,
                                       segment,
                                       e);
                            });
                            let val: u64 = unsafe { transmute(pval) };

                            for feedback in feedbacks {
                                let mut shiftval = shift_left_or_right(val, feedback.shift);
                                if feedback.negate {
                                    shiftval = !shiftval + 1;
                                }
                                if feedback.fill {
                                    let baseval = segvals[feedback.segment][feedback.index];
                                    let fill_amount = shiftval as isize + feedback.fill_offset;
                                    if fill_amount.is_negative() {
                                        panic!("Error: Got a negative fill amount!");
                                    } else if feedback.align {
                                        while self.segments[feedback.segment].len() <
                                              fill_amount as usize {
                                            self.segments[feedback.segment].push(baseval);
                                        }
                                    } else {
                                        for _ in 0..fill_amount {
                                            self.segments[feedback.segment].push(baseval);
                                        }
                                    }
                                    segvals[feedback.segment].pop();
                                } else {
                                    segvals[feedback.segment][feedback.index] += shiftval;
                                }
                            }
                        }
                    }
                }
                for (segvec, segment) in segvals.iter_mut().zip(self.segments.iter_mut()) {
                    segment.append(segvec);
                }
                return true;
            }
        }
        false
    }
}
<commit_msg>fix bug with not using all tag_creates vec<commit_after>use super::config::{Config, Capture};
use std::collections::HashMap;
use std::io::{BufRead, Write};

#[derive(Debug, Clone, Copy)]
pub enum OutputFormat {
    LittleEndian,
    BigEndian,
    HexList,
}

struct Replacement {
    // Line for purposes of printing errors.
    line: usize,
    // Left shift amount
    shift: i32,
    // Segment to add the value to.
    add_segment: usize,
    // The index in the add_segment to add the value.
    index: usize,
    // The tag to retrieve the position to add.
    tag: String,
    // The segment for which we are retrieving the position from the tag.
    pos_segment: usize,
    // The offset we add after retrieving the value from the tag.
    pos_offset: isize,
}

pub struct Parser<'a> {
    config: &'a Config,
    segments: Vec<Vec<u64>>,
    tags: HashMap<String, Vec<usize>>,
    plus_tags: Vec<(usize, Vec<usize>)>,
    minus_tags: Vec<(usize, Vec<usize>)>,
    replacements: Vec<Replacement>,
}

fn shift_left_or_right(a: u64, shift: i32) -> u64 {
    if shift < 0 {
        a >> (-shift)
    } else {
        a << shift
    }
}

impl<'a> Parser<'a> {
    pub fn new(config: &'a Config) -> Self {
        Parser {
            config: config,
            segments: {
                let mut v = Vec::new();
                for _ in 0..config.segment_widths.len() {
                    v.push(Vec::new());
                }
                v
            },
            tags: HashMap::new(),
            plus_tags: Vec::new(),
            minus_tags: Vec::new(),
            replacements: Vec::new(),
        }
    }

    pub fn link(&mut self) {
        // Iterate through every replacement.
        'outer: for r in &self.replacements {
            if r.tag.chars().all(|c| c == '+') {
                for e in &self.plus_tags {
                    // Ensure they have the same amount of pluses and that the relevant segment is at least as high.
                    if e.0 == r.tag.len() && e.1[r.add_segment] >= r.index {
                        self.segments[r.add_segment][r.index] +=
                            shift_left_or_right((e.1[r.pos_segment] as isize + r.pos_offset) as u64, r.shift);

                        break 'outer;
                    }
                }
                panic!("Error: Forward + tag used on line {} was never defined.",
                       r.line);
            } else if r.tag.chars().all(|c| c == '-') {
                for e in self.minus_tags.iter().rev() {
                    // Ensure they have the same amount of minuses and that the relevant segment is at least as low.
                    if e.0 == r.tag.len() && e.1[r.add_segment] < r.index {
                        self.segments[r.add_segment][r.index] +=
                            shift_left_or_right((e.1[r.pos_segment] as isize + r.pos_offset) as u64, r.shift);

                        break 'outer;
                    }
                }
                panic!("Error: Forward + tag used on line {} was never defined.",
                       r.line);
            } else {
                // Get the tag offset vector corresponding to the replacement.
                let tag = self.tags.get(&r.tag).unwrap_or_else(|| {
                    panic!("Error: Tag \"{}\" used on line {} never defined.",
                           r.tag,
                           r.line);
                });
                self.segments[r.add_segment][r.index] +=
                    shift_left_or_right((tag[r.pos_segment] as isize + r.pos_offset) as u64,
                                        r.shift);
            }
        }
    }

    pub fn parse<B>(&mut self, bufread: B)
        where B: BufRead
    {
        for (index, line) in bufread.lines().enumerate() {
            let line = line.unwrap_or_else(|e| panic!("Error: Failed to read from buffer: {}", e));

            // Remove everything after the first #, which denotes a comment.
            let line = line.splitn(2, '#').next().unwrap();

            if self.config.split_whitespace {
                for word in line.split_whitespace() {
                    self.parse_segment(word, index + 1);
                }
            } else {
                self.parse_segment(line, index + 1);
            }
        }
    }

    pub fn output<W>(&self, format: OutputFormat, segment: usize, w: &mut W)
        where W: Write
    {
        use byteorder::{ByteOrder, LittleEndian, BigEndian};
        match format {
            OutputFormat::LittleEndian => {
                // Allocate enough bytes to store a u64
                let mut bytes = [0; 8];
                let width = self.config.segment_widths[segment];
                for val in &self.segments[segment] {
                    LittleEndian::write_u64(&mut bytes, *val);
                    w.write_all(&bytes[0..width]).unwrap_or_else(|e| {
                        panic!("Error: Writing to output file for segment {} failed: {}",
                               segment,
                               e);
                    });
                }
            }
            OutputFormat::BigEndian => {
                // Allocate enough bytes to store a u64
                let mut bytes = [0; 8];
                let width = self.config.segment_widths[segment];
                for val in &self.segments[segment] {
                    BigEndian::write_u64(&mut bytes, *val);
                    w.write_all(&bytes[0..width]).unwrap_or_else(|e| {
                        panic!("Error: Writing to output file for segment {} failed: {}",
                               segment,
                               e);
                    });
                }
            }
            OutputFormat::HexList => {
                use std::iter::FromIterator;
                // Allocate enough bytes to store a u64
                let mut bytes = [0u8; 8];
                let width = self.config.segment_widths[segment];
                for val in &self.segments[segment] {
                    BigEndian::write_u64(&mut bytes, *val);
                    w.write_all((String::from_iter(bytes[(8 - width)..8]
                                .iter()
                                .map(|&b| format!("{:02X}", b))) +
                                    "\n")
                            .as_bytes())
                        .unwrap_or_else(|e| {
                            panic!("Error: Writing to output file for segment {} failed: {}",
                                   segment,
                                   e);
                        });
                }
            }
        }
    }

    pub fn parse_segment(&mut self, segment: &str, line: usize) {
        if segment.is_empty() {
            return;
        }
        if self.attempt_tag_create(segment, line) {
            return;
        }
        if self.attempt_rules(segment, line) {
            return;
        }
        panic!("Error: Unrecognized symbol \"{}\" on line {}.",
               segment,
               line);
    }

    fn attempt_tag_create(&mut self, segment: &str, line: usize) -> bool {
        for tc in &self.config.tag_creates {
            if let Some(caps) = tc.regex.as_ref().unwrap().captures(segment) {
                let s = caps.at(1).unwrap();
                if s.chars().all(|c| c == '+') {
                    self.plus_tags.push((s.len(),
                                         self.segments
                        .iter()
                        .map(|v| v.len())
                        .collect()));
                } else if s.chars().all(|c| c == '-') {
                    self.minus_tags.push((s.len(),
                                          self.segments
                        .iter()
                        .map(|v| v.len())
                        .collect()));
                } else {
                    use std::collections::hash_map::Entry;
                    match self.tags.entry(s.to_string()) {
                        Entry::Occupied(_) => {
                            panic!("Attempted to create duplicate tag \"{}\" on line {}",
                                   s,
                                   line)
                        }
                        Entry::Vacant(v) => {
                            v.insert(self.segments
                                .iter()
                                .map(|v| v.len())
                                .collect());
                        }
                    }
                }
                return true;
            }
        }
        false
    }

    fn attempt_rules(&mut self, segment: &str, line: usize) -> bool {
        let config = &self.config;
        for rule in &config.rules {
            if let Some(caps) = rule.regex.as_ref().unwrap().captures(segment) {
                let mut segvals = rule.segment_values.clone();
                for self_reference in &rule.self_references {
                    segvals[self_reference.add_segment][self_reference.add_index] +=
                        if self_reference.shift < 0 {
                            (self.segments[self_reference.from_segment].len() as u64) >>
                            ((-self_reference.shift) as u32)
                        } else {
                            (self.segments[self_reference.from_segment].len() as u64) <<
                            (self_reference.shift as u32)
                        };
                }
                for (index, capture) in rule.captures.iter().enumerate() {
                    use std::mem::transmute;
                    let cap_string = caps.at(index + 1).unwrap();
                    match *capture {
                        Capture::Tag { ref feedbacks } => {
                            for feedback in feedbacks {
                                self.replacements.push(Replacement {
                                    line: line,
                                    shift: feedback.shift,
                                    add_segment: feedback.add_segment,
                                    index: self.segments[feedback.add_segment].len() +
                                           feedback.add_index,
                                    tag: String::from(cap_string),
                                    pos_segment: feedback.from_segment,
                                    pos_offset: if feedback.relative {
                                        feedback.offset -
                                        self.segments[feedback.from_segment].len() as isize
                                    } else {
                                        feedback.offset
                                    },
                                });
                            }
                        }
                        Capture::Str { add_segment } => {
                            for c in cap_string.chars() {
                                self.segments[add_segment].push(c as u64);
                            }
                        }
                        Capture::Num { ref feedbacks, ref base } => {
                            let pval = i64::from_str_radix(cap_string, *base).unwrap_or_else(|e| {
                                panic!("Error: Failed to parse captured string \"{}\" from \
                                        \"{}\" on line {}: {}",
                                       cap_string,
                                       segment,
                                       line,
                                       e);
                            });
                            let val: u64 = unsafe { transmute(pval) };

                            for feedback in feedbacks {
                                let mut shiftval = shift_left_or_right(val, feedback.shift);
                                if feedback.negate {
                                    shiftval = !shiftval + 1;
                                }
                                if feedback.fill {
                                    let baseval = segvals[feedback.segment][feedback.index];
                                    let fill_amount = shiftval as isize + feedback.fill_offset;
                                    if fill_amount.is_negative() {
                                        panic!("Error: Got a negative fill amount!");
                                    } else if feedback.align {
                                        while self.segments[feedback.segment].len() <
                                              fill_amount as usize {
                                            self.segments[feedback.segment].push(baseval);
                                        }
                                    } else {
                                        for _ in 0..fill_amount {
                                            self.segments[feedback.segment].push(baseval);
                                        }
                                    }
                                    segvals[feedback.segment].pop();
                                } else {
                                    segvals[feedback.segment][feedback.index] += shiftval;
                                }
                            }
                        }
                    }
                }
                for (segvec, segment) in segvals.iter_mut().zip(self.segments.iter_mut()) {
                    segment.append(segvec);
                }
                return true;
            }
        }
        false
    }
}
<|endoftext|>


<commit_before>use std::io::stdin;
use std::io::prelude::*;
use std::iter::once;
use regex::Regex;

pub struct MessageIter {
    buf: String,
}

pub enum Message {
    Header(String, String),
    Warning(String),
    Note(String),
    Error(String),
    Help(String),
    FollowUp(String),
    Source(String, String),
    Marker(String),
    NewLine,
    Wat,
}

impl Iterator for MessageIter {
    type Item = Vec<Message>;

    fn next(&mut self) -> Option<Vec<Message>> {
        use self::Message::*;

        let mut res = Vec::new();
        let mut file = String::new();
        let mut stop = false;
        let si = stdin();
        let stdin = si.lock().lines().map(|x| x.expect("Stdin failed"));

        for l in once(self.buf.clone()).chain(stdin) {
            let re_header = Regex::new(r"([0-9A-Za-z_\.\\/]+):(\d+):\d+: .*(warning: |note: |error: |help: )(.*)").unwrap();
            let re_source = Regex::new(r"(\d+) (.*)").unwrap();
            if re_header.is_match(&l) {
                if !stop {
                    stop = true;
                } else {
                    self.buf = l.to_string();
                    return Some(res);
                }

                res.push(NewLine);

                let caps = re_header.captures(&l).unwrap();
                file = caps.at(1).unwrap_or("?").to_string();

                res.push(Header(file.clone(), caps.at(2).unwrap_or("?").to_string()));

                let msg = caps.at(4).unwrap_or("?").to_string();

                // Warning, header or note?
                match caps.at(3).unwrap_or("?") {
                    "warning: " => res.push(Warning(msg)),
                    "note: " =>    res.push(Note(msg)),
                    "error: " =>   res.push(Error(msg)),
                    "help: " =>    res.push(Help(msg)),
                    _ =>           res.push(Wat),
                }
            } else if l.len() > file.len() && re_source.is_match(&l[file.len()..]) {
                let caps = re_source.captures(&l).unwrap();

                res.push(Source(caps.at(1).unwrap_or("?").to_string(), caps.at(2).unwrap_or("????").to_string()));
            } else if l.chars().next() == Some(' ') && l.contains("^") {

                let offset = if let Some(&Source(ref line, _)) = res.last() {
                    file.len() + line.len().saturating_sub(6)
                } else {
                    0
                };

                if offset < l.len() {
                    res.push(Marker(l[offset..].to_string()));
                }
            } else {
                res.push(FollowUp(l.to_string()));
            }
        }
        None
    }
}

impl MessageIter {
    pub fn new() -> Self {
        MessageIter {
            buf: String::new(),
        }
    }
}

<commit_msg>Fix arrows<commit_after>use std::io::stdin;
use std::io::prelude::*;
use std::iter::once;
use regex::Regex;

pub struct MessageIter {
    buf: String,
}

pub enum Message {
    Header(String, String),
    Warning(String),
    Note(String),
    Error(String),
    Help(String),
    FollowUp(String),
    Source(String, String),
    Marker(String),
    NewLine,
    Wat,
}

impl Iterator for MessageIter {
    type Item = Vec<Message>;

    fn next(&mut self) -> Option<Vec<Message>> {
        use self::Message::*;

        let mut res = Vec::new();
        let mut file = String::new();
        let mut stop = false;
        let si = stdin();
        let stdin = si.lock().lines().map(|x| x.expect("Stdin failed"));

        for l in once(self.buf.clone()).chain(stdin) {
            let re_header = Regex::new(r"([0-9A-Za-z_\.\\/]+):(\d+):\d+: .*(warning: |note: |error: |help: )(.*)").unwrap();
            let re_source = Regex::new(r"(\d+) (.*)").unwrap();
            if re_header.is_match(&l) {
                if !stop {
                    stop = true;
                } else {
                    self.buf = l.to_string();
                    return Some(res);
                }

                res.push(NewLine);

                let caps = re_header.captures(&l).unwrap();
                file = caps.at(1).unwrap_or("?").to_string();

                res.push(Header(file.clone(), caps.at(2).unwrap_or("?").to_string()));

                let msg = caps.at(4).unwrap_or("?").to_string();

                // Warning, header or note?
                match caps.at(3).unwrap_or("?") {
                    "warning: " => res.push(Warning(msg)),
                    "note: " =>    res.push(Note(msg)),
                    "error: " =>   res.push(Error(msg)),
                    "help: " =>    res.push(Help(msg)),
                    _ =>           res.push(Wat),
                }
            } else if l.len() > file.len() && re_source.is_match(&l[file.len()..]) {
                let caps = re_source.captures(&l).unwrap();

                res.push(Source(caps.at(1).unwrap_or("?").to_string(), caps.at(2).unwrap_or("????").to_string()));
            } else if l.starts_with(' ') && l.contains("^") {

                let offset = file.len() - 4; //+ 5 - 5;

                if offset < l.len() {
                    res.push(Marker(l[offset..].to_string()));
                }
            } else {
                res.push(FollowUp(l.to_string()));
            }
        }
        None
    }
}

impl MessageIter {
    pub fn new() -> Self {
        MessageIter {
            buf: String::new(),
        }
    }
}

<|endoftext|>


<commit_before>use rustc_serialize::json::Json;

use super::Document;

#[derive(Debug)]
pub enum Filter {
    Not(Box<Filter>),
    Or(Vec<Filter>),
    And(Vec<Filter>),
    Term(String, String),
}

impl Filter {
    pub fn matches(&self, doc: &Document) -> bool {
        match *self {
            Filter::Not(ref filter) => !filter.matches(doc),
            Filter::Or(ref filters) => {
                for filter in filters.iter() {
                    if filter.matches(doc) {
                        return true;
                    }
                }

                false
            }
            Filter::And(ref filters) => {
                for filter in filters.iter() {
                    if !filter.matches(doc) {
                        return false;
                    }
                }

                true
            }
            Filter::Term(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    if let Json::String(ref field_value) = *field_value {
                        return field_value == value;
                    }
                }

                false
            }
        }
    }
}

#[derive(Debug)]
pub enum Query {
    Match{field: String, query: String},
    MultiMatch{fields: Vec<String>, query: String},
    Filtered{query: Box<Query>, filter: Box<Filter>},
}

pub fn parse_filter(json: &Json) -> Filter {
    Filter::Term("not".to_owned(), "implemented".to_owned())
}

pub fn parse_match_query(json: &Json) -> Query {
    let query_json = json.as_object().unwrap();

    Query::Match {
        field: query_json.get("field").unwrap().as_string().unwrap().to_owned(),
        query: query_json.get("query").unwrap().as_string().unwrap().to_owned(),
    }
}

pub fn parse_multi_match_query(json: &Json) -> Query {
    let query_json = json.as_object().unwrap();

    Query::MultiMatch {
        // Convert "fields" into a Vec<String>
        fields: query_json.get("fields").unwrap()
                          .as_array().unwrap()
                          .iter().map(|s| s.as_string().unwrap().to_owned())
                          .collect::<Vec<_>>(),
        query: query_json.get("query").unwrap().as_string().unwrap().to_owned(),
    }
}

pub fn parse_filtered_query(json: &Json) -> Query {
    let query_json = json.as_object().unwrap();

    Query::Filtered {
        filter: Box::new(parse_filter(query_json.get("filter").unwrap())),
        query: Box::new(parse_query(query_json.get("query").unwrap())),
    }
}

pub fn parse_query(json: &Json) -> Query {
    let query_json = json.as_object().unwrap();
    let first_key = query_json.keys().nth(0).unwrap();

    if first_key == "match" {
        let inner_query = query_json.get("match").unwrap();
        parse_match_query(inner_query)
    } else if first_key == "multi_match" {
        let inner_query = query_json.get("multi_match").unwrap();
        parse_multi_match_query(inner_query)
    } else if first_key == "filtered" {
        let inner_query = query_json.get("filtered").unwrap();
        parse_filtered_query(inner_query)
    } else {
        // TODO
        Query::Match {
            field: "not".to_owned(),
            query: "implemented".to_owned(),
        }
    }
}
<commit_msg>Filter parsing<commit_after>use rustc_serialize::json::Json;

use super::Document;

#[derive(Debug)]
pub enum Filter {
    Term(String, String),
    Prefix(String, String),
    And(Vec<Filter>),
    Or(Vec<Filter>),
    Not(Box<Filter>),
}

impl Filter {
    pub fn matches(&self, doc: &Document) -> bool {
        match *self {
            Filter::Term(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    if let Json::String(ref field_value) = *field_value {
                        return field_value == value;
                    }
                }

                false
            }
            Filter::Prefix(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    if let Json::String(ref field_value) = *field_value {
                        return field_value.starts_with(value);
                    }
                }

                false
            }
            Filter::And(ref filters) => {
                for filter in filters.iter() {
                    if !filter.matches(doc) {
                        return false;
                    }
                }

                true
            }
            Filter::Or(ref filters) => {
                for filter in filters.iter() {
                    if filter.matches(doc) {
                        return true;
                    }
                }

                false
            }
            Filter::Not(ref filter) => !filter.matches(doc),
        }
    }
}

pub fn parse_filter(json: &Json) -> Filter {
    let filter_json = json.as_object().unwrap();
    let first_key = filter_json.keys().nth(0).unwrap();

    if first_key == "term" {
        let filter_json = filter_json.get("term").unwrap().as_object().unwrap();
        let first_key = filter_json.keys().nth(0).unwrap();

        // TODO: needs a type system
        Filter::Term(first_key.clone(), "not implemented".to_owned())
    } else if first_key == "prefix" {
        let filter_json = filter_json.get("prefix").unwrap().as_object().unwrap();
        let first_key = filter_json.keys().nth(0).unwrap();
        let value = filter_json.get(first_key).unwrap().as_string().unwrap();

        Filter::Prefix(first_key.clone(), value.to_owned())
    } else if first_key == "and" {
        Filter::And(filter_json.get("and").unwrap()
                               .as_array().unwrap()
                               .iter().map(|f| parse_filter(f))
                               .collect::<Vec<_>>(),)
    } else if first_key == "or" {
        Filter::Or(filter_json.get("or").unwrap()
                               .as_array().unwrap()
                               .iter().map(|f| parse_filter(f))
                               .collect::<Vec<_>>(),)
    } else if first_key == "not" {
        Filter::Not(Box::new(parse_filter(filter_json.get("not").unwrap())))
    } else {
        Filter::Term("not".to_owned(), "implemented".to_owned())
    }
}

#[derive(Debug)]
pub enum Query {
    Match{field: String, query: String},
    MultiMatch{fields: Vec<String>, query: String},
    Filtered{query: Box<Query>, filter: Box<Filter>},
}

pub fn parse_match_query(json: &Json) -> Query {
    let query_json = json.as_object().unwrap();

    Query::Match {
        field: query_json.get("field").unwrap().as_string().unwrap().to_owned(),
        query: query_json.get("query").unwrap().as_string().unwrap().to_owned(),
    }
}

pub fn parse_multi_match_query(json: &Json) -> Query {
    let query_json = json.as_object().unwrap();

    Query::MultiMatch {
        // Convert "fields" into a Vec<String>
        fields: query_json.get("fields").unwrap()
                          .as_array().unwrap()
                          .iter().map(|s| s.as_string().unwrap().to_owned())
                          .collect::<Vec<_>>(),
        query: query_json.get("query").unwrap().as_string().unwrap().to_owned(),
    }
}

pub fn parse_filtered_query(json: &Json) -> Query {
    let query_json = json.as_object().unwrap();

    Query::Filtered {
        filter: Box::new(parse_filter(query_json.get("filter").unwrap())),
        query: Box::new(parse_query(query_json.get("query").unwrap())),
    }
}

pub fn parse_query(json: &Json) -> Query {
    let query_json = json.as_object().unwrap();
    let first_key = query_json.keys().nth(0).unwrap();

    if first_key == "match" {
        let inner_query = query_json.get("match").unwrap();
        parse_match_query(inner_query)
    } else if first_key == "multi_match" {
        let inner_query = query_json.get("multi_match").unwrap();
        parse_multi_match_query(inner_query)
    } else if first_key == "filtered" {
        let inner_query = query_json.get("filtered").unwrap();
        parse_filtered_query(inner_query)
    } else {
        // TODO
        Query::Match {
            field: "not".to_owned(),
            query: "implemented".to_owned(),
        }
    }
}
<|endoftext|>


<commit_before>use std::hash::Hash;
use std::collections::HashMap;

use super::interpret::TurtleCommand;

/// These rules describe how an L-System should evolve to its next
/// state and how this state should be interpreted in order to draw it.
/// These two different concepts are stored alongside to facilitate the definition
/// of L-System, both in code and in file.
///
/// A production (or evolution) rule consists in a symbol combined with its
/// corresponding result. The internal data structure is up to the structures
/// implementing this trait.
///
/// See 'TurtleCommand' for further detail on the interpretation rules.
pub trait LRules<S: Eq> {
    /// Get the production of the given symbol, or None if no matching rule is
    /// found.
    fn production(&self, symbol: &S) -> Option<&Vec<S>>;

    /// Get the interpreter command for the given symbol, or None if no matching
    /// command is found.
    fn interpretation(&self, symbol: &S) -> Option<&TurtleCommand>;

    /// Get the expansion size of the worse-case production.
    fn biggest_expansion(&self) -> usize;
}

#[derive(Clone, Debug)]
struct SymbolRule<S: Eq>(Vec<S>, TurtleCommand);

/// HashMap-based Rules structure.
#[derive(Clone, Debug)]
pub struct HashMapRules<S>
    where S: Eq + Hash
{
    rules: HashMap<S, SymbolRule<S>>,
    biggest_expansion: usize,
}

impl<S> HashMapRules<S> where S: Eq + Hash
{
    pub fn new() -> HashMapRules<S> {
        HashMapRules {
            rules: HashMap::new(),
            biggest_expansion: 0,
        }
    }

    /// Add a new symbol rule or modify an existing one.
    /// Return true if an existing rule was modified, false otherwise.
    pub fn set(&mut self, symbol: S, production: Vec<S>, interpretation: TurtleCommand) -> bool {
        let production_len = production.len();
        let modified = match self.rules.insert(symbol, SymbolRule(production, interpretation)) {
            Some(_) => true,
            None => false,
        };
        if production_len > self.biggest_expansion {
            self.biggest_expansion = production_len;
        }
        modified
    }
}

impl HashMapRules<char> {
    /// Convenience method for calling 'set' directly with an str slice.
    /// NB: unicode char should be avoided at all cost, which is why ASCII is
    /// preferred.
    pub fn set_str(&mut self,
                   symbol: char,
                   production: &str,
                   interpretation: TurtleCommand)
                   -> bool {
        self.set(symbol, production.chars().collect(), interpretation)
    }
}

impl<S> LRules<S> for HashMapRules<S> where S: Eq + Hash
{
    fn production(&self, symbol: &S) -> Option<&Vec<S>> {
        self.rules.get(symbol).map(|r| &r.0)
    }

    fn interpretation(&self, symbol: &S) -> Option<&TurtleCommand> {
        self.rules.get(symbol).map(|r| &r.1)
    }

    fn biggest_expansion(&self) -> usize {
        self.biggest_expansion
    }
}

/// Default, ASCII-only 'HashMapRules' type.
pub type AsciiHashMapRules = HashMapRules<u8>;

impl AsciiHashMapRules {
    pub fn set_ascii(&mut self,
                     symbol: u8,
                     production: &[u8],
                     interpretation: TurtleCommand)
                     -> bool {
        self.set(symbol, production.to_vec(), interpretation)
    }
}

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

    #[test]
    fn hashmap_rules_char() {
        let mut rules: HashMapRules<char> = HashMapRules::new();
        rules.set_str('A', "+B−A−B+", TurtleCommand::AdvanceBy(10f32));
        rules.set_str('B', "−A+B+A−", TurtleCommand::AdvanceBy(10f32));
        rules.set_str('+', "+", TurtleCommand::RotateBy(60f32));
        rules.set_str('-', "-", TurtleCommand::RotateBy(-60f32));

        assert_eq!(rules.biggest_expansion(), 7);
        assert_eq!(rules.production(&'A'),
                   Some(&"+B−A−B+".chars().collect()));
        assert_eq!(rules.production(&'B'),
                   Some(&"−A+B+A−".chars().collect()));
        assert_eq!(rules.production(&'C'), None);
    }

    #[test]
    fn hashmap_rules_ascii() {
        let mut rules = AsciiHashMapRules::new();
        rules.set_ascii(b'A', b"AB", TurtleCommand::None);
        rules.set_ascii(b'B', b"A", TurtleCommand::None);

        assert_eq!(rules.biggest_expansion(), 2);
        assert_eq!(rules.production(&b'A'), Some(&b"AB".to_vec()));
        assert_eq!(rules.production(&b'B'), Some(&b"A".to_vec()));
        assert_eq!(rules.production(&b'C'), None);
    }
}
<commit_msg>add average expansion to the 'LRules' trait<commit_after>use std::hash::Hash;
use std::collections::HashMap;

use super::interpret::TurtleCommand;

/// These rules describe how an L-System should evolve to its next
/// state and how this state should be interpreted in order to draw it.
/// These two different concepts are stored alongside to facilitate the definition
/// of L-System, both in code and in file.
///
/// A production (or evolution) rule consists in a symbol combined with its
/// corresponding result. The internal data structure is up to the structures
/// implementing this trait.
///
/// See 'TurtleCommand' for further detail on the interpretation rules.
pub trait LRules<S: Eq> {
    /// Get the production of the given symbol, or None if no matching rule is
    /// found.
    fn production(&self, symbol: &S) -> Option<&Vec<S>>;

    /// Get the interpreter command for the given symbol, or None if no matching
    /// command is found.
    fn interpretation(&self, symbol: &S) -> Option<&TurtleCommand>;

    /// Get the expansion size of the worse-case production.
    fn biggest_expansion(&self) -> usize;

    /// Get the average expansion size of the production rules.
    fn average_expansion(&self) -> f64;
}

#[derive(Clone, Debug)]
struct SymbolRule<S: Eq>(Vec<S>, TurtleCommand);

/// HashMap-based Rules structure.
#[derive(Clone, Debug)]
pub struct HashMapRules<S>
    where S: Eq + Hash
{
    rules: HashMap<S, SymbolRule<S>>,
    biggest_expansion: usize,
    average_expansion: f64,
}

impl<S> HashMapRules<S> where S: Eq + Hash
{
    pub fn new() -> HashMapRules<S> {
        HashMapRules {
            rules: HashMap::new(),
            biggest_expansion: 0,
            average_expansion: 0f64,
        }
    }

    /// Add a new symbol rule or modify an existing one.
    /// Return true if an existing rule was modified, false otherwise.
    pub fn set(&mut self, symbol: S, production: Vec<S>, interpretation: TurtleCommand) -> bool {
        let production_len = production.len();
        let modified = match self.rules.insert(symbol, SymbolRule(production, interpretation)) {
            Some(_) => true,
            None => false,
        };

        // biggest expansion computing
        if production_len > self.biggest_expansion {
            self.biggest_expansion = production_len;
        }
        // average expansion computing
        assert!(self.rules.len() > 0);
        self.average_expansion += (production_len as f64 - self.average_expansion) /
                                  (self.rules.len() as f64);

        modified
    }
}

impl HashMapRules<char> {
    /// Convenience method for calling 'set' directly with an str slice.
    /// NB: unicode char should be avoided at all cost, which is why ASCII is
    /// preferred.
    pub fn set_str(&mut self,
                   symbol: char,
                   production: &str,
                   interpretation: TurtleCommand)
                   -> bool {
        self.set(symbol, production.chars().collect(), interpretation)
    }
}

impl<S> LRules<S> for HashMapRules<S> where S: Eq + Hash
{
    fn production(&self, symbol: &S) -> Option<&Vec<S>> {
        self.rules.get(symbol).map(|r| &r.0)
    }

    fn interpretation(&self, symbol: &S) -> Option<&TurtleCommand> {
        self.rules.get(symbol).map(|r| &r.1)
    }

    fn biggest_expansion(&self) -> usize {
        self.biggest_expansion
    }

    fn average_expansion(&self) -> f64 {
        self.average_expansion
    }
}

/// Default, ASCII-only 'HashMapRules' type.
pub type AsciiHashMapRules = HashMapRules<u8>;

impl AsciiHashMapRules {
    pub fn set_ascii(&mut self,
                     symbol: u8,
                     production: &[u8],
                     interpretation: TurtleCommand)
                     -> bool {
        self.set(symbol, production.to_vec(), interpretation)
    }
}

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

    #[test]
    fn hashmap_rules_char() {
        let mut rules: HashMapRules<char> = HashMapRules::new();
        rules.set_str('A', "+B−A−B+", TurtleCommand::AdvanceBy(10f32));
        rules.set_str('B', "−A+B+A−", TurtleCommand::AdvanceBy(10f32));
        rules.set_str('+', "+", TurtleCommand::RotateBy(60f32));
        rules.set_str('-', "-", TurtleCommand::RotateBy(-60f32));

        assert_eq!(rules.biggest_expansion(), 7);
        assert_eq!(rules.average_expansion(), 4.0);
        assert_eq!(rules.production(&'A'),
                   Some(&"+B−A−B+".chars().collect()));
        assert_eq!(rules.production(&'B'),
                   Some(&"−A+B+A−".chars().collect()));
        assert_eq!(rules.production(&'C'), None);
    }

    #[test]
    fn hashmap_rules_ascii() {
        let mut rules = AsciiHashMapRules::new();
        rules.set_ascii(b'A', b"AB", TurtleCommand::None);
        rules.set_ascii(b'B', b"A", TurtleCommand::None);

        assert_eq!(rules.biggest_expansion(), 2);
        assert_eq!(rules.average_expansion(), 1.5);
        assert_eq!(rules.production(&b'A'), Some(&b"AB".to_vec()));
        assert_eq!(rules.production(&b'B'), Some(&b"A".to_vec()));
        assert_eq!(rules.production(&b'C'), None);
    }
}
<|endoftext|>


<commit_before>use std::io::stdin;
use std::io::stdout;
use std::io::Write;
use std::str;
use std::time::Duration;

use zookeeper::{Acl, CreateMode, Watcher, WatchedEvent, ZkError, ZooKeeper};
use zookeeper::acls;

struct MyWatcher;

impl Watcher for MyWatcher {
    fn handle(&self, e: &WatchedEvent) {
        println!("{:?}", e)
    }
}

pub struct Shell {
    hosts: String,
    zk: Option<ZooKeeper>,
    session_timeout: u64,
    default_acl: Vec<Acl>,
}

// are we connected?
macro_rules! fetch_zk {
    ($e:expr) => (
        match $e {
            Some(ref __zk) => __zk,
            _ => {
                println!("Not connected.");
                return;
            }
        })
}

macro_rules! check_args {
    ($args:ident, $min:expr, $max:expr, $params:expr) => (
        if $args.len() < $min || $args.len() > $max {
            println!("Wrong number of arguments, expected parameters: {}", $params);
            return;
        } else {
            $args.len()
        })
}

fn report_error(error: ZkError, path: &str) {
    match error {
        ZkError::NoNode => println!("Path {} does not exist.", path),
        ZkError::NotEmpty => println!("Path {} is not empty.", path),
        unknown => println!("Unknown error: {:?}", unknown),
    }
}

impl Shell {
    pub fn new(hosts: &str) -> Shell {
        Shell {
            hosts: hosts.to_string(),
            zk: None,
            session_timeout: 5,
            default_acl: acls::OPEN_ACL_UNSAFE.clone(),
        }
    }

    pub fn run(&mut self) {
        if !self.hosts.is_empty() {
            println!("Connecting...");
            let zk = ZooKeeper::connect(
                &self.hosts,
                Duration::from_secs(self.session_timeout),
                MyWatcher).unwrap();
            self.zk = Some(zk);
        }

        loop {
            let mut line = String::new();

            print!("> ");
            let _ = stdout().flush();

            stdin()
                .read_line(&mut line)
                .ok()
                .expect("Failed to read line");

            let pieces: Vec<&str>  = line.trim().split_whitespace().collect();

            if pieces.len() == 0 {
                continue;
            }

            // dispatch the command
            let args = pieces[1..].to_vec();
            match pieces[0] {
                "get" => self.get(args),
                "set" => self.set(args),
                "ls" => self.ls(args),
                "create" => self.create(args),
                "rm" => self.rm(args),
                "exists" => self.exists(args),
                unknown => println!("Unknown command: {}", unknown)
            }
        }

    }

    fn get(&mut self, args: Vec<&str>) {
        let argc = check_args!(args, 1, 2, "<path> [watch]");
        let watch = match argc {
            1 => false,
            _ => args[1].to_lowercase() == "true"
        };

        let zk = fetch_zk!(self.zk);
        let path = args[0];
        let ret = zk.get_data(path, watch);

        match ret {
            Ok(data_stat) =>  {
                let (bytes, _) = data_stat;
                let datastr = str::from_utf8(&bytes[..]).unwrap().to_string();
                println!("{}", datastr);
            },
            Err(err) => report_error(err, path),
        }
    }

    fn set(&mut self, args: Vec<&str>) {
        let argc = check_args!(args, 2, 3, "<path> <data> [version]");
        let version = match argc {
            3 => match args[2].parse::<i32>() {
                Ok(version) => version,
                Err(_) => -1
            },
            _ => -1
        };

        let zk = fetch_zk!(self.zk);
        let path = args[0];
        let data = args[1].as_bytes().to_vec();
        let ret = zk.set_data(path, data, version);

        match ret {
            Ok(_) => (),
            Err(err) => report_error(err, path),
        }
    }

    fn ls(&mut self, args: Vec<&str>) {
        let argc = check_args!(args, 1, 2, "<path> [watch]");
        let watch = match argc {
            1 => false,
            _ => args[1].to_lowercase() == "true"
        };

        let zk = fetch_zk!(self.zk);
        let path = args[0];
        let ret = zk.get_children(path, watch);

        match ret {
            Ok(children) => println!("{}", children.join(" ")),
            Err(err) => report_error(err, path),
        }
    }

    fn create(&mut self, args: Vec<&str>) {
        let mut mode: CreateMode = CreateMode::Persistent;

        let argc = check_args!(args, 2, 4, "<path> <data> [ephemeral] [sequential]");
        if argc >= 3 {
            if args[2].to_lowercase() == "true" {
                mode = CreateMode::Ephemeral;
            }
        }

        if argc == 4 {
            if args[3].to_lowercase() == "true" {
                mode = match mode {
                    CreateMode::Ephemeral => CreateMode::EphemeralSequential,
                    _ => CreateMode::PersistentSequential
                }
            }
        }

        let zk = fetch_zk!(self.zk);
        let path = args[0];
        let data = args[1].as_bytes().to_vec();

        let ret = zk.create(
            path, data, self.default_acl.clone(), mode);

        match ret {
            Ok(_) => (),
            Err(err) => report_error(err, path),
        }
    }

    fn rm(&mut self, args: Vec<&str>) {
        let argc = check_args!(args, 1, 2, "<path> [version]");
        let version = match argc {
            2 => match args[1].parse::<i32>() {
                Ok(version) => version,
                Err(_) => -1
            },
            _ => -1
        };

        let zk = fetch_zk!(self.zk);
        let path = args[0];
        let ret = zk.delete(path, version);

        match ret {
            Ok(()) =>  (),
            Err(err) => report_error(err, path),
        }
    }

    fn exists(&mut self, args: Vec<&str>) {
        let argc = check_args!(args, 1, 2, "<path> [watch]");
        let watch = match argc {
            1 => false,
            _ => args[1].to_lowercase() == "true"
        };

        let zk = fetch_zk!(self.zk);
        let path = args[0];
        let ret = zk.exists(path, watch);

        match ret {
            Ok(stat) => println!("{:?}", stat),
            Err(err) => report_error(err, path),
        }
    }
}
<commit_msg>feature(shell): add `connect` and `disconnect`<commit_after>use std::io::stdin;
use std::io::stdout;
use std::io::Write;
use std::str;
use std::time::Duration;

use zookeeper::{Acl, CreateMode, Watcher, WatchedEvent, ZkError, ZooKeeper};
use zookeeper::acls;

struct MyWatcher;

impl Watcher for MyWatcher {
    fn handle(&self, e: &WatchedEvent) {
        println!("{:?}", e)
    }
}

pub struct Shell {
    hosts: String,
    zk: Option<ZooKeeper>,
    session_timeout: u64,
    default_acl: Vec<Acl>,
}

// are we connected?
macro_rules! fetch_zk {
    ($e:expr) => (
        match $e {
            Some(ref __zk) => __zk,
            _ => {
                println!("Not connected.");
                return;
            }
        })
}

macro_rules! check_args {
    ($args:ident, $min:expr, $max:expr, $params:expr) => (
        if $args.len() < $min || $args.len() > $max {
            println!("Wrong number of arguments, expected parameters: {}", $params);
            return;
        } else {
            $args.len()
        })
}

fn report_error(error: ZkError, path: &str) {
    match error {
        ZkError::NoNode => println!("Path {} does not exist.", path),
        ZkError::NotEmpty => println!("Path {} is not empty.", path),
        unknown => println!("Unknown error: {:?}", unknown),
    }
}

impl Shell {
    pub fn new(hosts: &str) -> Shell {
        Shell {
            hosts: hosts.to_string(),
            zk: None,
            session_timeout: 5,
            default_acl: acls::OPEN_ACL_UNSAFE.clone(),
        }
    }

    pub fn run(&mut self) {
        if !self.hosts.is_empty() {
            let hosts = self.hosts.clone();
            self.connect_to(&hosts);
        }

        loop {
            let mut line = String::new();

            print!("> ");
            let _ = stdout().flush();

            stdin()
                .read_line(&mut line)
                .ok()
                .expect("Failed to read line");

            let pieces: Vec<&str>  = line.trim().split_whitespace().collect();

            if pieces.len() == 0 {
                continue;
            }

            // dispatch the command
            let args = pieces[1..].to_vec();
            match pieces[0] {
                "get" => self.get(args),
                "set" => self.set(args),
                "ls" => self.ls(args),
                "create" => self.create(args),
                "rm" => self.rm(args),
                "exists" => self.exists(args),
                "disconnect" => self.disconnect(),
                "connect" => self.connect(args),
                unknown => println!("Unknown command: {}", unknown)
            }
        }

    }

    fn get(&mut self, args: Vec<&str>) {
        let argc = check_args!(args, 1, 2, "<path> [watch]");
        let watch = match argc {
            1 => false,
            _ => args[1].to_lowercase() == "true"
        };

        let zk = fetch_zk!(self.zk);
        let path = args[0];
        let ret = zk.get_data(path, watch);

        match ret {
            Ok(data_stat) =>  {
                let (bytes, _) = data_stat;
                let datastr = str::from_utf8(&bytes[..]).unwrap().to_string();
                println!("{}", datastr);
            },
            Err(err) => report_error(err, path),
        }
    }

    fn set(&mut self, args: Vec<&str>) {
        let argc = check_args!(args, 2, 3, "<path> <data> [version]");
        let version = match argc {
            3 => match args[2].parse::<i32>() {
                Ok(version) => version,
                Err(_) => -1
            },
            _ => -1
        };

        let zk = fetch_zk!(self.zk);
        let path = args[0];
        let data = args[1].as_bytes().to_vec();
        let ret = zk.set_data(path, data, version);

        match ret {
            Ok(_) => (),
            Err(err) => report_error(err, path),
        }
    }

    fn ls(&mut self, args: Vec<&str>) {
        let argc = check_args!(args, 1, 2, "<path> [watch]");
        let watch = match argc {
            1 => false,
            _ => args[1].to_lowercase() == "true"
        };

        let zk = fetch_zk!(self.zk);
        let path = args[0];
        let ret = zk.get_children(path, watch);

        match ret {
            Ok(children) => println!("{}", children.join(" ")),
            Err(err) => report_error(err, path),
        }
    }

    fn create(&mut self, args: Vec<&str>) {
        let mut mode: CreateMode = CreateMode::Persistent;

        let argc = check_args!(args, 2, 4, "<path> <data> [ephemeral] [sequential]");
        if argc >= 3 {
            if args[2].to_lowercase() == "true" {
                mode = CreateMode::Ephemeral;
            }
        }

        if argc == 4 {
            if args[3].to_lowercase() == "true" {
                mode = match mode {
                    CreateMode::Ephemeral => CreateMode::EphemeralSequential,
                    _ => CreateMode::PersistentSequential
                }
            }
        }

        let zk = fetch_zk!(self.zk);
        let path = args[0];
        let data = args[1].as_bytes().to_vec();

        let ret = zk.create(
            path, data, self.default_acl.clone(), mode);

        match ret {
            Ok(_) => (),
            Err(err) => report_error(err, path),
        }
    }

    fn rm(&mut self, args: Vec<&str>) {
        let argc = check_args!(args, 1, 2, "<path> [version]");
        let version = match argc {
            2 => match args[1].parse::<i32>() {
                Ok(version) => version,
                Err(_) => -1
            },
            _ => -1
        };

        let zk = fetch_zk!(self.zk);
        let path = args[0];
        let ret = zk.delete(path, version);

        match ret {
            Ok(()) =>  (),
            Err(err) => report_error(err, path),
        }
    }

    fn exists(&mut self, args: Vec<&str>) {
        let argc = check_args!(args, 1, 2, "<path> [watch]");
        let watch = match argc {
            1 => false,
            _ => args[1].to_lowercase() == "true"
        };

        let zk = fetch_zk!(self.zk);
        let path = args[0];
        let ret = zk.exists(path, watch);

        match ret {
            Ok(stat) => println!("{:?}", stat),
            Err(err) => report_error(err, path),
        }
    }

    fn disconnect(&mut self) {
        {
            let zk = fetch_zk!(self.zk);
            zk.close();
        }
        self.zk = None;
    }

    fn connect(&mut self, args: Vec<&str>) {
        let _ = check_args!(args, 1, 1, "<hosts>");

        if self.zk.is_some() {
            let zk = fetch_zk!(self.zk);
            zk.close();
        }
        self.zk = None;
        self.connect_to(args[0]);
    }

    fn connect_to(&mut self, hosts: &str) {
        println!("Connecting to {}...", hosts);
        let timeout = Duration::from_secs(self.session_timeout);
        let result = ZooKeeper::connect(hosts, timeout, MyWatcher);
        match result {
            Ok(zk) => { self.zk = Some(zk); },
            Err(error) => println!("{:?}", error)
        }
    }
}
<|endoftext|>


<commit_before>use {Command, Error, Merger};

/// A stack of commands.
///
/// The `Stack` is the simplest data structure and works by pushing and
/// popping off `Command`s that modifies the `receiver`.
/// Unlike the `Record`, it does not have a special state that can be used for callbacks.
///
/// # Examples
/// ```
/// use std::error::Error;
/// use undo::{Command, Stack};
///
/// struct Add(char);
///
/// impl Command<String> for Add {
///     fn redo(&mut self, s: &mut String) -> Result<(), Box<Error>> {
///         s.push(self.0);
///         Ok(())
///     }
///
///     fn undo(&mut self, s: &mut String) -> Result<(), Box<Error>> {
///         self.0 = s.pop().expect("`String` is unexpectedly empty");
///         Ok(())
///     }
/// }
///
/// fn foo() -> Result<(), Box<Error>> {
///     let mut stack = Stack::default();
///
///     stack.push(Add('a'))?;
///     stack.push(Add('b'))?;
///     stack.push(Add('c'))?;
///
///     assert_eq!(stack.as_receiver(), "abc");
///
///     let c = stack.pop().unwrap()?;
///     let b = stack.pop().unwrap()?;
///     let a = stack.pop().unwrap()?;
///
///     assert_eq!(stack.as_receiver(), "");
///
///     stack.push(a)?;
///     stack.push(b)?;
///     stack.push(c)?;
///
///     assert_eq!(stack.into_receiver(), "abc");
///
///     Ok(())
/// }
/// # foo().unwrap();
/// ```
#[derive(Debug, Default)]
pub struct Stack<R> {
    commands: Vec<Box<Command<R>>>,
    receiver: R,
}

impl<R> Stack<R> {
    /// Creates a new `Stack`.
    #[inline]
    pub fn new<T: Into<R>>(receiver: T) -> Stack<R> {
        Stack {
            commands: Vec::new(),
            receiver: receiver.into(),
        }
    }

    /// Creates a new `Stack` with the given `capacity`.
    #[inline]
    pub fn with_capacity<T: Into<R>>(receiver: T, capacity: usize) -> Stack<R> {
        Stack {
            commands: Vec::with_capacity(capacity),
            receiver: receiver.into(),
        }
    }

    /// Returns the capacity of the `Stack`.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.commands.capacity()
    }

    /// Returns the number of `Command`s in the `Stack`.
    #[inline]
    pub fn len(&self) -> usize {
        self.commands.len()
    }

    /// Returns `true` if the `Stack` is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.commands.is_empty()
    }

    /// Returns a reference to the `receiver`.
    #[inline]
    pub fn as_receiver(&self) -> &R {
        &self.receiver
    }

    /// Consumes the `Stack`, returning the `receiver`.
    #[inline]
    pub fn into_receiver(self) -> R {
        self.receiver
    }

    /// Pushes `cmd` on the stack and executes its [`redo`] method. The command is merged with
    /// the previous top `Command` if their `id` is equal.
    ///
    /// # Errors
    /// If an error occur when executing `redo`, the error is returned together with the `Command`.
    ///
    /// [`redo`]: ../trait.Command.html#tymethod.redo
    #[inline]
    pub fn push<C>(&mut self, mut cmd: C) -> Result<(), Error<R>>
        where C: Command<R> + 'static,
              R: 'static,
    {
        if let Err(e) = cmd.redo(&mut self.receiver) {
            return Err(Error(Box::new(cmd), e));
        }
        match (cmd.id(), self.commands.last().and_then(|last| last.id())) {
            (Some(id1), Some(id2)) if id1 == id2 => {
                // Merge the command with the one on the top of the stack.
                let cmd = Merger {
                    cmd1: self.commands.pop().unwrap(),
                    cmd2: Box::new(cmd),
                };
                self.commands.push(Box::new(cmd));
            }
            _ => self.commands.push(Box::new(cmd)),
        }
        Ok(())
    }

    /// Calls the top commands [`undo`] method and pops it off the stack.
    /// Returns `None` if the stack is empty.
    ///
    /// # Errors
    /// If an error occur when executing `undo` the error is returned together with the `Command`.
    ///
    /// [`undo`]: ../trait.Command.html#tymethod.undo
    #[inline]
    pub fn pop(&mut self) -> Option<Result<Box<Command<R>>, Error<R>>> {
        let mut cmd = match self.commands.pop() {
            Some(cmd) => cmd,
            None => return None,
        };
        match cmd.undo(&mut self.receiver) {
            Ok(_) => Some(Ok(cmd)),
            Err(e) => Some(Err(Error(cmd, e))),
        }
    }
}

impl<R> AsRef<R> for Stack<R> {
    #[inline]
    fn as_ref(&self) -> &R {
        self.as_receiver()
    }
}
<commit_msg>Also remove expect() from Stack example<commit_after>use {Command, Error, Merger};

/// A stack of commands.
///
/// The `Stack` is the simplest data structure and works by pushing and
/// popping off `Command`s that modifies the `receiver`.
/// Unlike the `Record`, it does not have a special state that can be used for callbacks.
///
/// # Examples
/// ```
/// use std::error::Error;
/// use undo::{Command, Stack};
///
/// struct Add(char);
///
/// impl Command<String> for Add {
///     fn redo(&mut self, s: &mut String) -> Result<(), Box<Error>> {
///         s.push(self.0);
///         Ok(())
///     }
///
///     fn undo(&mut self, s: &mut String) -> Result<(), Box<Error>> {
///         self.0 = s.pop().ok_or("`String` is unexpectedly empty")?;
///         Ok(())
///     }
/// }
///
/// fn foo() -> Result<(), Box<Error>> {
///     let mut stack = Stack::default();
///
///     stack.push(Add('a'))?;
///     stack.push(Add('b'))?;
///     stack.push(Add('c'))?;
///
///     assert_eq!(stack.as_receiver(), "abc");
///
///     let c = stack.pop().unwrap()?;
///     let b = stack.pop().unwrap()?;
///     let a = stack.pop().unwrap()?;
///
///     assert_eq!(stack.as_receiver(), "");
///
///     stack.push(a)?;
///     stack.push(b)?;
///     stack.push(c)?;
///
///     assert_eq!(stack.into_receiver(), "abc");
///
///     Ok(())
/// }
/// # foo().unwrap();
/// ```
#[derive(Debug, Default)]
pub struct Stack<R> {
    commands: Vec<Box<Command<R>>>,
    receiver: R,
}

impl<R> Stack<R> {
    /// Creates a new `Stack`.
    #[inline]
    pub fn new<T: Into<R>>(receiver: T) -> Stack<R> {
        Stack {
            commands: Vec::new(),
            receiver: receiver.into(),
        }
    }

    /// Creates a new `Stack` with the given `capacity`.
    #[inline]
    pub fn with_capacity<T: Into<R>>(receiver: T, capacity: usize) -> Stack<R> {
        Stack {
            commands: Vec::with_capacity(capacity),
            receiver: receiver.into(),
        }
    }

    /// Returns the capacity of the `Stack`.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.commands.capacity()
    }

    /// Returns the number of `Command`s in the `Stack`.
    #[inline]
    pub fn len(&self) -> usize {
        self.commands.len()
    }

    /// Returns `true` if the `Stack` is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.commands.is_empty()
    }

    /// Returns a reference to the `receiver`.
    #[inline]
    pub fn as_receiver(&self) -> &R {
        &self.receiver
    }

    /// Consumes the `Stack`, returning the `receiver`.
    #[inline]
    pub fn into_receiver(self) -> R {
        self.receiver
    }

    /// Pushes `cmd` on the stack and executes its [`redo`] method. The command is merged with
    /// the previous top `Command` if their `id` is equal.
    ///
    /// # Errors
    /// If an error occur when executing `redo`, the error is returned together with the `Command`.
    ///
    /// [`redo`]: ../trait.Command.html#tymethod.redo
    #[inline]
    pub fn push<C>(&mut self, mut cmd: C) -> Result<(), Error<R>>
        where C: Command<R> + 'static,
              R: 'static,
    {
        if let Err(e) = cmd.redo(&mut self.receiver) {
            return Err(Error(Box::new(cmd), e));
        }
        match (cmd.id(), self.commands.last().and_then(|last| last.id())) {
            (Some(id1), Some(id2)) if id1 == id2 => {
                // Merge the command with the one on the top of the stack.
                let cmd = Merger {
                    cmd1: self.commands.pop().unwrap(),
                    cmd2: Box::new(cmd),
                };
                self.commands.push(Box::new(cmd));
            }
            _ => self.commands.push(Box::new(cmd)),
        }
        Ok(())
    }

    /// Calls the top commands [`undo`] method and pops it off the stack.
    /// Returns `None` if the stack is empty.
    ///
    /// # Errors
    /// If an error occur when executing `undo` the error is returned together with the `Command`.
    ///
    /// [`undo`]: ../trait.Command.html#tymethod.undo
    #[inline]
    pub fn pop(&mut self) -> Option<Result<Box<Command<R>>, Error<R>>> {
        let mut cmd = match self.commands.pop() {
            Some(cmd) => cmd,
            None => return None,
        };
        match cmd.undo(&mut self.receiver) {
            Ok(_) => Some(Ok(cmd)),
            Err(e) => Some(Err(Error(cmd, e))),
        }
    }
}

impl<R> AsRef<R> for Stack<R> {
    #[inline]
    fn as_ref(&self) -> &R {
        self.as_receiver()
    }
}
<|endoftext|>