<commit_before>//! This module deals with configuration data including the management of the list of secrets

#![allow(clippy::filter_map)]
extern crate rand;
use crate::image::CONF_LINE_IDENTIFIER__IMAGE;
use rand::seq::SliceRandom;
use rand::thread_rng;

/// Default game mode. Can be changed in the configuration file.
const DEFAULT_REWARDING_SCHEME: RewardingScheme = RewardingScheme::UnhideWhenGuessedChar;

/// Keyword in the configuration file to switch rewarding scheme in the enum `RewardingScheme`
/// to `UnHideWhenLostLife`
const UNHIDE_WHEN_LOST_LIVE_IDENTIFIER: &str = "traditional-rewarding";

/// Keyword in the configuration file to switch rewarding scheme in the enum `RewardingScheme`
/// to `UnHideWhenGuessedChar`
const UNHIDE_WHEN_GUESSED_CHAR_IDENTIFIER: &str = "success-rewarding";

/// Tags comment lines in the configuration file.
pub const CONF_LINE_IDENTIFIER__COMMENT: char = '#';

/// Tags control comman lines in the configuration file.
pub const CONF_LINE_IDENTIFIER__CONTROL: char = ':';

/// Optionally tags secret strings in config-file. Can be omitted.
pub const CONF_LINE_IDENTIFIER__WORD: char = '-';

/// A tag to enclose parts of the secret to be visible from the start, e.g.
/// "guess_-me_" will be displayed in the game as "_ _ _ _ _ - m e"
pub const CONF_LINE_WORD_MODIFIER__VISIBLE: char = '_';

/// Custom error type used expressing potential syntax errors when parsing the configuration file.
custom_error! {pub ConfigParseError
    GameModifier{line_number: usize, line: String}   = "
Syntax error in line
{line_number}:  \"{line}\"

The game modifier must be one of the following:
    :traditional-rewarding
    :success-rewarding

Edit config file and start again.\n",
    LineIdentifier{line_number: usize, line: String} = "
Syntax error in line
{line_number}:  \"{line}\"

The first character of every non-empty line has to be one of the following:
    any letter or digit (secret string),
    '#' (comment line),
    '-' (secret string),
    '|' (ASCII-Art image) or
    ':' (game modifier).

Edit config file and start again.\n",
    NoSecretString{} = "
A config file must have a least one secret string, which is
a non-empty line starting with a letter, digit, '_' or '-'.
",
}

/// A game mode defining how the ASCII-art image will be disclosed progressively.
#[derive(Debug, PartialEq)]
pub enum RewardingScheme {
    /// Game mode that is used together with the traditional gallows image (the gallows image
    /// is not build in, but can be add in the configuration file. The image is disclosed
    /// piecemeal after each wrong guess.
    UnhideWhenLostLife,
    /// Default game mode. The image is disclosed piecemeal after each right guess.
    UnhideWhenGuessedChar,
}

/// A dictionary holding all secret sentences from among whom one is chosen randomly at the
/// beginning of the game.
#[derive(Debug)]
pub struct Dict {
    wordlist: Vec<String>,
    pub rewarding_scheme: RewardingScheme,
}

impl Dict {
    /// Parses the configuration data, sets game modifier variables and populates the dictionary
    /// with secrets.
    pub fn new(lines: &str) -> Result<Self, ConfigParseError> {
        let mut rewarding_scheme = DEFAULT_REWARDING_SCHEME;
        let mut file_syntax_test1: Result<(), ConfigParseError> = Ok(());
        let mut file_syntax_test2: Result<(), ConfigParseError> = Ok(());

        let wordlist =
          // remove Unicode BOM if present (\u{feff} has in UTF8 3 bytes).
          if lines.starts_with('\u{feff}') { &lines[3..] } else { &lines[..] }
            // interpret identifier line
            .lines()
            .enumerate()
            .filter(|&(n,l)| {
                if l.starts_with(CONF_LINE_IDENTIFIER__CONTROL) {
                    if l[1..].trim() == UNHIDE_WHEN_LOST_LIVE_IDENTIFIER {
                        rewarding_scheme = RewardingScheme::UnhideWhenLostLife;
                        false
                    }
                    else if l[1..].trim() == UNHIDE_WHEN_GUESSED_CHAR_IDENTIFIER {
                        rewarding_scheme = RewardingScheme::UnhideWhenGuessedChar;
                        false
                    }
                    else {
                        // we only save the first error
                        if file_syntax_test1.is_ok() {
                            file_syntax_test1 = Err(ConfigParseError::GameModifier {
                                line_number: n+1, line: l.to_string() });
                        };
                        false
                    }
                } else {
                    true
                }
            })
            .filter(|&(_,l)|!( l.trim().is_empty() ||
                          l.starts_with(CONF_LINE_IDENTIFIER__COMMENT) ||
                          l.starts_with(CONF_LINE_IDENTIFIER__CONTROL) ||
                          l.starts_with(CONF_LINE_IDENTIFIER__IMAGE)
                        )
            )
            .map(|(n,l)| if l.starts_with(CONF_LINE_IDENTIFIER__WORD) {
                             l[1..].trim().to_string()
                        } else {
                             // Lines starting alphanumericly are secret strings also.
                             // We can safely unwrap here since all empty lines had been filtered.
                             let c = l.trim().chars().next().unwrap();
                             if c.is_alphanumeric() || c == CONF_LINE_WORD_MODIFIER__VISIBLE {
                                l.trim().to_string()
                             } else {
                                 // we only save the first error
                                 if file_syntax_test2.is_ok() {
                                    file_syntax_test2 = Err(ConfigParseError::LineIdentifier {
                                        line_number: n+1, line: l.to_string() });
                                 };
                                // This will never be used but we have to return something
                                "".to_string()
                             }
                        }
            )
            .collect::<Vec<String>>();

        if file_syntax_test1.is_err() {
            return Err(file_syntax_test1.unwrap_err());
        };
        if file_syntax_test2.is_err() {
            return Err(file_syntax_test2.unwrap_err());
        };

        if wordlist.is_empty() {
            return Err(ConfigParseError::NoSecretString {});
        }

        Ok(Dict {
            wordlist,
            rewarding_scheme,
        })
    }

    /// Chooses randomly one secret from the dictionary.
    pub fn get_random_word(&self) -> String {
        let mut rng = thread_rng();
        (&self.wordlist).choose(&mut rng).unwrap().to_string()
    }
}
<commit_msg>add dictionary parser tests<commit_after>//! This module deals with configuration data including the management of the list of secrets

#![allow(clippy::filter_map)]
extern crate rand;
use crate::image::CONF_LINE_IDENTIFIER__IMAGE;
use rand::seq::SliceRandom;
use rand::thread_rng;

/// Default game mode. Can be changed in the configuration file.
const DEFAULT_REWARDING_SCHEME: RewardingScheme = RewardingScheme::UnhideWhenGuessedChar;

/// Keyword in the configuration file to switch rewarding scheme in the enum `RewardingScheme`
/// to `UnHideWhenLostLife`
const UNHIDE_WHEN_LOST_LIVE_IDENTIFIER: &str = "traditional-rewarding";

/// Keyword in the configuration file to switch rewarding scheme in the enum `RewardingScheme`
/// to `UnHideWhenGuessedChar`
const UNHIDE_WHEN_GUESSED_CHAR_IDENTIFIER: &str = "success-rewarding";

/// Tags comment lines in the configuration file.
pub const CONF_LINE_IDENTIFIER__COMMENT: char = '#';

/// Tags control comman lines in the configuration file.
pub const CONF_LINE_IDENTIFIER__CONTROL: char = ':';

/// Optionally tags secret strings in config-file. Can be omitted.
pub const CONF_LINE_IDENTIFIER__WORD: char = '-';

/// A tag to enclose parts of the secret to be visible from the start, e.g.
/// "guess_-me_" will be displayed in the game as "_ _ _ _ _ - m e"
pub const CONF_LINE_WORD_MODIFIER__VISIBLE: char = '_';

/// Custom error type used expressing potential syntax errors when parsing the configuration file.
custom_error! {#[derive(PartialEq)] pub ConfigParseError
    GameModifier{line_number: usize, line: String}   = "
Syntax error in line
{line_number}:  \"{line}\"

The game modifier must be one of the following:
    :traditional-rewarding
    :success-rewarding

Edit config file and start again.\n",
    LineIdentifier{line_number: usize, line: String} = "
Syntax error in line
{line_number}:  \"{line}\"

The first character of every non-empty line has to be one of the following:
    any letter or digit (secret string),
    '#' (comment line),
    '-' (secret string),
    '|' (ASCII-Art image) or
    ':' (game modifier).

Edit config file and start again.\n",
    NoSecretString{} = "
A config file must have a least one secret string, which is
a non-empty line starting with a letter, digit, '_' or '-'.
",
}

/// A game mode defining how the ASCII-art image will be disclosed progressively.
#[derive(Debug, PartialEq)]
pub enum RewardingScheme {
    /// Game mode that is used together with the traditional gallows image (the gallows image
    /// is not build in, but can be add in the configuration file. The image is disclosed
    /// piecemeal after each wrong guess.
    UnhideWhenLostLife,
    /// Default game mode. The image is disclosed piecemeal after each right guess.
    UnhideWhenGuessedChar,
}

/// A dictionary holding all secret sentences from among whom one is chosen randomly at the
/// beginning of the game.
#[derive(Debug, PartialEq)]
pub struct Dict {
    wordlist: Vec<String>,
    pub rewarding_scheme: RewardingScheme,
}

impl Dict {
    /// Parses the configuration data, sets game modifier variables and populates the dictionary
    /// with secrets.
    pub fn new(lines: &str) -> Result<Self, ConfigParseError> {
        let mut rewarding_scheme = DEFAULT_REWARDING_SCHEME;
        let mut file_syntax_test1: Result<(), ConfigParseError> = Ok(());
        let mut file_syntax_test2: Result<(), ConfigParseError> = Ok(());

        let wordlist =
          // remove Unicode BOM if present (\u{feff} has in UTF8 3 bytes).
          if lines.starts_with('\u{feff}') { &lines[3..] } else { &lines[..] }
            // interpret identifier line
            .lines()
            .enumerate()
            .filter(|&(n,l)| {
                if l.starts_with(CONF_LINE_IDENTIFIER__CONTROL) {
                    if l[1..].trim() == UNHIDE_WHEN_LOST_LIVE_IDENTIFIER {
                        rewarding_scheme = RewardingScheme::UnhideWhenLostLife;
                        false
                    }
                    else if l[1..].trim() == UNHIDE_WHEN_GUESSED_CHAR_IDENTIFIER {
                        rewarding_scheme = RewardingScheme::UnhideWhenGuessedChar;
                        false
                    }
                    else {
                        // we only save the first error
                        if file_syntax_test1.is_ok() {
                            file_syntax_test1 = Err(ConfigParseError::GameModifier {
                                line_number: n+1, line: l.to_string() });
                        };
                        false
                    }
                } else {
                    true
                }
            })
            .filter(|&(_,l)|!( l.trim().is_empty() ||
                          l.starts_with(CONF_LINE_IDENTIFIER__COMMENT) ||
                          l.starts_with(CONF_LINE_IDENTIFIER__CONTROL) ||
                          l.starts_with(CONF_LINE_IDENTIFIER__IMAGE)
                        )
            )
            .map(|(n,l)| if l.starts_with(CONF_LINE_IDENTIFIER__WORD) {
                             l[1..].trim().to_string()
                        } else {
                             // Lines starting alphanumericly are secret strings also.
                             // We can safely unwrap here since all empty lines had been filtered.
                             let c = l.trim().chars().next().unwrap();
                             if c.is_alphanumeric() || c == CONF_LINE_WORD_MODIFIER__VISIBLE {
                                l.trim().to_string()
                             } else {
                                 // we only save the first error
                                 if file_syntax_test2.is_ok() {
                                    file_syntax_test2 = Err(ConfigParseError::LineIdentifier {
                                        line_number: n+1, line: l.to_string() });
                                 };
                                // This will never be used but we have to return something
                                "".to_string()
                             }
                        }
            )
            .collect::<Vec<String>>();

        if file_syntax_test1.is_err() {
            return Err(file_syntax_test1.unwrap_err());
        };
        if file_syntax_test2.is_err() {
            return Err(file_syntax_test2.unwrap_err());
        };

        if wordlist.is_empty() {
            return Err(ConfigParseError::NoSecretString {});
        }

        Ok(Dict {
            wordlist,
            rewarding_scheme,
        })
    }

    /// Chooses randomly one secret from the dictionary.
    pub fn get_random_word(&self) -> String {
        let mut rng = thread_rng();
        (&self.wordlist).choose(&mut rng).unwrap().to_string()
    }
}

// ***********************

#[cfg(test)]
mod tests {
    use super::{ConfigParseError, Dict, RewardingScheme};

    /// parse all 3 data types in configuration file format
    #[test]
    fn test_dictionary_parser_syntax() {
        let config: &str = "
#  comment

guess me
hang_man_
_good l_uck
:traditional-rewarding
";
        let dict = Dict::new(&config);
        let expected = Ok(Dict {
            wordlist: vec![
                "guess me".to_string(),
                "hang_man_".to_string(),
                "_good l_uck".to_string(),
            ],
            rewarding_scheme: RewardingScheme::UnhideWhenLostLife,
        });
        assert!(dict == expected);
    }

    /// indent of secrets is allowed
    #[test]
    fn test_dictionary_parser_indent() {
        let config: &str = "   guess me";
        let dict = Dict::new(&config);
        let expected = Ok(Dict {
            wordlist: vec!["guess me".to_string()],
            // this is default
            rewarding_scheme: RewardingScheme::UnhideWhenGuessedChar,
        });
        assert!(dict == expected);
    }

    /// indent of comments is not allowed
    #[test]
    fn test_dictionary_parser_error_indent() {
        let config = "\n\n\n   # comment";
        let dict = Dict::new(&config);
        let expected = Err(ConfigParseError::LineIdentifier {
            line_number: 4,
            line: "   # comment".to_string(),
        });
        assert!(dict == expected);
    }

    /// indent of game modifier is not allowed
    #[test]
    fn test_dictionary_parser_error_indent2() {
        let config = "\n\n\n\n :success-rewarding";
        let dict = Dict::new(&config);
        let expected = Err(ConfigParseError::LineIdentifier {
            line_number: 5,
            line: " :success-rewarding".to_string(),
        });
        assert!(dict == expected);
    }

    /// test game modifier spelling
    #[test]
    fn test_dictionary_parser_error_misspelled() {
        let config = "\n\n:traditional-rewardXing";
        let dict = Dict::new(&config);
        let expected = Err(ConfigParseError::GameModifier {
            line_number: 3,
            line: ":traditional-rewardXing".to_string(),
        });
        assert!(dict == expected);
    }

    /// configuration must define at least one secret
    #[test]
    fn test_dictionary_parser_error_no_secrets() {
        let config = "# nothing but comment";
        let dict = Dict::new(&config);
        let expected = Err(ConfigParseError::NoSecretString {});
        assert!(dict == expected);
    }
}
<|endoftext|>


<commit_before>//! The main event loop which performs I/O on the pseudoterminal
use std::borrow::Cow;
use std::collections::VecDeque;
use std::io::{self, ErrorKind, Write};
use std::fs::File;
use std::os::unix::io::AsRawFd;
use std::sync::Arc;

use mio::{self, Events, PollOpt, Ready};
use mio::unix::EventedFd;

use ansi;
use display;
use event;
use term::Term;
use util::thread;
use sync::FairMutex;

/// Messages that may be sent to the `EventLoop`
#[derive(Debug)]
pub enum Msg {
    /// Data that should be written to the pty
    Input(Cow<'static, [u8]>),

    /// Indicates that the `EvemtLoop` should shut down, as Alacritty is shutting down
    Shutdown
}

/// The main event!.. loop.
///
/// Handles all the pty I/O and runs the pty parser which updates terminal
/// state.
pub struct EventLoop<Io> {
    poll: mio::Poll,
    pty: Io,
    rx: mio::channel::Receiver<Msg>,
    tx: mio::channel::Sender<Msg>,
    terminal: Arc<FairMutex<Term>>,
    display: display::Notifier,
    ref_test: bool,
}

/// Helper type which tracks how much of a buffer has been written.
struct Writing {
    source: Cow<'static, [u8]>,
    written: usize,
}

/// All of the mutable state needed to run the event loop
///
/// Contains list of items to write, current write state, etc. Anything that
/// would otherwise be mutated on the `EventLoop` goes here.
pub struct State {
    write_list: VecDeque<Cow<'static, [u8]>>,
    writing: Option<Writing>,
    parser: ansi::Processor,
}

pub struct Notifier(pub ::mio::channel::Sender<Msg>);

impl event::Notify for Notifier {
    fn notify<B>(&mut self, bytes: B)
        where B: Into<Cow<'static, [u8]>>
    {
        let bytes = bytes.into();
        // terminal hangs if we send 0 bytes through.
        if bytes.len() == 0 {
            return
        }
        match self.0.send(Msg::Input(bytes)) {
            Ok(_) => (),
            Err(_) => panic!("expected send event loop msg"),
        }
    }
}

impl Default for State {
    fn default() -> State {
        State {
            write_list: VecDeque::new(),
            parser: ansi::Processor::new(),
            writing: None,
        }
    }
}

impl State {
    #[inline]
    fn ensure_next(&mut self) {
        if self.writing.is_none() {
            self.goto_next();
        }
    }

    #[inline]
    fn goto_next(&mut self) {
        self.writing = self.write_list
            .pop_front()
            .map(Writing::new);
    }

    #[inline]
    fn take_current(&mut self) -> Option<Writing> {
        self.writing.take()
    }

    #[inline]
    fn needs_write(&self) -> bool {
        self.writing.is_some() || !self.write_list.is_empty()
    }

    #[inline]
    fn set_current(&mut self, new: Option<Writing>) {
        self.writing = new;
    }
}

impl Writing {
    #[inline]
    fn new(c: Cow<'static, [u8]>) -> Writing {
        Writing { source: c, written: 0 }
    }

    #[inline]
    fn advance(&mut self, n: usize) {
        self.written += n;
    }

    #[inline]
    fn remaining_bytes(&self) -> &[u8] {
        &self.source[self.written..]
    }

    #[inline]
    fn finished(&self) -> bool {
        self.written >= self.source.len()
    }
}

/// `mio::Token` for the event loop channel
const CHANNEL: mio::Token = mio::Token(0);

/// `mio::Token` for the pty file descriptor
const PTY: mio::Token = mio::Token(1);

impl<Io> EventLoop<Io>
    where Io: io::Read + io::Write + Send + AsRawFd + 'static
{
    /// Create a new event loop
    pub fn new(
        terminal: Arc<FairMutex<Term>>,
        display: display::Notifier,
        pty: Io,
        ref_test: bool,
    ) -> EventLoop<Io> {
        let (tx, rx) = ::mio::channel::channel();
        EventLoop {
            poll: mio::Poll::new().expect("create mio Poll"),
            pty: pty,
            tx: tx,
            rx: rx,
            terminal: terminal,
            display: display,
            ref_test: ref_test,
        }
    }

    pub fn channel(&self) -> mio::channel::Sender<Msg> {
        self.tx.clone()
    }

    // Drain the channel
    //
    // Returns `Ok` if the `EventLoop` should continue running.
    // `Ok(true)`is returned if items were received
    //
    // An `Err` indicates that the event loop should shut down
    fn drain_recv_channel(&self, state: &mut State) -> Result<bool, ()> {
        let mut received_item = false;
        while let Ok(msg) = self.rx.try_recv() {
            received_item = true;
            match msg {
                Msg::Input(input) => {
                    state.write_list.push_back(input);
                },
                Msg::Shutdown => {
                    return Err(())
                }
            }
        }

        Ok(received_item)
    }

    // Returns a `bool` indicating whether or not the event loop should continue running
    #[inline]
    fn channel_event(&mut self, state: &mut State) -> bool {
        if self.drain_recv_channel(state).is_err() {
            return false;
        }

        self.poll.reregister(
            &self.rx, CHANNEL,
            Ready::readable(),
            PollOpt::edge() | PollOpt::oneshot()
        ).expect("reregister channel");

        if state.needs_write() {
            self.poll.reregister(
                &EventedFd(&self.pty.as_raw_fd()),
                PTY,
                Ready::readable() | Ready::writable(),
                PollOpt::edge() | PollOpt::oneshot()
            ).expect("reregister fd after channel recv");
        }
        true
    }

    #[inline]
    fn pty_read<W>(
        &mut self,
        state: &mut State,
        buf: &mut [u8],
        mut writer: Option<&mut W>
    ) -> io::Result<()>
        where W: Write
    {
        loop {
            match self.pty.read(&mut buf[..]) {
                Ok(0) => break,
                Ok(got) => {
                    writer = writer.map(|w| {
                        w.write_all(&buf[..got]).unwrap(); w
                    });

                    let mut terminal = self.terminal.lock();
                    for byte in &buf[..got] {
                        state.parser.advance(&mut *terminal, *byte, &mut self.pty);
                    }

                    // Only request a draw if one hasn't already been requested.
                    //
                    // This is a performance optimization even if only for X11
                    // which is very expensive to hammer on the even loop wakeup
                    if !terminal.dirty {
                        self.display.notify();
                        terminal.dirty = true;

                        // Break for writing
                        //
                        // Want to prevent case where reading always returns
                        // data and sequences like `C-c` cannot be sent.
                        //
                        // Doing this check in !terminal.dirty will prevent the
                        // condition from being checked overzealously.
                        //
                        // We want to break if `drain_recv_channel` returns either `Ok(true)`
                        // (new items came in for writing) or `Err` (we need to shut down)
                        if state.writing.is_some()
                            || !state.write_list.is_empty()
                            || self.drain_recv_channel(state).unwrap_or_else(|_| true)
                        {
                            break;
                        }
                    }
                },
                Err(err) => {
                    match err.kind() {
                        ErrorKind::Interrupted |
                        ErrorKind::WouldBlock => break,
                        _ => return Err(err),
                    }
                }
            }
        }

        Ok(())
    }

    #[inline]
    fn pty_write(&mut self, state: &mut State) -> io::Result<()> {
        state.ensure_next();

        'write_many: while let Some(mut current) = state.take_current() {
            'write_one: loop {
                match self.pty.write(current.remaining_bytes()) {
                    Ok(0) => {
                        state.set_current(Some(current));
                        break 'write_many;
                    },
                    Ok(n) => {
                        current.advance(n);
                        if current.finished() {
                            state.goto_next();
                            break 'write_one;
                        }
                    },
                    Err(err) => {
                        state.set_current(Some(current));
                        match err.kind() {
                            ErrorKind::Interrupted |
                            ErrorKind::WouldBlock => break 'write_many,
                            _ => return Err(err),
                        }
                    }
                }

            }
        }

        Ok(())
    }

    pub fn spawn(
        mut self,
        state: Option<State>
    ) -> thread::JoinHandle<(EventLoop<Io>, State)> {
        thread::spawn_named("pty reader", move || {
            let mut state = state.unwrap_or_else(Default::default);
            let mut buf = [0u8; 4096];

            let fd = self.pty.as_raw_fd();
            let fd = EventedFd(&fd);

            let poll_opts = PollOpt::edge() | PollOpt::oneshot();

            self.poll.register(&self.rx, CHANNEL, Ready::readable(), poll_opts).unwrap();
            self.poll.register(&fd, PTY, Ready::readable(), poll_opts).unwrap();

            let mut events = Events::with_capacity(1024);

            let mut pipe = if self.ref_test {
                let file = File::create("./alacritty.recording")
                    .expect("create alacritty recording");
                Some(file)
            } else {
                None
            };

            'event_loop: loop {
                if let Err(err) = self.poll.poll(&mut events, None) {
                    match err.kind() {
                        ErrorKind::Interrupted => continue,
                        _ => panic!("EventLoop polling error: {:?}", err)
                    }
                }

                for event in events.iter() {
                    match event.token() {
                        CHANNEL =>  {
                            if !self.channel_event(&mut state) {
                                break 'event_loop;
                            }
                        },
                        PTY => {
                            let kind = event.kind();

                            if kind.is_hup() {
                                break 'event_loop;
                            }

                            if kind.is_readable() {
                                if let Err(err) = self.pty_read(&mut state, &mut buf, pipe.as_mut()) {
                                    error!("Event loop exitting due to error: {} [{}:{}]",
                                           err, file!(), line!());
                                    break 'event_loop;
                                }

                                if ::tty::process_should_exit() {
                                    break 'event_loop;
                                }
                            }

                            if kind.is_writable() {
                                if let Err(err) = self.pty_write(&mut state) {
                                    error!("Event loop exitting due to error: {} [{}:{}]",
                                           err, file!(), line!());
                                    break 'event_loop;
                                }
                            }

                            // Figure out pty interest
                            let mut interest = Ready::readable();
                            if state.needs_write() {
                                interest.insert(Ready::writable());
                            }

                            // Reregister pty
                            self.poll
                                .reregister(&fd, PTY, interest, poll_opts)
                                .expect("register fd after read/write");
                        },
                        _ => (),
                    }
                }
            }

            let _ = self.poll.deregister(&self.rx);
            let _ = self.poll.deregister(&fd);

            (self, state)
        })
    }
}
<commit_msg>Fix typo<commit_after>//! The main event loop which performs I/O on the pseudoterminal
use std::borrow::Cow;
use std::collections::VecDeque;
use std::io::{self, ErrorKind, Write};
use std::fs::File;
use std::os::unix::io::AsRawFd;
use std::sync::Arc;

use mio::{self, Events, PollOpt, Ready};
use mio::unix::EventedFd;

use ansi;
use display;
use event;
use term::Term;
use util::thread;
use sync::FairMutex;

/// Messages that may be sent to the `EventLoop`
#[derive(Debug)]
pub enum Msg {
    /// Data that should be written to the pty
    Input(Cow<'static, [u8]>),

    /// Indicates that the `EventLoop` should shut down, as Alacritty is shutting down
    Shutdown
}

/// The main event!.. loop.
///
/// Handles all the pty I/O and runs the pty parser which updates terminal
/// state.
pub struct EventLoop<Io> {
    poll: mio::Poll,
    pty: Io,
    rx: mio::channel::Receiver<Msg>,
    tx: mio::channel::Sender<Msg>,
    terminal: Arc<FairMutex<Term>>,
    display: display::Notifier,
    ref_test: bool,
}

/// Helper type which tracks how much of a buffer has been written.
struct Writing {
    source: Cow<'static, [u8]>,
    written: usize,
}

/// All of the mutable state needed to run the event loop
///
/// Contains list of items to write, current write state, etc. Anything that
/// would otherwise be mutated on the `EventLoop` goes here.
pub struct State {
    write_list: VecDeque<Cow<'static, [u8]>>,
    writing: Option<Writing>,
    parser: ansi::Processor,
}

pub struct Notifier(pub ::mio::channel::Sender<Msg>);

impl event::Notify for Notifier {
    fn notify<B>(&mut self, bytes: B)
        where B: Into<Cow<'static, [u8]>>
    {
        let bytes = bytes.into();
        // terminal hangs if we send 0 bytes through.
        if bytes.len() == 0 {
            return
        }
        match self.0.send(Msg::Input(bytes)) {
            Ok(_) => (),
            Err(_) => panic!("expected send event loop msg"),
        }
    }
}

impl Default for State {
    fn default() -> State {
        State {
            write_list: VecDeque::new(),
            parser: ansi::Processor::new(),
            writing: None,
        }
    }
}

impl State {
    #[inline]
    fn ensure_next(&mut self) {
        if self.writing.is_none() {
            self.goto_next();
        }
    }

    #[inline]
    fn goto_next(&mut self) {
        self.writing = self.write_list
            .pop_front()
            .map(Writing::new);
    }

    #[inline]
    fn take_current(&mut self) -> Option<Writing> {
        self.writing.take()
    }

    #[inline]
    fn needs_write(&self) -> bool {
        self.writing.is_some() || !self.write_list.is_empty()
    }

    #[inline]
    fn set_current(&mut self, new: Option<Writing>) {
        self.writing = new;
    }
}

impl Writing {
    #[inline]
    fn new(c: Cow<'static, [u8]>) -> Writing {
        Writing { source: c, written: 0 }
    }

    #[inline]
    fn advance(&mut self, n: usize) {
        self.written += n;
    }

    #[inline]
    fn remaining_bytes(&self) -> &[u8] {
        &self.source[self.written..]
    }

    #[inline]
    fn finished(&self) -> bool {
        self.written >= self.source.len()
    }
}

/// `mio::Token` for the event loop channel
const CHANNEL: mio::Token = mio::Token(0);

/// `mio::Token` for the pty file descriptor
const PTY: mio::Token = mio::Token(1);

impl<Io> EventLoop<Io>
    where Io: io::Read + io::Write + Send + AsRawFd + 'static
{
    /// Create a new event loop
    pub fn new(
        terminal: Arc<FairMutex<Term>>,
        display: display::Notifier,
        pty: Io,
        ref_test: bool,
    ) -> EventLoop<Io> {
        let (tx, rx) = ::mio::channel::channel();
        EventLoop {
            poll: mio::Poll::new().expect("create mio Poll"),
            pty: pty,
            tx: tx,
            rx: rx,
            terminal: terminal,
            display: display,
            ref_test: ref_test,
        }
    }

    pub fn channel(&self) -> mio::channel::Sender<Msg> {
        self.tx.clone()
    }

    // Drain the channel
    //
    // Returns `Ok` if the `EventLoop` should continue running.
    // `Ok(true)`is returned if items were received
    //
    // An `Err` indicates that the event loop should shut down
    fn drain_recv_channel(&self, state: &mut State) -> Result<bool, ()> {
        let mut received_item = false;
        while let Ok(msg) = self.rx.try_recv() {
            received_item = true;
            match msg {
                Msg::Input(input) => {
                    state.write_list.push_back(input);
                },
                Msg::Shutdown => {
                    return Err(())
                }
            }
        }

        Ok(received_item)
    }

    // Returns a `bool` indicating whether or not the event loop should continue running
    #[inline]
    fn channel_event(&mut self, state: &mut State) -> bool {
        if self.drain_recv_channel(state).is_err() {
            return false;
        }

        self.poll.reregister(
            &self.rx, CHANNEL,
            Ready::readable(),
            PollOpt::edge() | PollOpt::oneshot()
        ).expect("reregister channel");

        if state.needs_write() {
            self.poll.reregister(
                &EventedFd(&self.pty.as_raw_fd()),
                PTY,
                Ready::readable() | Ready::writable(),
                PollOpt::edge() | PollOpt::oneshot()
            ).expect("reregister fd after channel recv");
        }
        true
    }

    #[inline]
    fn pty_read<W>(
        &mut self,
        state: &mut State,
        buf: &mut [u8],
        mut writer: Option<&mut W>
    ) -> io::Result<()>
        where W: Write
    {
        loop {
            match self.pty.read(&mut buf[..]) {
                Ok(0) => break,
                Ok(got) => {
                    writer = writer.map(|w| {
                        w.write_all(&buf[..got]).unwrap(); w
                    });

                    let mut terminal = self.terminal.lock();
                    for byte in &buf[..got] {
                        state.parser.advance(&mut *terminal, *byte, &mut self.pty);
                    }

                    // Only request a draw if one hasn't already been requested.
                    //
                    // This is a performance optimization even if only for X11
                    // which is very expensive to hammer on the even loop wakeup
                    if !terminal.dirty {
                        self.display.notify();
                        terminal.dirty = true;

                        // Break for writing
                        //
                        // Want to prevent case where reading always returns
                        // data and sequences like `C-c` cannot be sent.
                        //
                        // Doing this check in !terminal.dirty will prevent the
                        // condition from being checked overzealously.
                        //
                        // We want to break if `drain_recv_channel` returns either `Ok(true)`
                        // (new items came in for writing) or `Err` (we need to shut down)
                        if state.writing.is_some()
                            || !state.write_list.is_empty()
                            || self.drain_recv_channel(state).unwrap_or_else(|_| true)
                        {
                            break;
                        }
                    }
                },
                Err(err) => {
                    match err.kind() {
                        ErrorKind::Interrupted |
                        ErrorKind::WouldBlock => break,
                        _ => return Err(err),
                    }
                }
            }
        }

        Ok(())
    }

    #[inline]
    fn pty_write(&mut self, state: &mut State) -> io::Result<()> {
        state.ensure_next();

        'write_many: while let Some(mut current) = state.take_current() {
            'write_one: loop {
                match self.pty.write(current.remaining_bytes()) {
                    Ok(0) => {
                        state.set_current(Some(current));
                        break 'write_many;
                    },
                    Ok(n) => {
                        current.advance(n);
                        if current.finished() {
                            state.goto_next();
                            break 'write_one;
                        }
                    },
                    Err(err) => {
                        state.set_current(Some(current));
                        match err.kind() {
                            ErrorKind::Interrupted |
                            ErrorKind::WouldBlock => break 'write_many,
                            _ => return Err(err),
                        }
                    }
                }

            }
        }

        Ok(())
    }

    pub fn spawn(
        mut self,
        state: Option<State>
    ) -> thread::JoinHandle<(EventLoop<Io>, State)> {
        thread::spawn_named("pty reader", move || {
            let mut state = state.unwrap_or_else(Default::default);
            let mut buf = [0u8; 4096];

            let fd = self.pty.as_raw_fd();
            let fd = EventedFd(&fd);

            let poll_opts = PollOpt::edge() | PollOpt::oneshot();

            self.poll.register(&self.rx, CHANNEL, Ready::readable(), poll_opts).unwrap();
            self.poll.register(&fd, PTY, Ready::readable(), poll_opts).unwrap();

            let mut events = Events::with_capacity(1024);

            let mut pipe = if self.ref_test {
                let file = File::create("./alacritty.recording")
                    .expect("create alacritty recording");
                Some(file)
            } else {
                None
            };

            'event_loop: loop {
                if let Err(err) = self.poll.poll(&mut events, None) {
                    match err.kind() {
                        ErrorKind::Interrupted => continue,
                        _ => panic!("EventLoop polling error: {:?}", err)
                    }
                }

                for event in events.iter() {
                    match event.token() {
                        CHANNEL =>  {
                            if !self.channel_event(&mut state) {
                                break 'event_loop;
                            }
                        },
                        PTY => {
                            let kind = event.kind();

                            if kind.is_hup() {
                                break 'event_loop;
                            }

                            if kind.is_readable() {
                                if let Err(err) = self.pty_read(&mut state, &mut buf, pipe.as_mut()) {
                                    error!("Event loop exitting due to error: {} [{}:{}]",
                                           err, file!(), line!());
                                    break 'event_loop;
                                }

                                if ::tty::process_should_exit() {
                                    break 'event_loop;
                                }
                            }

                            if kind.is_writable() {
                                if let Err(err) = self.pty_write(&mut state) {
                                    error!("Event loop exitting due to error: {} [{}:{}]",
                                           err, file!(), line!());
                                    break 'event_loop;
                                }
                            }

                            // Figure out pty interest
                            let mut interest = Ready::readable();
                            if state.needs_write() {
                                interest.insert(Ready::writable());
                            }

                            // Reregister pty
                            self.poll
                                .reregister(&fd, PTY, interest, poll_opts)
                                .expect("register fd after read/write");
                        },
                        _ => (),
                    }
                }
            }

            let _ = self.poll.deregister(&self.rx);
            let _ = self.poll.deregister(&fd);

            (self, state)
        })
    }
}
<|endoftext|>


<commit_before>
pub struct Events {
    up: bool,
    down: bool,
    left: bool,
    right: bool,
}

impl Events {
    pub fn is_up() -> bool {
        self.up
    }

    pub fn is_down() -> bool {
        self.down
    }

    pub fn is_left() -> bool {
        self.left
    }

    pub fn is_right() -> bool {
        self.right
    }

    pub fn process_input(&mut self, input: &piston_window::Input) {
        use piston_window::{Input, Button, Key};

        match input {
            &Input::Press(button) => {
                match button {
                    Button::Keyboard(Key::Up) => { self.up = true; }
                    Button::Keyboard(Key::Down) => { self.down = true; }
                    Button::Keyboard(Key::Left) => { self.left = true; }
                    Button::Keyboard(Key::Right) => { self.right = true; }
                    _ => {}
                }
            }
            &Input::Release(button) => {
                match button {
                    Button::Keyboard(Key::Up) => { self.up = false; }
                    Button::Keyboard(Key::Down) => { self.down = false; }
                    Button::Keyboard(Key::Left) => { self.left = false; }
                    Button::Keyboard(Key::Right) => { self.right = false; }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}
<commit_msg>Evens methods fix (self parameter)<commit_after>
pub struct Events {
    up: bool,
    down: bool,
    left: bool,
    right: bool,
}

impl Events {
    pub fn is_up(&self) -> bool {
        self.up
    }

    pub fn is_down(&self) -> bool {
        self.down
    }

    pub fn is_left(&self) -> bool {
        self.left
    }

    pub fn is_right(&self) -> bool {
        self.right
    }

    pub fn process_input(&mut self, input: &piston_window::Input) {
        use piston_window::{Input, Button, Key};

        match input {
            &Input::Press(button) => {
                match button {
                    Button::Keyboard(Key::Up) => { self.up = true; }
                    Button::Keyboard(Key::Down) => { self.down = true; }
                    Button::Keyboard(Key::Left) => { self.left = true; }
                    Button::Keyboard(Key::Right) => { self.right = true; }
                    _ => {}
                }
            }
            &Input::Release(button) => {
                match button {
                    Button::Keyboard(Key::Up) => { self.up = false; }
                    Button::Keyboard(Key::Down) => { self.down = false; }
                    Button::Keyboard(Key::Left) => { self.left = false; }
                    Button::Keyboard(Key::Right) => { self.right = false; }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>pub fn basename(input: &str) -> &str {
    let mut index = 0;
    for (id, character) in input.bytes().enumerate() {
        if character == b'/' {
            index = id;
        }
    }
    if index == 0 {
        input
    } else {
        &input[index + 1..]
    }
}

/// Removes the extension of a given input
pub fn remove_extension(input: &str) -> &str {
    let mut dir_index = 0;
    let mut ext_index = 0;

    for (id, character) in input.bytes().enumerate() {
        if character == b'/' {
            dir_index = id;
        }
        if character == b'.' {
            ext_index = id;
        }
    }

    // Account for hidden files and directories
    if ext_index == 0 || dir_index + 2 > ext_index {
        input
    } else {
        &input[0..ext_index]
    }
}

pub fn dirname(input: &str) -> &str {
    let mut index = 0;
    for (id, character) in input.bytes().enumerate() {
        if character == b'/' {
            index = id;
        }
    }
    if index == 0 { "." } else { &input[0..index] }
}

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

    #[test]
    fn path_remove_ext_simple() {
        assert_eq!(remove_extension("foo.txt"), "foo");
    }

    #[test]
    fn path_remove_ext_dir() {
        assert_eq!(remove_extension("dir/foo.txt"), "dir/foo");
    }

    #[test]
    fn path_hidden() {
        assert_eq!(remove_extension(".foo"), ".foo")
    }

    #[test]
    fn path_remove_ext_utf8() {
        assert_eq!(remove_extension("💖.txt"), "💖");
    }

    #[test]
    fn path_remove_ext_empty() {
        assert_eq!(remove_extension(""), "");
    }

    #[test]
    fn path_basename_simple() {
        assert_eq!(basename("foo.txt"), "foo.txt");
    }

    #[test]
    fn path_basename_dir() {
        assert_eq!(basename("dir/foo.txt"), "foo.txt");
    }

    #[test]
    fn path_basename_empty() {
        assert_eq!(basename(""), "");
    }

    #[test]
    fn path_basename_utf8() {
        assert_eq!(basename("💖/foo.txt"), "foo.txt");
        assert_eq!(basename("dir/💖.txt"), "💖.txt");
    }

    #[test]
    fn path_dirname_simple() {
        assert_eq!(dirname("foo.txt"), ".");
    }

    #[test]
    fn path_dirname_dir() {
        assert_eq!(dirname("dir/foo.txt"), "dir");
    }

    #[test]
    fn path_dirname_utf8() {
        assert_eq!(dirname("💖/foo.txt"), "💖");
        assert_eq!(dirname("dir/💖.txt"), "dir");
    }

    #[test]
    fn path_dirname_empty() {
        assert_eq!(dirname(""), ".");
    }
}
<commit_msg>Handle OS-specific path separators when manipulating paths<commit_after>use std::path::MAIN_SEPARATOR;

pub fn basename(input: &str) -> &str {
    let mut index = 0;
    for (id, character) in input.char_indices() {
        if character == MAIN_SEPARATOR {
            index = id;
        }
    }
    if index == 0 {
        input
    } else {
        &input[index + 1..]
    }
}

/// Removes the extension of a given input
pub fn remove_extension(input: &str) -> &str {
    let mut dir_index = 0;
    let mut ext_index = 0;

    for (id, character) in input.char_indices() {
        if character == MAIN_SEPARATOR {
            dir_index = id;
        }
        if character == '.' {
            ext_index = id;
        }
    }

    // Account for hidden files and directories
    if ext_index == 0 || dir_index + 2 > ext_index {
        input
    } else {
        &input[0..ext_index]
    }
}

pub fn dirname(input: &str) -> &str {
    let mut index = 0;
    for (id, character) in input.char_indices() {
        if character == MAIN_SEPARATOR {
            index = id;
        }
    }
    if index == 0 { "." } else { &input[0..index] }
}

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

    fn correct(input: &str) -> String {
        let mut sep = String::new();
        sep.push(MAIN_SEPARATOR);
        input.replace('/', &sep)
    }

    #[test]
    fn path_remove_ext_simple() {
        assert_eq!(remove_extension("foo.txt"), "foo");
    }

    #[test]
    fn path_remove_ext_dir() {
        assert_eq!(
            remove_extension(&correct("dir/foo.txt")),
            &correct("dir/foo")
        );
    }

    #[test]
    fn path_hidden() {
        assert_eq!(remove_extension(".foo"), ".foo")
    }

    #[test]
    fn path_remove_ext_utf8() {
        assert_eq!(remove_extension("💖.txt"), "💖");
    }

    #[test]
    fn path_remove_ext_empty() {
        assert_eq!(remove_extension(""), "");
    }

    #[test]
    fn path_basename_simple() {
        assert_eq!(basename("foo.txt"), "foo.txt");
    }

    #[test]
    fn path_basename_dir() {
        assert_eq!(basename(&correct("dir/foo.txt")), "foo.txt");
    }

    #[test]
    fn path_basename_empty() {
        assert_eq!(basename(""), "");
    }

    #[test]
    fn path_basename_utf8() {
        assert_eq!(basename(&correct("💖/foo.txt")), "foo.txt");
        assert_eq!(basename(&correct("dir/💖.txt")), "💖.txt");
    }

    #[test]
    fn path_dirname_simple() {
        assert_eq!(dirname("foo.txt"), ".");
    }

    #[test]
    fn path_dirname_dir() {
        assert_eq!(dirname(&correct("dir/foo.txt")), "dir");
    }

    #[test]
    fn path_dirname_utf8() {
        assert_eq!(dirname(&correct("💖/foo.txt")), "💖");
        assert_eq!(dirname(&correct("dir/💖.txt")), "dir");
    }

    #[test]
    fn path_dirname_empty() {
        assert_eq!(dirname(""), ".");
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::cell::Cell;

/// The Memory Management Unit.
/// Provides access to all mapped memory in the system, including I/O and graphics.
pub struct MMU {
    pub loading_bios: Cell<bool>,
    data: [u8; 65536],
}

impl fmt::Debug for MMU {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MMU 64k")
    }
}

impl MMU {
    pub fn new() -> MMU {
        MMU {
            loading_bios: Cell::new(true),
            data: [1; 65536],
        }
    }

    /// reads a byte at the memory address specified
    pub fn read_b(&self, addr: u16) -> u8 {
        // when PC first reaches 0x100, the BIOS data is not addressable anymore.
        // using Cell sucks, but this is one of the few cases mentioned by official docs where
        // it is an option. Read is logically an immutable operation, but we need to make the
        // bios unaddressable after its first read.
        if self.loading_bios.get() && addr == 0x0100 {
            self.loading_bios.set(false);
        }

        match addr {
            // bios area, 256B long for regular gameboy.
            0...0x00FF if self.loading_bios.get() => 0,
            // ROM0 area, this is banked memory, it will swap according to selected bank
            0x0000...0x3FFF if !self.loading_bios.get() => 0,
            // ROM1 area, 16kB unbanked data
            0x4000...0x7FFF => 0,
            // Graphics, 8kB VRAM
            0x8000...0x9FFF => 0,
            // Switchable RAM bank, 8kB
            0xA000...0xBFFF => {
                // TODO: handle RAM banks
                self.data[addr as usize]
            }
            // Internal RAM, 8kB
            0xC000...0xDFFF => self.data[addr as usize],
            // Echo of internal RAM, this is less than 8k, up to 0xFDFF,
            0xE000...0xFDFF => {
                // TODO: change address to go to actual RAM location
                0
            }
            // Sprite attribute memory, 160B
            0xFE00...0xFE9F => 0,
            // empty
            0xFEA0...0xFEFF | 0xFF4C...0xFF7F => 0,
            // I/O ports
            0xFF00...0xFF4B => 0,
            // More internal RAM
            0xFF80...0xFFFE => 0,
            // Interrupt Enable register
            0xFFFF => 0,

            _ => self.data[addr as usize],
        }
    }

    pub fn write_b(&mut self, addr: u16, data: u8) {
        self.data[addr as usize] = data;
    }
}
<commit_msg>RAM mirroring in read<commit_after>use std::fmt;
use std::cell::Cell;

/// The Memory Management Unit.
/// Provides access to all mapped memory in the system, including I/O and graphics.
pub struct MMU {
    pub loading_bios: Cell<bool>,
    data: [u8; 65536],
}

impl fmt::Debug for MMU {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MMU 64k")
    }
}

impl MMU {
    pub fn new() -> MMU {
        MMU {
            loading_bios: Cell::new(true),
            data: [1; 65536],
        }
    }

    /// reads a byte at the memory address specified
    pub fn read_b(&self, addr: u16) -> u8 {
        // when PC first reaches 0x100, the BIOS data is not addressable anymore.
        // using Cell sucks, but this is one of the few cases mentioned by official docs where
        // it is an option. Read is logically an immutable operation, but we need to make the
        // bios unaddressable after its first read.
        if self.loading_bios.get() && addr == 0x0100 {
            self.loading_bios.set(false);
        }

        match addr {
            // bios area, 256B long for regular gameboy.
            0...0x00FF if self.loading_bios.get() => 0,
            // ROM0 area, this is banked memory, it will swap according to selected bank
            0x0000...0x3FFF if !self.loading_bios.get() => 0,
            // ROM1 area, 16kB unbanked data
            0x4000...0x7FFF => 0,
            // Graphics, 8kB VRAM
            0x8000...0x9FFF => 0,
            // Switchable RAM bank, 8kB
            0xA000...0xBFFF => {
                // TODO: handle RAM banks
                self.data[addr as usize]
            }
            // Internal RAM, 8kB
            0xC000...0xDFFF => self.data[addr as usize],
            // Echo of internal RAM, this is less than 8k, up to 0xFDFF,
            0xE000...0xFDFF => self.data[(addr - 0x2000) as usize],
            // Sprite attribute memory, 160B
            0xFE00...0xFE9F => 0,
            // empty
            0xFEA0...0xFEFF | 0xFF4C...0xFF7F => 0,
            // I/O ports
            0xFF00...0xFF4B => 0,
            // More internal RAM
            0xFF80...0xFFFE => 0,
            // Interrupt Enable register
            0xFFFF => 0,

            _ => panic!("tried to write at unkown address: {:4X}", addr)
        }
    }

    pub fn write_b(&mut self, addr: u16, data: u8) {
        self.data[addr as usize] = data;
    }
}
<|endoftext|>


<commit_before>pub mod files;

use std::cmp;
use std::iter;
use std::io::Write;

const MAX_PATCH_LEN: usize = 0xFFFF;

#[derive(Debug)]
pub struct Ips {
    buffer: Vec<u8>
}

impl Ips {
    pub fn new(buffer: &Vec<u8>) -> Self {
        Ips {
            buffer: buffer.clone()
        }
    }

    pub fn diff(&self, change: &Vec<u8>) -> Vec<Patch> {
        let (change_within, additional) = change.split_at(self.buffer.len());
        let mut pairs = (0..).zip(self.buffer.iter().zip(change_within));

        let mut patches: Vec<Patch> = vec![];
        let mut index = 0;
        let mut data = vec![];

        while let Some((offset, (&before, &after))) = pairs.next() {
            if before != after {
                if data.is_empty() {
                    index = offset;
                }
                data.push(after);
            } else if ! data.is_empty() {
                let patch = Patch::new(index, data);
                patches.push(patch);
                data = vec![];
            }
        };

        for chunk in additional.chunks(MAX_PATCH_LEN) {
            let patch = Patch::new(self.buffer.len() as u32, chunk.to_vec());
            patches.push(patch);
        }

        patches
    }

    pub fn patch(&self, change: &Vec<Patch>) -> Vec<u8> {
        let total_size = cmp::max(self.buffer.len(), patch_max_len(&change).unwrap());

        let mut output = Vec::with_capacity(total_size);
        output.write(&self.buffer);

        for patch in change {
            {
                let (_, mut skipped) = output.split_at_mut(patch.addr as usize);
                skipped.write(&patch.data())
            }.map(|written_len| {
                let data = patch.data();
                let (_, unwritten_data) = data.split_at(written_len);
                for &b in unwritten_data {
                    output.push(b);
                }
            });
        }
        output
    }

}

pub fn patch_max_len(patch: &[Patch]) -> Option<usize> {
    patch.iter().map(|x| x.addr as usize + x.data().len()).max()
}

pub fn serialize_patches(patches: Vec<Patch>) -> Vec<u8> {
    let patch_contents: Vec<u8> = patches.iter().flat_map(|p| p.bytes()).collect();
    let mut binary: Vec<u8> = b"PATCH".to_vec();
    binary.extend(patch_contents);
    binary.extend(b"EOF".to_vec());
    binary
}

pub fn unserialize_patches(binary: Vec<u8>) -> Option<Vec<Patch>> {
    let mut patches: Vec<Patch> = Vec::new();

    let slice = &binary;
    let (header, mut slice) = slice.split_at(5);

    if header != b"PATCH" {
        return None;
    }

    loop {
        // TODO support RLE'd patches
        let (addr_slice, rest) = slice.split_at(3);
        let (len_slice, rest) = rest.split_at(2);

        if (! addr_slice.is_empty()) && len_slice.len() < 2 {
            // Malformed data
            return None;
        }

        let mut addr_array = [0; 3];
        addr_array.clone_from_slice(addr_slice);
        let addr = Patch::unserialize_addr_array(addr_array);

        let mut len_array = [0; 2];
        len_array.clone_from_slice(len_slice);
        let len = Patch::unserialize_len(len_array);

        if rest.len() < len {
            // Malformed data
            return None;
        }

        let (patch, rest) = if len == 0 {
            // should decode RLE
            let (rle_len_slice, rest) = rest.split_at(2);

            let mut rle_len_array = [0; 2];
            rle_len_array.clone_from_slice(rle_len_slice);
            let rle_len = Patch::unserialize_len(rle_len_array);

            let (rle_val_slice, rest) = rest.split_at(1);
            let rle_val = rle_val_slice[0];

            let patch = Patch::new(addr, from_rle(rle_len, rle_val));
            (patch, rest)
        } else {
            let (data, rest) = rest.split_at(len);

            (Patch::new(addr, data.to_vec()), rest)
        };

        patches.push(patch);

        slice = rest;

        let possible_eof: Vec<u8> = rest.iter().take(3).cloned().collect();
        if &possible_eof == b"EOF" {
            // We are done here
            break;
        }
    }

    Some(patches)
}

pub fn into_rle(data: Vec<u8>) -> (usize, u8) {
    (data.len(), data[0])
}

pub fn from_rle(len: usize, val: u8) -> Vec<u8> {
    iter::repeat(val).take(len).collect()
}

#[derive(Debug, PartialEq, Clone)]
pub struct Patch {
    addr: u32,
    data: Vec<u8>
}

impl Patch {
    pub fn new(addr: u32, data: Vec<u8>) -> Self {
        assert!(addr <= 0xFFFFFF);
        Patch {
            addr: addr,
            data: data
        }
    }

    pub fn data(&self) -> &Vec<u8> {
        &self.data
    }

    pub fn bytes(&self) -> Vec<u8> {
        let mut bytes: Vec<u8> = self.serialize_addr();
        let len = self.serialize_len();
        bytes.extend(len);
        bytes.extend(self.data());
        bytes
    }

    pub fn unserialize_addr_array(addr: [u8; 3]) -> u32 {
        ((addr[0] as u32) << 16) | ((addr[1] as u32) << 8) | addr[2] as u32
    }

    pub fn serialize_addr(&self) -> Vec<u8> {
        vec![(self.addr >> 16) as u8, (self.addr >> 8) as u8, self.addr as u8]
    }

    pub fn unserialize_len(addr: [u8; 2]) -> usize {
        (((addr[0] as u32) << 8) | addr[1] as u32) as usize
    }

    pub fn serialize_len(&self) -> Vec<u8> {
        vec![(self.data().len() >> 8) as u8, self.data().len() as u8]
    }
}
<commit_msg>Simplify expression<commit_after>pub mod files;

use std::cmp;
use std::iter;
use std::io::Write;

const MAX_PATCH_LEN: usize = 0xFFFF;

#[derive(Debug)]
pub struct Ips {
    buffer: Vec<u8>
}

impl Ips {
    pub fn new(buffer: &Vec<u8>) -> Self {
        Ips {
            buffer: buffer.clone()
        }
    }

    pub fn diff(&self, change: &Vec<u8>) -> Vec<Patch> {
        let (change_within, additional) = change.split_at(self.buffer.len());
        let mut pairs = (0..).zip(self.buffer.iter().zip(change_within));

        let mut patches: Vec<Patch> = vec![];
        let mut index = 0;
        let mut data = vec![];

        while let Some((offset, (&before, &after))) = pairs.next() {
            if before != after {
                if data.is_empty() {
                    index = offset;
                }
                data.push(after);
            } else if ! data.is_empty() {
                let patch = Patch::new(index, data);
                patches.push(patch);
                data = vec![];
            }
        };

        for chunk in additional.chunks(MAX_PATCH_LEN) {
            let patch = Patch::new(self.buffer.len() as u32, chunk.to_vec());
            patches.push(patch);
        }

        patches
    }

    pub fn patch(&self, change: &Vec<Patch>) -> Vec<u8> {
        let total_size = cmp::max(self.buffer.len(), patch_max_len(&change).unwrap());

        let mut output = Vec::with_capacity(total_size);
        output.write(&self.buffer);

        for patch in change {
            {
                let (_, mut skipped) = output.split_at_mut(patch.addr as usize);
                skipped.write(&patch.data())
            }.map(|written_len| {
                let data = patch.data();
                let (_, unwritten_data) = data.split_at(written_len);
                for &b in unwritten_data {
                    output.push(b);
                }
            });
        }
        output
    }

}

pub fn patch_max_len(patch: &[Patch]) -> Option<usize> {
    patch.iter().map(|x| x.addr as usize + x.data().len()).max()
}

pub fn serialize_patches(patches: Vec<Patch>) -> Vec<u8> {
    let patch_contents: Vec<u8> = patches.iter().flat_map(|p| p.bytes()).collect();
    let mut binary: Vec<u8> = b"PATCH".to_vec();
    binary.extend(patch_contents);
    binary.extend(b"EOF".to_vec());
    binary
}

pub fn unserialize_patches(binary: Vec<u8>) -> Option<Vec<Patch>> {
    let mut patches: Vec<Patch> = Vec::new();

    let slice = &binary;
    let (header, mut slice) = slice.split_at(5);

    if header != b"PATCH" {
        return None;
    }

    loop {
        // TODO support RLE'd patches
        let (addr_slice, rest) = slice.split_at(3);
        let (len_slice, rest) = rest.split_at(2);

        if (! addr_slice.is_empty()) && len_slice.len() < 2 {
            // Malformed data
            return None;
        }

        let mut addr_array = [0; 3];
        addr_array.clone_from_slice(addr_slice);
        let addr = Patch::unserialize_addr_array(addr_array);

        let mut len_array = [0; 2];
        len_array.clone_from_slice(len_slice);
        let len = Patch::unserialize_len(len_array);

        if rest.len() < len {
            // Malformed data
            return None;
        }

        let (patch, rest) = if len == 0 {
            // should decode RLE
            let (rle_len_slice, rest) = rest.split_at(2);

            let mut rle_len_array = [0; 2];
            rle_len_array.clone_from_slice(rle_len_slice);
            let rle_len = Patch::unserialize_len(rle_len_array);

            let (rle_val_slice, rest) = rest.split_at(1);
            let rle_val = rle_val_slice[0];

            let patch = Patch::new(addr, from_rle(rle_len, rle_val));
            (patch, rest)
        } else {
            let (data, rest) = rest.split_at(len);

            (Patch::new(addr, data.to_vec()), rest)
        };

        patches.push(patch);

        slice = rest;

        let (possible_eof, _) = rest.split_at(3);
        if possible_eof == b"EOF" {
            // We are done here
            break;
        }
    }

    Some(patches)
}

pub fn into_rle(data: Vec<u8>) -> (usize, u8) {
    (data.len(), data[0])
}

pub fn from_rle(len: usize, val: u8) -> Vec<u8> {
    iter::repeat(val).take(len).collect()
}

#[derive(Debug, PartialEq, Clone)]
pub struct Patch {
    addr: u32,
    data: Vec<u8>
}

impl Patch {
    pub fn new(addr: u32, data: Vec<u8>) -> Self {
        assert!(addr <= 0xFFFFFF);
        Patch {
            addr: addr,
            data: data
        }
    }

    pub fn data(&self) -> &Vec<u8> {
        &self.data
    }

    pub fn bytes(&self) -> Vec<u8> {
        let mut bytes: Vec<u8> = self.serialize_addr();
        let len = self.serialize_len();
        bytes.extend(len);
        bytes.extend(self.data());
        bytes
    }

    pub fn unserialize_addr_array(addr: [u8; 3]) -> u32 {
        ((addr[0] as u32) << 16) | ((addr[1] as u32) << 8) | addr[2] as u32
    }

    pub fn serialize_addr(&self) -> Vec<u8> {
        vec![(self.addr >> 16) as u8, (self.addr >> 8) as u8, self.addr as u8]
    }

    pub fn unserialize_len(addr: [u8; 2]) -> usize {
        (((addr[0] as u32) << 8) | addr[1] as u32) as usize
    }

    pub fn serialize_len(&self) -> Vec<u8> {
        vec![(self.data().len() >> 8) as u8, self.data().len() as u8]
    }
}
<|endoftext|>


<commit_before>use {
  crate::{
    grammar::Prod,
    parsers::{
      tree::{Node, TreeHandle},
      Token,
    },
    start_grammar::{StartElementTypes, StartGrammar, StreamTerminal},
    state::ProdState,
    utils::{change_iter, WasChanged},
    ElementTypes,
  },
  im::Vector,
  std::collections::{btree_map, BTreeMap},
};

#[derive(Derivative)]
#[derivative(
  Clone(bound = ""),
  Eq(bound = ""),
  PartialEq(bound = ""),
  Ord(bound = ""),
  PartialOrd(bound = ""),
  Debug(bound = "")
)]
struct EarleyStateKey<'a, E: ElementTypes> {
  prod_state: ProdState<'a, StartElementTypes<E>>,
  origin_index: usize,
}

impl<'a, E: ElementTypes> EarleyStateKey<'a, E> {
  pub fn is_final_key(&self) -> bool {
    self
      .prod_state
      .next_elem()
      .and_then(|elem| elem.as_term())
      .map_or(false, StreamTerminal::is_eos)
  }
}

#[derive(Derivative)]
#[derivative(
  Clone(bound = ""),
  Eq(bound = ""),
  PartialEq(bound = ""),
  Ord(bound = ""),
  PartialOrd(bound = ""),
  Debug(bound = "")
)]
pub struct EarleyState<'a, E, T>
where
  E: ElementTypes,
{
  key: EarleyStateKey<'a, E>,
  #[derivative(Debug = "ignore")]
  value: Vector<Node<'a, E, T>>,
}

impl<'a, E, T> EarleyState<'a, E, T>
where
  E: ElementTypes,
  T: Ord + Clone,
{
  pub fn from_prod_start(
    prod: Prod<'a, StartElementTypes<E>>,
    index: usize,
  ) -> Self {
    EarleyState {
      key: EarleyStateKey {
        prod_state: ProdState::from_start(prod),
        origin_index: index,
      },
      value: Vector::new(),
    }
  }

  pub fn prod_state(&self) -> &ProdState<'a, StartElementTypes<E>> {
    &self.key.prod_state
  }

  pub fn create_next_value(
    &self,
    node: Node<'a, E, T>,
  ) -> Vector<Node<'a, E, T>> {
    let mut value = self.value.clone();
    value.push_back(node);
    value
  }

  pub fn predict(
    &self,
    grammar: &'a StartGrammar<E>,
    prev_states: &[EarleyStateSet<'a, E, T>],
  ) -> Vec<EarleyState<'a, E, T>> {
    self
      .prod_state()
      .next_elem()
      .iter()
      .filter_map(|nt| nt.as_nonterm())
      .filter_map(|nt| grammar.get_rule(nt))
      .flat_map(|r| r.prods())
      .map(|p| EarleyState {
        key: EarleyStateKey {
          prod_state: ProdState::from_start(p),
          origin_index: prev_states.len(),
        },
        value: Vector::new(),
      })
      .collect()
  }

  pub fn scan(
    &self,
    tree_handle: &TreeHandle<'a, E, T>,
    next_token: &Token<E::Term, T>,
  ) -> Option<EarleyState<'a, E, T>> {
    self
      .prod_state()
      .next_elem_state()
      .and_then(|(e, ps)| e.elem().as_term().map(move |t| (t, ps)))
      .filter(|(t, _)| t.has_kind(&next_token.kind))
      .map(|(_, ps)| EarleyState {
        key: EarleyStateKey {
          prod_state: ps,
          origin_index: self.key.origin_index,
        },
        value: self.create_next_value(
          tree_handle
            .make_leaf_node(next_token.kind.clone(), next_token.value.clone()),
        ),
      })
  }

  pub fn complete(
    &self,
    tree_handle: &TreeHandle<'a, E, T>,
    prev_states: &[EarleyStateSet<'a, E, T>],
    curr_state: &EarleyStateSet<'a, E, T>,
  ) -> Vec<EarleyState<'a, E, T>> {
    if self.prod_state().is_complete() {
      eprintln!("Completing prod state {:?}.", self.prod_state());
      let origin_state = if self.key.origin_index == prev_states.len() {
        curr_state
      } else {
        &prev_states[self.key.origin_index]
      };

      origin_state
        .states()
        .into_iter()
        .filter_map(|state| {
          state
            .prod_state()
            .next_elem_state()
            .map(|(e, ps)| (state, e, ps))
        })
        .filter_map(|(st, e, ps)| e.elem().as_nonterm().map(|nt| (st, nt, ps)))
        .filter(|(_, nt, _)| nt == &self.prod_state().prod().head())
        .map(|(st, _, ps)| EarleyState {
          key: EarleyStateKey {
            prod_state: ps,
            origin_index: st.key.origin_index,
          },
          value: st.create_next_value(tree_handle.make_branch_node(
            self.prod_state().action_key().as_base().unwrap().clone(),
            self.value.iter().cloned(),
          )),
        })
        .collect()
    } else {
      Vec::new()
    }
  }
}

pub struct EarleyStateSet<'a, E, T>
where
  E: ElementTypes,
{
  states: BTreeMap<EarleyStateKey<'a, E>, Vector<Node<'a, E, T>>>,
}

impl<'a, E, T> EarleyStateSet<'a, E, T>
where
  E: ElementTypes,
  T: Ord + Clone,
{
  pub fn new() -> Self {
    EarleyStateSet {
      states: BTreeMap::new(),
    }
  }

  pub fn new_start(grammar: &'a StartGrammar<E>) -> Self {
    let start_nt = grammar.start_nt();
    let start_rule =
      grammar.get_rule(start_nt).expect("Start NT must be valid.");
    EarleyStateSet::from_states(
      start_rule
        .prods()
        .map(|prod| EarleyState::from_prod_start(prod, 0)),
    )
  }

  pub fn from_states(
    iter: impl Iterator<Item = EarleyState<'a, E, T>>,
  ) -> Self {
    let mut state_set = EarleyStateSet::new();
    for state in iter {
      state_set.insert(&state);
    }

    state_set
  }

  pub fn states<'b>(
    &'b self,
  ) -> impl Iterator<Item = EarleyState<'a, E, T>> + 'b {
    self.states.iter().map(|(key, value)| EarleyState {
      key: key.clone(),
      value: value.clone(),
    })
  }

  pub fn insert(&mut self, state: &EarleyState<'a, E, T>) -> WasChanged {
    match self.states.entry(state.key.clone()) {
      btree_map::Entry::Vacant(vac) => {
        vac.insert(state.value.clone());
        WasChanged::Changed
      }
      btree_map::Entry::Occupied(mut occ) => {
        let existing_nodes = occ.get_mut();
        let new_nodes = &state.value;
        assert_eq!(existing_nodes.len(), new_nodes.len());
        change_iter(
          existing_nodes.iter_mut().zip(new_nodes),
          |(existing_node, new_node)| existing_node.add_all(new_node),
        )
      }
    }
  }

  pub fn shift(
    &self,
    tree_handle: &TreeHandle<'a, E, T>,
    token: &Token<E::Term, T>,
  ) -> Self {
    EarleyStateSet::from_states(
      self
        .states()
        .into_iter()
        .filter_map(|state| state.scan(tree_handle, token)),
    )
  }

  pub fn is_empty(&self) -> bool {
    self.states.is_empty()
  }

  pub fn get_final(&self) -> Option<&Node<'a, E, T>> {
    for (k, v) in &self.states {
      if k.is_final_key() {
        assert_eq!(v.len(), 1);
        return Some(v.get(0).unwrap());
      }
    }

    None
  }
}

impl<'a, E, T> std::fmt::Debug for EarleyStateSet<'a, E, T>
where
  E: ElementTypes,
  T: Ord + Clone,
{
  fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    f.debug_set().entries(self.states()).finish()
  }
}
<commit_msg>Cleanup on debug representations<commit_after>use {
  crate::{
    grammar::Prod,
    parsers::{
      tree::{Node, TreeHandle},
      Token,
    },
    start_grammar::{StartElementTypes, StartGrammar, StreamTerminal},
    state::ProdState,
    utils::{change_iter, WasChanged},
    ElementTypes,
  },
  im::Vector,
  std::collections::{btree_map, BTreeMap},
};

#[derive(Derivative)]
#[derivative(
  Clone(bound = ""),
  Eq(bound = ""),
  PartialEq(bound = ""),
  Ord(bound = ""),
  PartialOrd(bound = ""),
  Debug(bound = "")
)]
struct EarleyStateKey<'a, E: ElementTypes> {
  prod_state: ProdState<'a, StartElementTypes<E>>,
  origin_index: usize,
}

impl<'a, E: ElementTypes> EarleyStateKey<'a, E> {
  pub fn is_final_key(&self) -> bool {
    self
      .prod_state
      .next_elem()
      .and_then(|elem| elem.as_term())
      .map_or(false, StreamTerminal::is_eos)
  }
}

#[derive(Derivative)]
#[derivative(
  Clone(bound = ""),
  Eq(bound = ""),
  PartialEq(bound = ""),
  Ord(bound = ""),
  PartialOrd(bound = "")
)]
pub struct EarleyState<'a, E, T>
where
  E: ElementTypes,
{
  key: EarleyStateKey<'a, E>,
  #[derivative(Debug = "ignore")]
  value: Vector<Node<'a, E, T>>,
}

impl<'a, E, T> EarleyState<'a, E, T>
where
  E: ElementTypes,
  T: Ord + Clone,
{
  pub fn from_prod_start(
    prod: Prod<'a, StartElementTypes<E>>,
    index: usize,
  ) -> Self {
    EarleyState {
      key: EarleyStateKey {
        prod_state: ProdState::from_start(prod),
        origin_index: index,
      },
      value: Vector::new(),
    }
  }

  pub fn prod_state(&self) -> &ProdState<'a, StartElementTypes<E>> {
    &self.key.prod_state
  }

  pub fn create_next_value(
    &self,
    node: Node<'a, E, T>,
  ) -> Vector<Node<'a, E, T>> {
    let mut value = self.value.clone();
    value.push_back(node);
    value
  }

  pub fn predict(
    &self,
    grammar: &'a StartGrammar<E>,
    prev_states: &[EarleyStateSet<'a, E, T>],
  ) -> Vec<EarleyState<'a, E, T>> {
    self
      .prod_state()
      .next_elem()
      .iter()
      .filter_map(|nt| nt.as_nonterm())
      .filter_map(|nt| grammar.get_rule(nt))
      .flat_map(|r| r.prods())
      .map(|p| EarleyState {
        key: EarleyStateKey {
          prod_state: ProdState::from_start(p),
          origin_index: prev_states.len(),
        },
        value: Vector::new(),
      })
      .collect()
  }

  pub fn scan(
    &self,
    tree_handle: &TreeHandle<'a, E, T>,
    next_token: &Token<E::Term, T>,
  ) -> Option<EarleyState<'a, E, T>> {
    self
      .prod_state()
      .next_elem_state()
      .and_then(|(e, ps)| e.elem().as_term().map(move |t| (t, ps)))
      .filter(|(t, _)| t.has_kind(&next_token.kind))
      .map(|(_, ps)| EarleyState {
        key: EarleyStateKey {
          prod_state: ps,
          origin_index: self.key.origin_index,
        },
        value: self.create_next_value(
          tree_handle
            .make_leaf_node(next_token.kind.clone(), next_token.value.clone()),
        ),
      })
  }

  pub fn complete(
    &self,
    tree_handle: &TreeHandle<'a, E, T>,
    prev_states: &[EarleyStateSet<'a, E, T>],
    curr_state: &EarleyStateSet<'a, E, T>,
  ) -> Vec<EarleyState<'a, E, T>> {
    if self.prod_state().is_complete() {
      eprintln!("Completing prod state {:?}.", self.prod_state());
      let origin_state = if self.key.origin_index == prev_states.len() {
        curr_state
      } else {
        &prev_states[self.key.origin_index]
      };

      origin_state
        .states()
        .into_iter()
        .filter_map(|state| {
          state
            .prod_state()
            .next_elem_state()
            .map(|(e, ps)| (state, e, ps))
        })
        .filter_map(|(st, e, ps)| e.elem().as_nonterm().map(|nt| (st, nt, ps)))
        .filter(|(_, nt, _)| nt == &self.prod_state().prod().head())
        .map(|(st, _, ps)| EarleyState {
          key: EarleyStateKey {
            prod_state: ps,
            origin_index: st.key.origin_index,
          },
          value: st.create_next_value(tree_handle.make_branch_node(
            self.prod_state().action_key().as_base().unwrap().clone(),
            self.value.iter().cloned(),
          )),
        })
        .collect()
    } else {
      Vec::new()
    }
  }
}

impl<'a, E, T> std::fmt::Debug for EarleyState<'a, E, T>
where
  E: ElementTypes,
{
  fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    let mut st = f.debug_struct("EarleyState");
    st.field("prod_state", &self.key.prod_state);
    st.field("origin_index", &self.key.origin_index);
    st.field("value_len", &self.value.len());
    st.finish()
  }
}

pub struct EarleyStateSet<'a, E, T>
where
  E: ElementTypes,
{
  states: BTreeMap<EarleyStateKey<'a, E>, Vector<Node<'a, E, T>>>,
}

impl<'a, E, T> EarleyStateSet<'a, E, T>
where
  E: ElementTypes,
  T: Ord + Clone,
{
  pub fn new() -> Self {
    EarleyStateSet {
      states: BTreeMap::new(),
    }
  }

  pub fn new_start(grammar: &'a StartGrammar<E>) -> Self {
    let start_nt = grammar.start_nt();
    let start_rule =
      grammar.get_rule(start_nt).expect("Start NT must be valid.");
    EarleyStateSet::from_states(
      start_rule
        .prods()
        .map(|prod| EarleyState::from_prod_start(prod, 0)),
    )
  }

  pub fn from_states(
    iter: impl Iterator<Item = EarleyState<'a, E, T>>,
  ) -> Self {
    let mut state_set = EarleyStateSet::new();
    for state in iter {
      state_set.insert(&state);
    }

    state_set
  }

  pub fn states<'b>(
    &'b self,
  ) -> impl Iterator<Item = EarleyState<'a, E, T>> + 'b {
    self.states.iter().map(|(key, value)| EarleyState {
      key: key.clone(),
      value: value.clone(),
    })
  }

  pub fn insert(&mut self, state: &EarleyState<'a, E, T>) -> WasChanged {
    match self.states.entry(state.key.clone()) {
      btree_map::Entry::Vacant(vac) => {
        vac.insert(state.value.clone());
        WasChanged::Changed
      }
      btree_map::Entry::Occupied(mut occ) => {
        let existing_nodes = occ.get_mut();
        let new_nodes = &state.value;
        assert_eq!(existing_nodes.len(), new_nodes.len());
        change_iter(
          existing_nodes.iter_mut().zip(new_nodes),
          |(existing_node, new_node)| existing_node.add_all(new_node),
        )
      }
    }
  }

  pub fn shift(
    &self,
    tree_handle: &TreeHandle<'a, E, T>,
    token: &Token<E::Term, T>,
  ) -> Self {
    EarleyStateSet::from_states(
      self
        .states()
        .into_iter()
        .filter_map(|state| state.scan(tree_handle, token)),
    )
  }

  pub fn is_empty(&self) -> bool {
    self.states.is_empty()
  }

  pub fn get_final(&self) -> Option<&Node<'a, E, T>> {
    for (k, v) in &self.states {
      if k.is_final_key() {
        assert_eq!(v.len(), 1);
        return Some(v.get(0).unwrap());
      }
    }

    None
  }
}

impl<'a, E, T> std::fmt::Debug for EarleyStateSet<'a, E, T>
where
  E: ElementTypes,
  T: Ord + Clone,
{
  fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    f.debug_set().entries(self.states()).finish()
  }
}
<|endoftext|>


<commit_before>#[lang = "eh_personality"]
fn eh_personality() {}

#[lang = "panic_fmt"]
fn panic_fmt() {}
<commit_msg>convert panic_fmt to a extern fn<commit_after>#[lang = "eh_personality"]
fn eh_personality() {}

#[lang = "panic_fmt"]
extern fn panic_fmt() {}
<|endoftext|>


<commit_before>//! Check that functions don't accept an "excessive" number of arguments.

use syntax::ast::{Block, FnDecl, NodeId};
use syntax::codemap::Span;
use syntax::visit::FnKind;
use rustc::lint::{Context, LintArray, LintPass};

const MAX_ARGS_DEFAULT: usize = 6;
const MAX_ARGS_FOR_CLOSURE: usize = 4;

declare_lint!(FN_ARG_LIST_LENGTH, Warn, "Warn about long argument lists");

pub struct Pass;

fn get_max_args_allowed(kind: &FnKind) -> usize {
    match kind {
        &FnKind::FkFnBlock => MAX_ARGS_FOR_CLOSURE,
        _ => MAX_ARGS_DEFAULT
    }
}

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(FN_ARG_LIST_LENGTH)
    }

    fn check_fn(&mut self, cx: &Context, kind: FnKind, decl: &FnDecl, _: &Block,
                span: Span, _: NodeId) {
        if decl.inputs.len() > get_max_args_allowed(&kind) {
            cx.span_lint(FN_ARG_LIST_LENGTH, span,
                            "function has an excessive number of arguments");
        }
    }
}
<commit_msg>Use if-let as we only have a binary match<commit_after>//! Check that functions don't accept an "excessive" number of arguments.

use syntax::ast::{Block, FnDecl, NodeId};
use syntax::codemap::Span;
use syntax::visit::FnKind;
use rustc::lint::{Context, LintArray, LintPass};

const MAX_ARGS_DEFAULT: usize = 6;
const MAX_ARGS_FOR_CLOSURE: usize = 4;

declare_lint!(FN_ARG_LIST_LENGTH, Warn, "Warn about long argument lists");

pub struct Pass;

fn get_max_args_allowed(kind: &FnKind) -> usize {
    if let &FnKind::FkFnBlock = kind {
        MAX_ARGS_FOR_CLOSURE
    } else {
        MAX_ARGS_DEFAULT
    }
}

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(FN_ARG_LIST_LENGTH)
    }

    fn check_fn(&mut self, cx: &Context, kind: FnKind, decl: &FnDecl, _: &Block,
                span: Span, _: NodeId) {
        if decl.inputs.len() > get_max_args_allowed(&kind) {
            cx.span_lint(FN_ARG_LIST_LENGTH, span,
                            "function has an excessive number of arguments");
        }
    }
}
<|endoftext|>


<commit_before>extern crate byteorder;
#[macro_use]
extern crate slog;

extern crate bamrescue;

mod common;

fn check(reader: &mut bamrescue::Rescuable) {
    let results = bamrescue::check(reader, false, &common::null_logger());
    if results.bad_blocks_count > 0 ||
       results.truncated_in_block ||
       results.truncated_between_blocks {
        panic!("Invalid bam file");
    }
}

#[test]
fn empty_file() {
    check(&mut common::empty_file())
}

#[test]
fn empty_bam() {
    check(&mut common::empty_bam())
}

#[test]
fn empty_with_extra_subfields_before_bam() {
    check(&mut common::empty_with_extra_subfields_before_bam())
}

#[test]
fn empty_with_extra_subfields_after_bam() {
    check(&mut common::empty_with_extra_subfields_after_bam())
}

#[test]
fn empty_with_extra_subfields_before_and_after_bam() {
    check(&mut common::empty_with_extra_subfields_before_and_after_bam())
}

#[test]
fn single_block_bam() {
    check(&mut common::single_block_bam())
}

#[test]
fn two_blocks_bam() {
    check(&mut common::two_blocks_bam())
}

#[test]
fn three_blocks_bam() {
    check(&mut common::three_blocks_bam())
}

#[test]
fn three_blocks_empty_inside_bam() {
    check(&mut common::three_blocks_empty_inside_bam())
}

#[test]
#[should_panic]
fn single_block_missing_gzip_identifier() {
    check(&mut common::single_block_missing_gzip_identifier_bam())
}

#[test]
#[should_panic]
fn single_block_missing_bgzf_identifier() {
    check(&mut common::single_block_missing_bgzf_identifier_bam())
}

#[test]
#[should_panic]
fn single_block_missing_empty_bam() {
    check(&mut common::single_block_missing_empty_bam())
}

#[test]
#[should_panic]
fn two_blocks_missing_empty_bam() {
    check(&mut common::two_blocks_missing_empty_bam())
}

#[test]
#[should_panic]
fn three_blocks_bad_inflated_payload_crc32_bam() {
    check(&mut common::three_blocks_bad_inflated_payload_crc32_bam())
}

#[test]
#[should_panic]
fn three_blocks_bad_inflated_payload_size_bam() {
    check(&mut common::three_blocks_bad_inflated_payload_size_bam())
}

#[test]
#[should_panic]
fn three_blocks_too_small_bgzf_size_bam() {
    check(&mut common::three_blocks_too_small_bgzf_size_bam())
}

#[test]
#[should_panic]
fn three_blocks_too_large_bgzf_size_bam() {
    check(&mut common::three_blocks_too_large_bgzf_size_bam())
}

#[test]
fn three_blocks_with_extra_subfields_before_bam() {
    check(&mut common::three_blocks_with_extra_subfields_before_bam())
}

#[test]
fn three_blocks_with_extra_subfields_after_bam() {
    check(&mut common::three_blocks_with_extra_subfields_after_bam())
}

#[test]
fn three_blocks_with_extra_subfields_before_and_after_bam() {
    check(&mut common::three_blocks_with_extra_subfields_before_and_after_bam())
}
<commit_msg>Check results in details in tests<commit_after>extern crate byteorder;
#[macro_use]
extern crate slog;

extern crate bamrescue;

mod common;

fn check(reader: &mut bamrescue::Rescuable, blocks_count: u64, bad_blocks_count: u64, truncated_in_block: bool, truncated_between_blocks: bool) {
    let results = bamrescue::check(reader, false, &common::null_logger());
    assert_eq!(results.blocks_count, blocks_count);
    assert_eq!(results.bad_blocks_count, bad_blocks_count);
    assert_eq!(results.truncated_in_block, truncated_in_block);
    assert_eq!(results.truncated_between_blocks, truncated_between_blocks);

}

#[test]
fn empty_file() {
    check(&mut common::empty_file(), 0, 0, false, false)
}

#[test]
fn empty_bam() {
    check(&mut common::empty_bam(), 1, 0, false, false)
}

#[test]
fn empty_with_extra_subfields_before_bam() {
    check(&mut common::empty_with_extra_subfields_before_bam(), 1, 0, false, false)
}

#[test]
fn empty_with_extra_subfields_after_bam() {
    check(&mut common::empty_with_extra_subfields_after_bam(), 1, 0, false, false)
}

#[test]
fn empty_with_extra_subfields_before_and_after_bam() {
    check(&mut common::empty_with_extra_subfields_before_and_after_bam(), 1, 0, false, false)
}

#[test]
fn single_block_bam() {
    check(&mut common::single_block_bam(), 2, 0, false, false)
}

#[test]
fn two_blocks_bam() {
    check(&mut common::two_blocks_bam(), 3, 0, false, false)
}

#[test]
fn three_blocks_bam() {
    check(&mut common::three_blocks_bam(), 4, 0, false, false)
}

#[test]
fn three_blocks_empty_inside_bam() {
    check(&mut common::three_blocks_empty_inside_bam(), 4, 0, false, false)
}

#[test]
#[should_panic]
fn single_block_missing_gzip_identifier() {
    check(&mut common::single_block_missing_gzip_identifier_bam(), 2, 1, false, false)
}

#[test]
#[should_panic]
fn single_block_missing_bgzf_identifier() {
    check(&mut common::single_block_missing_bgzf_identifier_bam(), 2, 1, false, false)
}

#[test]
fn single_block_missing_empty_bam() {
    check(&mut common::single_block_missing_empty_bam(), 1, 0, false, true)
}

#[test]
fn two_blocks_missing_empty_bam() {
    check(&mut common::two_blocks_missing_empty_bam(), 2, 0, false, true)
}

#[test]
fn three_blocks_bad_inflated_payload_crc32_bam() {
    check(&mut common::three_blocks_bad_inflated_payload_crc32_bam(), 4, 1, false, false)
}

#[test]
fn three_blocks_bad_inflated_payload_size_bam() {
    check(&mut common::three_blocks_bad_inflated_payload_size_bam(), 4, 1, false, false)
}

#[test]
#[should_panic]
fn three_blocks_too_small_bgzf_size_bam() {
    check(&mut common::three_blocks_too_small_bgzf_size_bam(), 4, 1, false, false)
}

#[test]
#[should_panic]
fn three_blocks_too_large_bgzf_size_bam() {
    check(&mut common::three_blocks_too_large_bgzf_size_bam(), 4, 1, false, false)
}

#[test]
fn three_blocks_with_extra_subfields_before_bam() {
    check(&mut common::three_blocks_with_extra_subfields_before_bam(), 4, 0, false, false)
}

#[test]
fn three_blocks_with_extra_subfields_after_bam() {
    check(&mut common::three_blocks_with_extra_subfields_after_bam(), 4, 0, false, false)
}

#[test]
fn three_blocks_with_extra_subfields_before_and_after_bam() {
    check(&mut common::three_blocks_with_extra_subfields_before_and_after_bam(), 4, 0, false, false)
}
<|endoftext|>