<commit_before>use crate::rparser::{RBuilder, RParser, R_STATUS_FAIL, R_STATUS_OK};
use crate::{gen_get_variants, Variant};
use dhcp4r::packet::Packet;

pub struct DHCPBuilder {}
impl RBuilder for DHCPBuilder {
    fn new(&self) -> Box<dyn RParser> { Box::new(DHCPParser::new(b"DHCP")) }
    fn probe(&self, i:&[u8]) -> bool { dhcp_probe(i) }
}

pub struct DHCPParser<'a> {
    _name: Option<&'a[u8]>,
    reply: bool,
    xid: u32,
}

impl<'a> DHCPParser<'a> {
    pub fn new(name:&[u8]) -> DHCPParser {
        DHCPParser {
            _name: Some(name),
            reply: false,
            xid: 0,
        }
    }
}

impl<'a> RParser for DHCPParser<'a> {
    fn parse(&mut self, i: &[u8], _direction: u8) -> u32 {
        match Packet::from(i) {
            Ok(pkt) => {
                // debug!("pkt: {:?}", pkt);
                self.reply = pkt.reply;
                if self.xid == 0 {
                    self.xid = pkt.xid;
                }
                R_STATUS_OK
            }
            _ => R_STATUS_FAIL
        }
    }

    gen_get_variants!{DHCPParser, "dhcp.",
        reply => into,
        xid => into,
    }
}

pub fn dhcp_probe(i: &[u8]) -> bool {
    Packet::from(i).is_ok()
}
<commit_msg>DHCP: store HostName and ServerIdentifier if present<commit_after>use crate::rparser::{RBuilder, RParser, R_STATUS_FAIL, R_STATUS_OK};
use crate::{gen_get_variants, Variant};
use dhcp4r::{
    options::DhcpOption,
    packet::Packet
};
use std::net::Ipv4Addr;

pub struct DHCPBuilder {}
impl RBuilder for DHCPBuilder {
    fn new(&self) -> Box<dyn RParser> { Box::new(DHCPParser::new(b"DHCP")) }
    fn probe(&self, i:&[u8]) -> bool { dhcp_probe(i) }
}

#[derive(Default)]
pub struct DHCPParser<'a> {
    _name: Option<&'a[u8]>,
    reply: bool,
    xid: u32,
    hostname: Option<String>,
    server_identifier: Option<Ipv4Addr>,
}

impl<'a> DHCPParser<'a> {
    pub fn new(name:&[u8]) -> DHCPParser {
        DHCPParser {
            _name: Some(name),
            ..DHCPParser::default()
        }
    }
}

impl<'a> RParser for DHCPParser<'a> {
    fn parse(&mut self, i: &[u8], _direction: u8) -> u32 {
        match Packet::from(i) {
            Ok(pkt) => {
                // debug!("pkt: {:?}", pkt);
                self.reply = pkt.reply;
                if self.xid == 0 {
                    self.xid = pkt.xid;
                }
                for option in pkt.options.iter() {
                    debug!("  DHCP option: {}", option.code());
                    match option {
                        DhcpOption::HostName(s) => {
                            self.hostname = Some(s.clone());
                        },
                        DhcpOption::ServerIdentifier(ip4) => {
                            self.server_identifier = Some(ip4.clone());
                        },
                        _ => {},
                    }
                }
                R_STATUS_OK
            }
            _ => R_STATUS_FAIL
        }
    }

    gen_get_variants!{DHCPParser, "dhcp.",
        reply => into,
        xid => into,
        hostname => |s| { s.hostname.as_ref().map(|x| Variant::OwnedStr(x.clone())) },
        server_identifier => |s| { s.server_identifier.as_ref().map(|x| Variant::OwnedStr(x.to_string())) },
    }
}

pub fn dhcp_probe(i: &[u8]) -> bool {
    Packet::from(i).is_ok()
}
<|endoftext|>


<commit_before>//! API wrappers for common use cases like highlighting strings and
//! files without caring about intermediate semantic representation
//! and caching.

use crate::parsing::{ScopeStack, ParseState, SyntaxReference, SyntaxSet, ScopeStackOp};
use crate::highlighting::{Highlighter, HighlightState, HighlightIterator, Theme, Style};
use std::io::{self, BufReader};
use std::fs::File;
use std::path::Path;
// use util::debug_print_ops;

/// Simple way to go directly from lines of text to colored tokens.
///
/// Depending on how you load the syntaxes (see the [`SyntaxSet`] docs), this can either take
/// strings with trailing `\n`s or without.
///
/// [`SyntaxSet`]: ../parsing/struct.SyntaxSet.html
///
/// # Examples
///
/// Prints colored lines of a string to the terminal
///
/// ```
/// use syntect::easy::HighlightLines;
/// use syntect::parsing::SyntaxSet;
/// use syntect::highlighting::{ThemeSet, Style};
/// use syntect::util::{as_24_bit_terminal_escaped, LinesWithEndings};
///
/// // Load these once at the start of your program
/// let ps = SyntaxSet::load_defaults_newlines();
/// let ts = ThemeSet::load_defaults();
///
/// let syntax = ps.find_syntax_by_extension("rs").unwrap();
/// let mut h = HighlightLines::new(syntax, &ts.themes["base16-ocean.dark"]);
/// let s = "pub struct Wow { hi: u64 }\nfn blah() -> u64 {}";
/// for line in LinesWithEndings::from(s) { // LinesWithEndings enables use of newlines mode
///     let ranges: Vec<(Style, &str)> = h.highlight(line, &ps);
///     let escaped = as_24_bit_terminal_escaped(&ranges[..], true);
///     println!("{}", escaped);
/// }
/// ```
pub struct HighlightLines<'a> {
    highlighter: Highlighter<'a>,
    parse_state: ParseState,
    highlight_state: HighlightState,
}

impl<'a> HighlightLines<'a> {
    pub fn new(syntax: &SyntaxReference, theme: &'a Theme) -> HighlightLines<'a> {
        let highlighter = Highlighter::new(theme);
        let highlight_state = HighlightState::new(&highlighter, ScopeStack::new());
        HighlightLines {
            highlighter,
            parse_state: ParseState::new(syntax),
            highlight_state,
        }
    }

    /// Highlights a line of a file
    pub fn highlight<'b>(&mut self, line: &'b str, syntax_set: &SyntaxSet) -> Vec<(Style, &'b str)> {
        // println!("{}", self.highlight_state.path);
        let ops = self.parse_state.parse_line(line, syntax_set);
        // use util::debug_print_ops;
        // debug_print_ops(line, &ops);
        let iter =
            HighlightIterator::new(&mut self.highlight_state, &ops[..], line, &self.highlighter);
        iter.collect()
    }
}

/// Convenience struct containing everything you need to highlight a file
///
/// Use the `reader` to get the lines of the file and the `highlight_lines` to highlight them. See
/// the [`new`] method docs for more information.
///
/// [`new`]: #method.new
pub struct HighlightFile<'a> {
    pub reader: BufReader<File>,
    pub highlight_lines: HighlightLines<'a>,
}

impl<'a> HighlightFile<'a> {
    /// Constructs a file reader and a line highlighter to get you reading files as fast as possible.
    ///
    /// This auto-detects the syntax from the extension and constructs a [`HighlightLines`] with the
    /// correct syntax and theme.
    ///
    /// [`HighlightLines`]: struct.HighlightLines.html
    ///
    /// # Examples
    ///
    /// Using the `newlines` mode is a bit involved but yields more robust and glitch-free highlighting,
    /// as well as being slightly faster since it can re-use a line buffer.
    ///
    /// ```
    /// use syntect::parsing::SyntaxSet;
    /// use syntect::highlighting::{ThemeSet, Style};
    /// use syntect::util::as_24_bit_terminal_escaped;
    /// use syntect::easy::HighlightFile;
    /// use std::io::BufRead;
    ///
    /// # use std::io;
    /// # fn foo() -> io::Result<()> {
    /// let ss = SyntaxSet::load_defaults_newlines();
    /// let ts = ThemeSet::load_defaults();
    ///
    /// let mut highlighter = HighlightFile::new("testdata/highlight_test.erb", &ss, &ts.themes["base16-ocean.dark"]).unwrap();
    /// let mut line = String::new();
    /// while highlighter.reader.read_line(&mut line)? > 0 {
    ///     {
    ///         let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight(&line, &ss);
    ///         println!("{}", as_24_bit_terminal_escaped(&regions[..], true));
    ///     } // until NLL this scope is needed so we can clear the buffer after
    ///     line.clear(); // read_line appends so we need to clear between lines
    /// }
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// This example uses `reader.lines()` to get lines without a newline character, it's simpler but may break on rare tricky cases.
    ///
    /// ```
    /// use syntect::parsing::SyntaxSet;
    /// use syntect::highlighting::{ThemeSet, Style};
    /// use syntect::util::as_24_bit_terminal_escaped;
    /// use syntect::easy::HighlightFile;
    /// use std::io::BufRead;
    ///
    /// let ss = SyntaxSet::load_defaults_nonewlines();
    /// let ts = ThemeSet::load_defaults();
    ///
    /// let mut highlighter = HighlightFile::new("testdata/highlight_test.erb", &ss, &ts.themes["base16-ocean.dark"]).unwrap();
    /// for maybe_line in highlighter.reader.lines() {
    ///     let line = maybe_line.unwrap();
    ///     let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight(&line, &ss);
    ///     println!("{}", as_24_bit_terminal_escaped(&regions[..], true));
    /// }
    /// ```
    pub fn new<P: AsRef<Path>>(path_obj: P,
                               ss: &SyntaxSet,
                               theme: &'a Theme)
                               -> io::Result<HighlightFile<'a>> {
        let path: &Path = path_obj.as_ref();
        let f = File::open(path)?;
        let syntax = ss.find_syntax_for_file(path)?
            .unwrap_or_else(|| ss.find_syntax_plain_text());

        Ok(HighlightFile {
            reader: BufReader::new(f),
            highlight_lines: HighlightLines::new(syntax, theme),
        })
    }
}

/// Iterator over the regions of a line which a given the operation from the parser applies.
///
/// To use, just keep your own [`ScopeStack`] and then `ScopeStack.apply(op)` the operation that is
/// yielded at the top of your `for` loop over this iterator. Now you have a substring of the line
/// and the scope stack for that token.
///
/// See the `synstats.rs` example for an example of using this iterator.
///
/// **Note:** This will often return empty regions, just `continue` after applying the op if you
/// don't want them.
///
/// [`ScopeStack`]: ../parsing/struct.ScopeStack.html
#[derive(Debug)]
pub struct ScopeRegionIterator<'a> {
    ops: &'a [(usize, ScopeStackOp)],
    line: &'a str,
    index: usize,
    last_str_index: usize,
}

impl<'a> ScopeRegionIterator<'a> {
    pub fn new(ops: &'a [(usize, ScopeStackOp)], line: &'a str) -> ScopeRegionIterator<'a> {
        ScopeRegionIterator {
            ops,
            line,
            index: 0,
            last_str_index: 0,
        }
    }
}

static NOOP_OP: ScopeStackOp = ScopeStackOp::Noop;

impl<'a> Iterator for ScopeRegionIterator<'a> {
    type Item = (&'a str, &'a ScopeStackOp);
    fn next(&mut self) -> Option<Self::Item> {
        if self.index > self.ops.len() {
            return None;
        }

        // region extends up to next operation (ops[index]) or string end if there is none
        // note the next operation may be at, last_str_index, in which case the region is empty
        let next_str_i = if self.index == self.ops.len() {
            self.line.len()
        } else {
            self.ops[self.index].0
        };
        let substr = &self.line[self.last_str_index..next_str_i];
        self.last_str_index = next_str_i;

        // the first region covers everything before the first op, which may be empty
        let op = if self.index == 0 {
            &NOOP_OP
        } else {
            &self.ops[self.index-1].1
        };

        self.index += 1;
        Some((substr, op))
    }
}

#[cfg(all(feature = "assets", any(feature = "dump-load", feature = "dump-load-rs")))]
#[cfg(test)]
mod tests {
    use super::*;
    use crate::parsing::{SyntaxSet, ParseState, ScopeStack};
    use crate::highlighting::ThemeSet;
    use std::str::FromStr;

    #[test]
    fn can_highlight_lines() {
        let ss = SyntaxSet::load_defaults_nonewlines();
        let ts = ThemeSet::load_defaults();
        let syntax = ss.find_syntax_by_extension("rs").unwrap();
        let mut h = HighlightLines::new(syntax, &ts.themes["base16-ocean.dark"]);
        let ranges = h.highlight("pub struct Wow { hi: u64 }", &ss);
        assert!(ranges.len() > 4);
    }

    #[test]
    fn can_highlight_file() {
        let ss = SyntaxSet::load_defaults_nonewlines();
        let ts = ThemeSet::load_defaults();
        HighlightFile::new("testdata/highlight_test.erb",
                           &ss,
                           &ts.themes["base16-ocean.dark"])
            .unwrap();
    }

    #[test]
    fn can_find_regions() {
        let ss = SyntaxSet::load_defaults_nonewlines();
        let mut state = ParseState::new(ss.find_syntax_by_extension("rb").unwrap());
        let line = "lol =5+2";
        let ops = state.parse_line(line, &ss);

        let mut stack = ScopeStack::new();
        let mut token_count = 0;
        for (s, op) in ScopeRegionIterator::new(&ops, line) {
            stack.apply(op);
            if s.is_empty() { // in this case we don't care about blank tokens
                continue;
            }
            if token_count == 1 {
                assert_eq!(stack, ScopeStack::from_str("source.ruby keyword.operator.assignment.ruby").unwrap());
                assert_eq!(s, "=");
            }
            token_count += 1;
            println!("{:?} {}", s, stack);
        }
        assert_eq!(token_count, 5);
    }

    #[test]
    fn can_find_regions_with_trailing_newline() {
        let ss = SyntaxSet::load_defaults_newlines();
        let mut state = ParseState::new(ss.find_syntax_by_extension("rb").unwrap());
        let lines = ["# hello world\n", "lol=5+2\n"];
        let mut stack = ScopeStack::new();

        for line in lines.iter() {
            let ops = state.parse_line(&line, &ss);
            println!("{:?}", ops);

            let mut iterated_ops: Vec<&ScopeStackOp> = Vec::new();
            for (_, op) in ScopeRegionIterator::new(&ops, &line) {
                stack.apply(op);
                iterated_ops.push(&op);
                println!("{:?}", op);
            }

            let all_ops: Vec<&ScopeStackOp> = ops.iter().map(|t|&t.1).collect();
            assert_eq!(all_ops.len(), iterated_ops.len() - 1); // -1 because we want to ignore the NOOP
        }
    }
}
<commit_msg>Add ScopedRangeIterator<commit_after>//! API wrappers for common use cases like highlighting strings and
//! files without caring about intermediate semantic representation
//! and caching.

use crate::parsing::{ScopeStack, ParseState, SyntaxReference, SyntaxSet, ScopeStackOp};
use crate::highlighting::{Highlighter, HighlightState, HighlightIterator, Theme, Style};
use std::io::{self, BufReader};
use std::fs::File;
use std::path::Path;
// use util::debug_print_ops;

/// Simple way to go directly from lines of text to colored tokens.
///
/// Depending on how you load the syntaxes (see the [`SyntaxSet`] docs), this can either take
/// strings with trailing `\n`s or without.
///
/// [`SyntaxSet`]: ../parsing/struct.SyntaxSet.html
///
/// # Examples
///
/// Prints colored lines of a string to the terminal
///
/// ```
/// use syntect::easy::HighlightLines;
/// use syntect::parsing::SyntaxSet;
/// use syntect::highlighting::{ThemeSet, Style};
/// use syntect::util::{as_24_bit_terminal_escaped, LinesWithEndings};
///
/// // Load these once at the start of your program
/// let ps = SyntaxSet::load_defaults_newlines();
/// let ts = ThemeSet::load_defaults();
///
/// let syntax = ps.find_syntax_by_extension("rs").unwrap();
/// let mut h = HighlightLines::new(syntax, &ts.themes["base16-ocean.dark"]);
/// let s = "pub struct Wow { hi: u64 }\nfn blah() -> u64 {}";
/// for line in LinesWithEndings::from(s) { // LinesWithEndings enables use of newlines mode
///     let ranges: Vec<(Style, &str)> = h.highlight(line, &ps);
///     let escaped = as_24_bit_terminal_escaped(&ranges[..], true);
///     println!("{}", escaped);
/// }
/// ```
pub struct HighlightLines<'a> {
    highlighter: Highlighter<'a>,
    parse_state: ParseState,
    highlight_state: HighlightState,
}

impl<'a> HighlightLines<'a> {
    pub fn new(syntax: &SyntaxReference, theme: &'a Theme) -> HighlightLines<'a> {
        let highlighter = Highlighter::new(theme);
        let highlight_state = HighlightState::new(&highlighter, ScopeStack::new());
        HighlightLines {
            highlighter,
            parse_state: ParseState::new(syntax),
            highlight_state,
        }
    }

    /// Highlights a line of a file
    pub fn highlight<'b>(&mut self, line: &'b str, syntax_set: &SyntaxSet) -> Vec<(Style, &'b str)> {
        // println!("{}", self.highlight_state.path);
        let ops = self.parse_state.parse_line(line, syntax_set);
        // use util::debug_print_ops;
        // debug_print_ops(line, &ops);
        let iter =
            HighlightIterator::new(&mut self.highlight_state, &ops[..], line, &self.highlighter);
        iter.collect()
    }
}

/// Convenience struct containing everything you need to highlight a file
///
/// Use the `reader` to get the lines of the file and the `highlight_lines` to highlight them. See
/// the [`new`] method docs for more information.
///
/// [`new`]: #method.new
pub struct HighlightFile<'a> {
    pub reader: BufReader<File>,
    pub highlight_lines: HighlightLines<'a>,
}

impl<'a> HighlightFile<'a> {
    /// Constructs a file reader and a line highlighter to get you reading files as fast as possible.
    ///
    /// This auto-detects the syntax from the extension and constructs a [`HighlightLines`] with the
    /// correct syntax and theme.
    ///
    /// [`HighlightLines`]: struct.HighlightLines.html
    ///
    /// # Examples
    ///
    /// Using the `newlines` mode is a bit involved but yields more robust and glitch-free highlighting,
    /// as well as being slightly faster since it can re-use a line buffer.
    ///
    /// ```
    /// use syntect::parsing::SyntaxSet;
    /// use syntect::highlighting::{ThemeSet, Style};
    /// use syntect::util::as_24_bit_terminal_escaped;
    /// use syntect::easy::HighlightFile;
    /// use std::io::BufRead;
    ///
    /// # use std::io;
    /// # fn foo() -> io::Result<()> {
    /// let ss = SyntaxSet::load_defaults_newlines();
    /// let ts = ThemeSet::load_defaults();
    ///
    /// let mut highlighter = HighlightFile::new("testdata/highlight_test.erb", &ss, &ts.themes["base16-ocean.dark"]).unwrap();
    /// let mut line = String::new();
    /// while highlighter.reader.read_line(&mut line)? > 0 {
    ///     {
    ///         let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight(&line, &ss);
    ///         println!("{}", as_24_bit_terminal_escaped(&regions[..], true));
    ///     } // until NLL this scope is needed so we can clear the buffer after
    ///     line.clear(); // read_line appends so we need to clear between lines
    /// }
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// This example uses `reader.lines()` to get lines without a newline character, it's simpler but may break on rare tricky cases.
    ///
    /// ```
    /// use syntect::parsing::SyntaxSet;
    /// use syntect::highlighting::{ThemeSet, Style};
    /// use syntect::util::as_24_bit_terminal_escaped;
    /// use syntect::easy::HighlightFile;
    /// use std::io::BufRead;
    ///
    /// let ss = SyntaxSet::load_defaults_nonewlines();
    /// let ts = ThemeSet::load_defaults();
    ///
    /// let mut highlighter = HighlightFile::new("testdata/highlight_test.erb", &ss, &ts.themes["base16-ocean.dark"]).unwrap();
    /// for maybe_line in highlighter.reader.lines() {
    ///     let line = maybe_line.unwrap();
    ///     let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight(&line, &ss);
    ///     println!("{}", as_24_bit_terminal_escaped(&regions[..], true));
    /// }
    /// ```
    pub fn new<P: AsRef<Path>>(path_obj: P,
                               ss: &SyntaxSet,
                               theme: &'a Theme)
                               -> io::Result<HighlightFile<'a>> {
        let path: &Path = path_obj.as_ref();
        let f = File::open(path)?;
        let syntax = ss.find_syntax_for_file(path)?
            .unwrap_or_else(|| ss.find_syntax_plain_text());

        Ok(HighlightFile {
            reader: BufReader::new(f),
            highlight_lines: HighlightLines::new(syntax, theme),
        })
    }
}

/// Iterator over the regions of a line (including the ranges) which a given the operation from the parser applies.
///
/// To use, just keep your own [`ScopeStack`] and then `ScopeStack.apply(op)` the operation that is
/// yielded at the top of your `for` loop over this iterator. Now you have a substring of the line
/// and the scope stack for that token.
///
/// See the `synstats.rs` example for an example of using this iterator.
///
/// **Note:** This will often return empty regions, just `continue` after applying the op if you
/// don't want them.
///
/// [`ScopeStack`]: ../parsing/struct.ScopeStack.html
#[derive(Debug)]
pub struct ScopeRangeIterator<'a> {
    ops: &'a [(usize, ScopeStackOp)],
    line: &'a str,
    index: usize,
    last_str_index: usize,
}

impl<'a> ScopeRangeIterator<'a> {
    pub fn new(ops: &'a [(usize, ScopeStackOp)], line: &'a str) -> ScopeRangeIterator<'a> {
        ScopeRangeIterator {
            ops,
            line,
            index: 0,
            last_str_index: 0,
        }
    }
}

static NOOP_OP: ScopeStackOp = ScopeStackOp::Noop;

impl<'a> Iterator for ScopeRangeIterator<'a> {
    type Item = (&'a str, std::ops::Range<usize>, &'a ScopeStackOp);
    fn next(&mut self) -> Option<Self::Item> {
        if self.index > self.ops.len() {
            return None;
        }

        // region extends up to next operation (ops[index]) or string end if there is none
        // note the next operation may be at, last_str_index, in which case the region is empty
        let next_str_i = if self.index == self.ops.len() {
            self.line.len()
        } else {
            self.ops[self.index].0
        };
        let range = self.last_str_index..next_str_i;
        let substr = &self.line[range.clone()];
        self.last_str_index = next_str_i;

        // the first region covers everything before the first op, which may be empty
        let op = if self.index == 0 {
            &NOOP_OP
        } else {
            &self.ops[self.index - 1].1
        };

        self.index += 1;
        Some((substr, range, op))
    }
}

/// Iterator over the regions of a line which a given the operation from the parser applies.
///
/// To use, just keep your own [`ScopeStack`] and then `ScopeStack.apply(op)` the operation that is
/// yielded at the top of your `for` loop over this iterator. Now you have a substring of the line
/// and the scope stack for that token.
///
/// See the `synstats.rs` example for an example of using this iterator.
///
/// **Note:** This will often return empty regions, just `continue` after applying the op if you
/// don't want them.
///
/// [`ScopeStack`]: ../parsing/struct.ScopeStack.html
#[derive(Debug)]
pub struct ScopeRegionIterator<'a> {
    range_iter: ScopeRangeIterator<'a>,
}

impl<'a> ScopeRegionIterator<'a> {
    pub fn new(ops: &'a [(usize, ScopeStackOp)], line: &'a str) -> ScopeRegionIterator<'a> {
        ScopeRegionIterator {
            range_iter: ScopeRangeIterator::new(ops, line),
        }
    }
}

impl<'a> Iterator for ScopeRegionIterator<'a> {
    type Item = (&'a str, &'a ScopeStackOp);
    fn next(&mut self) -> Option<Self::Item> {
        let (substr, _, op) = self.range_iter.next()?;
        Some((substr, op))
    }
}

#[cfg(all(feature = "assets", any(feature = "dump-load", feature = "dump-load-rs")))]
#[cfg(test)]
mod tests {
    use super::*;
    use crate::parsing::{SyntaxSet, ParseState, ScopeStack};
    use crate::highlighting::ThemeSet;
    use std::str::FromStr;

    #[test]
    fn can_highlight_lines() {
        let ss = SyntaxSet::load_defaults_nonewlines();
        let ts = ThemeSet::load_defaults();
        let syntax = ss.find_syntax_by_extension("rs").unwrap();
        let mut h = HighlightLines::new(syntax, &ts.themes["base16-ocean.dark"]);
        let ranges = h.highlight("pub struct Wow { hi: u64 }", &ss);
        assert!(ranges.len() > 4);
    }

    #[test]
    fn can_highlight_file() {
        let ss = SyntaxSet::load_defaults_nonewlines();
        let ts = ThemeSet::load_defaults();
        HighlightFile::new("testdata/highlight_test.erb",
                           &ss,
                           &ts.themes["base16-ocean.dark"])
            .unwrap();
    }

    #[test]
    fn can_find_regions() {
        let ss = SyntaxSet::load_defaults_nonewlines();
        let mut state = ParseState::new(ss.find_syntax_by_extension("rb").unwrap());
        let line = "lol =5+2";
        let ops = state.parse_line(line, &ss);

        let mut stack = ScopeStack::new();
        let mut token_count = 0;
        for (s, op) in ScopeRegionIterator::new(&ops, line) {
            stack.apply(op);
            if s.is_empty() { // in this case we don't care about blank tokens
                continue;
            }
            if token_count == 1 {
                assert_eq!(stack, ScopeStack::from_str("source.ruby keyword.operator.assignment.ruby").unwrap());
                assert_eq!(s, "=");
            }
            token_count += 1;
            println!("{:?} {}", s, stack);
        }
        assert_eq!(token_count, 5);
    }

    #[test]
    fn can_find_regions_with_trailing_newline() {
        let ss = SyntaxSet::load_defaults_newlines();
        let mut state = ParseState::new(ss.find_syntax_by_extension("rb").unwrap());
        let lines = ["# hello world\n", "lol=5+2\n"];
        let mut stack = ScopeStack::new();

        for line in lines.iter() {
            let ops = state.parse_line(&line, &ss);
            println!("{:?}", ops);

            let mut iterated_ops: Vec<&ScopeStackOp> = Vec::new();
            for (_, op) in ScopeRegionIterator::new(&ops, &line) {
                stack.apply(op);
                iterated_ops.push(&op);
                println!("{:?}", op);
            }

            let all_ops: Vec<&ScopeStackOp> = ops.iter().map(|t|&t.1).collect();
            assert_eq!(all_ops.len(), iterated_ops.len() - 1); // -1 because we want to ignore the NOOP
        }
    }
}
<|endoftext|>


<commit_before>use encoding::types::EncodingRef;

use error::Error;
use history::{Cursor, History};
use buffer::Buffer;
use parser::{parse, ParseError, ParseSuccess};
use instr;

#[derive(Copy,Clone)]
pub enum EditMode {
    Emacs,
    Vi,
}

#[derive(Copy, Clone, PartialEq)]
pub enum ViMode {
    Insert,
    Normal,
    Replace,
}

pub struct EditCtx<'a> {
    buf: Buffer,
    history_cursor: Cursor<'a>,
    prompt: &'a str,
    seq: Vec<u8>,
    enc: EncodingRef,
    mode: EditMode,
    vi_mode: ViMode,
    vi_count: u32,
}

impl<'a> EditCtx<'a> {

    pub fn new(prompt: &'a str, history: &'a History, enc: EncodingRef, mode: EditMode) -> Self {
        EditCtx {
            buf: Buffer::new(),
            history_cursor: Cursor::new(history),
            prompt: prompt,
            seq: Vec::new(),
            enc: enc,
            mode: mode,
            // always start in insert mode
            vi_mode: ViMode::Insert,
            vi_count: 0,
        }
    }

    pub fn fill(&mut self, byte: u8) {
        self.seq.push(byte)
    }

}

pub enum EditResult<C> {
    Cont(C),
    Halt(Result<String, Error>)
}

macro_rules! vi_repeat {
    ( $ctx:ident, $x:expr ) => {
        match $ctx.vi_count {
            0 => { $x; }
            _ => for _ in 0..$ctx.vi_count { $x; }
        }
        $ctx.vi_count = 0;
    };
    ( $ctx:ident, $operation:expr, $step:expr ) => {
        match $ctx.vi_count {
            0 => { $operation; }
            _ => {
                $operation;
                for _ in 1..$ctx.vi_count { $step; $operation; }
            }
        }
        $ctx.vi_count = 0;
    };
}

pub fn edit<'a>(ctx: &mut EditCtx<'a>) -> EditResult<Vec<u8>> {
    use self::EditResult::*;

    let res = match parse(&ctx.seq, ctx.enc) {
        Err(ParseError::Error(len)) => {
            for _ in (0..len) {
                ctx.seq.remove(0);
            };
            Cont(false)
        },
        Err(ParseError::Incomplete) => Cont(false),
        Ok(ParseSuccess(token, len)) => {
            let res = match instr::interpret_token(token, ctx.mode, ctx.vi_mode) {
                instr::Instr::Done => {
                    Halt(Ok(ctx.buf.drain()))
                },
                instr::Instr::DeleteCharLeftOfCursor => {
                    vi_repeat!(ctx, ctx.buf.delete_char_left_of_cursor());
                    Cont(false)
                },
                instr::Instr::DeleteCharRightOfCursor => {
                    vi_repeat!(ctx, ctx.buf.delete_char_right_of_cursor());
                    Cont(false)
                },
                instr::Instr::DeleteCharRightOfCursorOrEOF => {
                    if !ctx.buf.delete_char_right_of_cursor() {
                        Halt(Err(Error::EndOfFile))
                    } else {
                        Cont(false)
                    }
                },
                instr::Instr::MoveCursorLeft => {
                    vi_repeat!(ctx, ctx.buf.move_left());
                    Cont(false)
                },
                instr::Instr::MoveCursorRight => {
                    vi_repeat!(ctx, ctx.buf.move_right());
                    Cont(false)
                },
                instr::Instr::MoveCursorStart => {
                    ctx.buf.move_start();
                    Cont(false)
                },
                instr::Instr::MoveCursorEnd => {
                    ctx.buf.move_end();
                    Cont(false)
                },
                instr::Instr::HistoryPrev => {
                    vi_repeat!(ctx, {
                        if ctx.history_cursor.incr() {
                            ctx.buf.swap()
                        }
                        ctx.history_cursor.get().map(|s| ctx.buf.replace(s));
                    });
                    Cont(false)
                },
                instr::Instr::HistoryNext => {
                    vi_repeat!(ctx, {
                        if ctx.history_cursor.decr() {
                            ctx.buf.swap()
                        }
                        ctx.history_cursor.get().map(|s| ctx.buf.replace(s));
                    });
                    Cont(false)
                },
                instr::Instr::NormalMode => {
                    if ctx.vi_mode == ViMode::Insert {
                        // cursor moves left when leaving insert mode
                        ctx.buf.move_left();
                    }
                    ctx.vi_mode = ViMode::Normal;
                    ctx.vi_count = 0;
                    Cont(false)
                }
                instr::Instr::ReplaceMode => {
                    ctx.vi_mode = ViMode::Replace;
                    Cont(false)
                }
                instr::Instr::Insert => {
                    ctx.vi_mode = ViMode::Insert;
                    Cont(false)
                }
                instr::Instr::InsertStart => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_start();
                    Cont(false)
                }
                instr::Instr::Append => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_right();
                    Cont(false)
                }
                instr::Instr::AppendEnd => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_end();
                    Cont(false)
                }
                instr::Instr::Digit(i) => {
                    match (ctx.vi_count, i) {
                        // if count is 0, then 0 moves to the start of a line
                        (0, 0) => ctx.buf.move_start(),
                        // otherwise add a digit to the count
                        (_, i) => ctx.vi_count = ctx.vi_count * 10 + i,
                    }
                    Cont(false)
                }
                instr::Instr::MoveEndOfWordRight => {
                    vi_repeat!(ctx, ctx.buf.move_to_end_of_word());
                    Cont(false)
                }
                instr::Instr::Substitute => {
                    vi_repeat!(ctx, ctx.buf.delete_char_right_of_cursor());
                    ctx.vi_mode = ViMode::Insert;
                    Cont(false)
                }
                instr::Instr::Noop => {
                    Cont(false)
                },
                instr::Instr::Cancel => Halt(Err(Error::Cancel)),
                instr::Instr::Clear => {
                    Cont(true)
                },
                instr::Instr::InsertAtCursor(text) => {
                    ctx.buf.insert_chars_at_cursor(text);
                    Cont(false)
                }
                instr::Instr::ReplaceAtCursor(text) => {
                    vi_repeat!(
                        ctx,
                        ctx.buf.replace_chars_at_cursor(text.clone()),
                        ctx.buf.move_right()
                    );
                    ctx.vi_mode = ViMode::Normal;
                    Cont(false)
                }
            };
            for _ in (0..len) {
                ctx.seq.remove(0);
            };
            res
        }
    };
    match res {
        Cont(clear) => EditResult::Cont(ctx.buf.get_line(ctx.prompt, clear)),
        Halt(res) => EditResult::Halt(res)
    }
}
<commit_msg>don't move past the end of the line in normal mode<commit_after>use encoding::types::EncodingRef;

use error::Error;
use history::{Cursor, History};
use buffer::Buffer;
use parser::{parse, ParseError, ParseSuccess};
use instr;

#[derive(Copy,Clone)]
pub enum EditMode {
    Emacs,
    Vi,
}

#[derive(Copy, Clone, PartialEq)]
pub enum ViMode {
    Insert,
    Normal,
    Replace,
}

pub struct EditCtx<'a> {
    buf: Buffer,
    history_cursor: Cursor<'a>,
    prompt: &'a str,
    seq: Vec<u8>,
    enc: EncodingRef,
    mode: EditMode,
    vi_mode: ViMode,
    vi_count: u32,
}

impl<'a> EditCtx<'a> {

    pub fn new(prompt: &'a str, history: &'a History, enc: EncodingRef, mode: EditMode) -> Self {
        EditCtx {
            buf: Buffer::new(),
            history_cursor: Cursor::new(history),
            prompt: prompt,
            seq: Vec::new(),
            enc: enc,
            mode: mode,
            // always start in insert mode
            vi_mode: ViMode::Insert,
            vi_count: 0,
        }
    }

    pub fn fill(&mut self, byte: u8) {
        self.seq.push(byte)
    }

}

pub enum EditResult<C> {
    Cont(C),
    Halt(Result<String, Error>)
}

macro_rules! vi_repeat {
    ( $ctx:ident, $x:expr ) => {
        match $ctx.vi_count {
            0 => { $x; }
            _ => for _ in 0..$ctx.vi_count { $x; }
        }
        $ctx.vi_count = 0;
    };
    ( $ctx:ident, $operation:expr, $step:expr ) => {
        match $ctx.vi_count {
            0 => { $operation; }
            _ => {
                $operation;
                for _ in 1..$ctx.vi_count { $step; $operation; }
            }
        }
        $ctx.vi_count = 0;
    };
}

pub fn edit<'a>(ctx: &mut EditCtx<'a>) -> EditResult<Vec<u8>> {
    use self::EditResult::*;

    let res = match parse(&ctx.seq, ctx.enc) {
        Err(ParseError::Error(len)) => {
            for _ in (0..len) {
                ctx.seq.remove(0);
            };
            Cont(false)
        },
        Err(ParseError::Incomplete) => Cont(false),
        Ok(ParseSuccess(token, len)) => {
            let res = match instr::interpret_token(token, ctx.mode, ctx.vi_mode) {
                instr::Instr::Done => {
                    Halt(Ok(ctx.buf.drain()))
                },
                instr::Instr::DeleteCharLeftOfCursor => {
                    vi_repeat!(ctx, ctx.buf.delete_char_left_of_cursor());
                    Cont(false)
                },
                instr::Instr::DeleteCharRightOfCursor => {
                    vi_repeat!(ctx, ctx.buf.delete_char_right_of_cursor());
                    Cont(false)
                },
                instr::Instr::DeleteCharRightOfCursorOrEOF => {
                    if !ctx.buf.delete_char_right_of_cursor() {
                        Halt(Err(Error::EndOfFile))
                    } else {
                        Cont(false)
                    }
                },
                instr::Instr::MoveCursorLeft => {
                    vi_repeat!(ctx, ctx.buf.move_left());
                    Cont(false)
                },
                instr::Instr::MoveCursorRight => {
                    vi_repeat!(ctx, ctx.buf.move_right());
                    if ctx.vi_mode == ViMode::Normal {
                        ctx.buf.exclude_eol();
                    }
                    Cont(false)
                },
                instr::Instr::MoveCursorStart => {
                    ctx.buf.move_start();
                    Cont(false)
                },
                instr::Instr::MoveCursorEnd => {
                    ctx.buf.move_end();
                    if ctx.vi_mode == ViMode::Normal {
                        ctx.buf.exclude_eol();
                    }
                    Cont(false)
                },
                instr::Instr::HistoryPrev => {
                    vi_repeat!(ctx, {
                        if ctx.history_cursor.incr() {
                            ctx.buf.swap()
                        }
                        ctx.history_cursor.get().map(|s| ctx.buf.replace(s));
                    });
                    Cont(false)
                },
                instr::Instr::HistoryNext => {
                    vi_repeat!(ctx, {
                        if ctx.history_cursor.decr() {
                            ctx.buf.swap()
                        }
                        ctx.history_cursor.get().map(|s| ctx.buf.replace(s));
                    });
                    Cont(false)
                },
                instr::Instr::NormalMode => {
                    if ctx.vi_mode == ViMode::Insert {
                        // cursor moves left when leaving insert mode
                        ctx.buf.move_left();
                    }
                    ctx.vi_mode = ViMode::Normal;
                    ctx.vi_count = 0;
                    Cont(false)
                }
                instr::Instr::ReplaceMode => {
                    ctx.vi_mode = ViMode::Replace;
                    Cont(false)
                }
                instr::Instr::Insert => {
                    ctx.vi_mode = ViMode::Insert;
                    Cont(false)
                }
                instr::Instr::InsertStart => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_start();
                    Cont(false)
                }
                instr::Instr::Append => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_right();
                    Cont(false)
                }
                instr::Instr::AppendEnd => {
                    ctx.vi_mode = ViMode::Insert;
                    ctx.buf.move_end();
                    Cont(false)
                }
                instr::Instr::Digit(i) => {
                    match (ctx.vi_count, i) {
                        // if count is 0, then 0 moves to the start of a line
                        (0, 0) => ctx.buf.move_start(),
                        // otherwise add a digit to the count
                        (_, i) => ctx.vi_count = ctx.vi_count * 10 + i,
                    }
                    Cont(false)
                }
                instr::Instr::MoveEndOfWordRight => {
                    vi_repeat!(ctx, ctx.buf.move_to_end_of_word());
                    ctx.buf.exclude_eol();
                    Cont(false)
                }
                instr::Instr::Substitute => {
                    vi_repeat!(ctx, ctx.buf.delete_char_right_of_cursor());
                    ctx.vi_mode = ViMode::Insert;
                    Cont(false)
                }
                instr::Instr::Noop => {
                    Cont(false)
                },
                instr::Instr::Cancel => Halt(Err(Error::Cancel)),
                instr::Instr::Clear => {
                    Cont(true)
                },
                instr::Instr::InsertAtCursor(text) => {
                    ctx.buf.insert_chars_at_cursor(text);
                    Cont(false)
                }
                instr::Instr::ReplaceAtCursor(text) => {
                    vi_repeat!(
                        ctx,
                        ctx.buf.replace_chars_at_cursor(text.clone()),
                        {
                            ctx.buf.move_right();
                            ctx.buf.exclude_eol();
                        }
                    );
                    ctx.vi_mode = ViMode::Normal;
                    Cont(false)
                }
            };
            for _ in (0..len) {
                ctx.seq.remove(0);
            };
            res
        }
    };
    match res {
        Cont(clear) => EditResult::Cont(ctx.buf.get_line(ctx.prompt, clear)),
        Halt(res) => EditResult::Halt(res)
    }
}
<|endoftext|>


<commit_before>extern crate zoom;
extern crate rand;

use super::bot::*;
use super::Vec3;

const BOTS_RADIUS_MULTIPLIER: f32 = 5.0;
const RADIUS_STATIC: f32 = 5.0;
const ENERGY_RATIO: f64 = 0.002;
const ENERGY_VARIATION: f64 = 0.1;
pub const ENERGY_THRESHOLD: i64 = 500000;
const ENERGY_FULL_COST: i64 = 5000;
const PHYSICS_RADIUS: f64 = 1.0;

const EDGE_FOOD_BENEFIT: f64 = 1.0;
const EDGE_DIFFUSION_COEFFICIENT: f64 = 0.01;

const DRAG: f64 = 0.1;

#[derive(Clone)]
pub struct RadParticle {
    pub p: zoom::BasicParticle<Vec3, f64>,
}

impl zoom::Position<Vec3> for RadParticle {
    fn position(&self) -> Vec3 {
        self.p.position()
    }
}

impl zoom::Velocity<Vec3> for RadParticle {
    fn velocity(&self) -> Vec3 {
        self.p.velocity()
    }
}

impl zoom::Particle<Vec3, f64> for RadParticle {
    fn impulse(&self, v: &Vec3) {
        self.p.impulse(v);
    }

    fn advance(&mut self, time: f64) {
        self.p.advance(time);
    }
}

impl zoom::Inertia<f64> for RadParticle {
    fn inertia(&self) -> f64 {
        self.p.inertia()
    }
}

impl zoom::Quanta<f64> for RadParticle {
    fn quanta(&self) -> f64 {
        self.p.quanta()
    }
}

impl zoom::PhysicsParticle<Vec3, f64> for RadParticle {
}

impl zoom::Ball<f64> for RadParticle {
    fn radius(&self) -> f64 {
        PHYSICS_RADIUS
    }
}

pub struct Node {
    pub particle: RadParticle,
    pub energy: i64,
    pub bots: Vec<Box<Bot>>,
    pub moved_bots: Vec<Box<Bot>>,
    pub deaths: i64,
    pub moves: i64,
    pub connections: i64,
    pub pull: i64,
    pub diffuse: i64,
}

impl Node {
    pub fn new(energy: i64, particle: zoom::BasicParticle<Vec3, f64>) -> Self {
        Node{
            energy: energy,
            particle: RadParticle{p: particle},
            bots: Vec::new(),
            moved_bots: Vec::new(),
            deaths: 0,
            moves: 0,
            connections: 0,
            pull: 0,
            diffuse: 0,
        }
    }

    pub fn diffuse(&mut self) {
        self.diffuse = self.connections * (self.energy as f64 * EDGE_DIFFUSION_COEFFICIENT) as i64;
        self.energy -= self.diffuse;
    }

    pub fn grow(&mut self, full: bool, rng: &mut rand::Isaac64Rng) {
        use rand::Rng;
        if full {
            if self.bots.is_empty() {
                self.energy = self.energy.saturating_sub((ENERGY_FULL_COST as f64 *
                    (1.0 + rng.gen_range(-ENERGY_VARIATION, ENERGY_VARIATION))) as i64);
            }
        } else {
            self.energy = self.energy.saturating_add((self.energy as f64 * ENERGY_RATIO *
                //Create rate differential
                (1.0 + rng.gen_range(-ENERGY_VARIATION, ENERGY_VARIATION) +
                    //Add food for having more connections
                    EDGE_FOOD_BENEFIT * self.connections as f64)
                ) as i64);
        }
    }

    pub fn advance(&mut self) {
        use zoom::{Particle, PhysicsParticle};
        self.particle.drag(DRAG);
        self.particle.advance(1.0);
    }

    pub fn should_split(&self) -> bool {
        self.energy >= ENERGY_THRESHOLD
    }
    pub fn should_obliterate(&self) -> bool {
        use std::num::FpCategory;
        use zoom::Position;
        let clos = |x: f64| {
            match x.classify() {
                FpCategory::Nan | FpCategory::Infinite => true,
                _ => false,
            }
        };
        self.energy <= 0 || match self.particle.position() {
            Vec3{x, y, z} => {clos(x) || clos(y) || clos(z)}
        }
    }

    pub fn color(&self) -> [f32; 4] {
        [
            1.0 - self.energy as f32 / ENERGY_THRESHOLD as f32,
            self.energy as f32 / ENERGY_THRESHOLD as f32,
            if self.bots.len() == 0 {
                0.0
            } else {
                self.moves as f32 / self.bots.len() as f32
            },
            1.0,
        ]
    }
    pub fn radius(&self) -> f32 {
        RADIUS_STATIC + BOTS_RADIUS_MULTIPLIER * (self.bots.len() as f32).sqrt()
    }
}
<commit_msg>push the insanity<commit_after>extern crate zoom;
extern crate rand;

use super::bot::*;
use super::Vec3;

const BOTS_RADIUS_MULTIPLIER: f32 = 5.0;
const RADIUS_STATIC: f32 = 5.0;
const ENERGY_RATIO: f64 = 0.002;
const ENERGY_VARIATION: f64 = 0.1;
pub const ENERGY_THRESHOLD: i64 = 500000;
const ENERGY_FULL_COST: i64 = 5000;
const PHYSICS_RADIUS: f64 = 1.0;

const EDGE_FOOD_BENEFIT: f64 = 2.0;
const EDGE_DIFFUSION_COEFFICIENT: f64 = 0.01;

const DRAG: f64 = 0.1;

#[derive(Clone)]
pub struct RadParticle {
    pub p: zoom::BasicParticle<Vec3, f64>,
}

impl zoom::Position<Vec3> for RadParticle {
    fn position(&self) -> Vec3 {
        self.p.position()
    }
}

impl zoom::Velocity<Vec3> for RadParticle {
    fn velocity(&self) -> Vec3 {
        self.p.velocity()
    }
}

impl zoom::Particle<Vec3, f64> for RadParticle {
    fn impulse(&self, v: &Vec3) {
        self.p.impulse(v);
    }

    fn advance(&mut self, time: f64) {
        self.p.advance(time);
    }
}

impl zoom::Inertia<f64> for RadParticle {
    fn inertia(&self) -> f64 {
        self.p.inertia()
    }
}

impl zoom::Quanta<f64> for RadParticle {
    fn quanta(&self) -> f64 {
        self.p.quanta()
    }
}

impl zoom::PhysicsParticle<Vec3, f64> for RadParticle {
}

impl zoom::Ball<f64> for RadParticle {
    fn radius(&self) -> f64 {
        PHYSICS_RADIUS
    }
}

pub struct Node {
    pub particle: RadParticle,
    pub energy: i64,
    pub bots: Vec<Box<Bot>>,
    pub moved_bots: Vec<Box<Bot>>,
    pub deaths: i64,
    pub moves: i64,
    pub connections: i64,
    pub pull: i64,
    pub diffuse: i64,
}

impl Node {
    pub fn new(energy: i64, particle: zoom::BasicParticle<Vec3, f64>) -> Self {
        Node{
            energy: energy,
            particle: RadParticle{p: particle},
            bots: Vec::new(),
            moved_bots: Vec::new(),
            deaths: 0,
            moves: 0,
            connections: 0,
            pull: 0,
            diffuse: 0,
        }
    }

    pub fn diffuse(&mut self) {
        self.diffuse = self.connections * (self.energy as f64 * EDGE_DIFFUSION_COEFFICIENT) as i64;
        self.energy -= self.diffuse;
    }

    pub fn grow(&mut self, full: bool, rng: &mut rand::Isaac64Rng) {
        use rand::Rng;
        if full {
            if self.bots.is_empty() {
                self.energy = self.energy.saturating_sub((ENERGY_FULL_COST as f64 *
                    (1.0 + rng.gen_range(-ENERGY_VARIATION, ENERGY_VARIATION))) as i64);
            }
        } else {
            self.energy = self.energy.saturating_add((self.energy as f64 * ENERGY_RATIO *
                //Create rate differential
                (1.0 + rng.gen_range(-ENERGY_VARIATION, ENERGY_VARIATION) +
                    //Add food for having more connections
                    EDGE_FOOD_BENEFIT * self.connections as f64)
                ) as i64);
        }
    }

    pub fn advance(&mut self) {
        use zoom::{Particle, PhysicsParticle};
        self.particle.drag(DRAG);
        self.particle.advance(1.0);
    }

    pub fn should_split(&self) -> bool {
        self.energy >= ENERGY_THRESHOLD
    }
    pub fn should_obliterate(&self) -> bool {
        use std::num::FpCategory;
        use zoom::Position;
        let clos = |x: f64| {
            match x.classify() {
                FpCategory::Nan | FpCategory::Infinite => true,
                _ => false,
            }
        };
        self.energy <= 0 || match self.particle.position() {
            Vec3{x, y, z} => {clos(x) || clos(y) || clos(z)}
        }
    }

    pub fn color(&self) -> [f32; 4] {
        [
            1.0 - self.energy as f32 / ENERGY_THRESHOLD as f32,
            self.energy as f32 / ENERGY_THRESHOLD as f32,
            if self.bots.len() == 0 {
                0.0
            } else {
                self.moves as f32 / self.bots.len() as f32
            },
            1.0,
        ]
    }
    pub fn radius(&self) -> f32 {
        RADIUS_STATIC + BOTS_RADIUS_MULTIPLIER * (self.bots.len() as f32).sqrt()
    }
}
<|endoftext|>


<commit_before>use std::net::Ipv6Addr;
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};

use rustc_serialize::{Encodable, Encoder, Decoder};

use dht::GenericId;
use dht::Node as DhtNode;

pub const PUBLIC_KEY_LENGTH: usize = 32;

pub type Path = [u8; 8];

/// Wrapper of `Ipv6Addr` that implements `GenericId`
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Address {
    pub octets: [u8; 16],
}

impl Address {
    pub fn from_ipv6addr(ipv6addr: &Ipv6Addr) -> Address {
        Address { octets: ipv6addr.octets() }
    }
    pub fn to_ipv6addr(&self) -> Ipv6Addr {
        Ipv6Addr::from(self.octets)
    }
}

impl GenericId for Address {
    fn bitxor(&self, other: &Self) -> Self {
        let vec = self.octets.to_vec().bitxor(&other.octets.to_vec());
        assert_eq!(vec.len(), 16);
        let mut octets = [0u8; 16];
        octets.copy_from_slice(&vec);
        Address { octets: octets }
    }
    fn is_zero(&self) -> bool {
        self.octets.to_vec().is_zero()
    }
    fn bits(&self) -> usize {
        self.octets.to_vec().bits()
    }
    fn gen(bit_size: usize) -> Self {
        let vec = Vec::<u8>::gen(bit_size);
        assert_eq!(vec.len(), 16);
        let mut octets = [0u8; 16];
        octets.copy_from_slice(&vec);
        Address { octets: octets }
    }
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.octets.encode(s)
    }
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        let vec = try!(Vec::<u8>::decode(d));
        assert_eq!(vec.len(), 16);
        let mut octets = [0u8; 16];
        octets.copy_from_slice(&vec);
        Ok(Address { octets: octets })
    }
}

#[derive(Debug, Clone, Eq, PartialOrd)]
pub struct NodeData {
    pub public_key: [u8; PUBLIC_KEY_LENGTH],
    pub path: Path,
    pub version: u64,
}

impl PartialEq for NodeData {
    fn eq(&self, other: &NodeData) -> bool {
        self.public_key == other.public_key
    }
}

impl Ord for NodeData {
    fn cmp(&self, other: &NodeData) -> Ordering {
        self.public_key.cmp(&other.public_key)
    }
}

impl Hash for NodeData {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.public_key.hash(state);
    }
}

type Node = DhtNode<Address, NodeData>;
<commit_msg>Rotates addresses by 64 bits before XORing.<commit_after>use std::net::Ipv6Addr;
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};

use rustc_serialize::{Encodable, Encoder, Decoder};

use dht::GenericId;
use dht::Node as DhtNode;

pub const PUBLIC_KEY_LENGTH: usize = 32;

pub type Path = [u8; 8];

/// Rotates an IPv6 address 64 bits, which is a required preprocessing
/// for computing the XOR metric.
/// See https://github.com/cjdelisle/cjdns/blob/cjdns-v18/doc/Whitepaper.md#the-router
fn rotate_64(i: &[u8; 16]) -> [u8; 16] {
    [
        i[ 8], i[ 9], i[10], i[11], i[12], i[13], i[14], i[15],
        i[ 0], i[ 1], i[ 2], i[ 3], i[ 4], i[ 5], i[ 6], i[ 7],
    ]
}

/// Wrapper of `Ipv6Addr` that implements `GenericId`
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Address {
    bytes: [u8; 16],
}

impl Address {
    pub fn new(bytes: &[u8; 16]) -> Address {
        Address { bytes: rotate_64(bytes) }
    }
    pub fn bytes(&self) -> [u8; 16] {
        rotate_64(&self.bytes)
    }
    pub fn from_ipv6addr(ipv6addr: &Ipv6Addr) -> Address {
        Address::new(&ipv6addr.octets())
    }
    pub fn to_ipv6addr(&self) -> Ipv6Addr {
        Ipv6Addr::from(self.bytes())
    }
}

impl GenericId for Address {
    fn bitxor(&self, other: &Self) -> Self {
        let vec = self.bytes.to_vec().bitxor(&other.bytes.to_vec());
        assert_eq!(vec.len(), 16);
        let mut bytes = [0u8; 16];
        bytes.copy_from_slice(&vec);
        Address { bytes: bytes }
    }
    fn is_zero(&self) -> bool {
        self.bytes.to_vec().is_zero()
    }
    fn bits(&self) -> usize {
        self.bytes.to_vec().bits()
    }
    fn gen(bit_size: usize) -> Self {
        let vec = Vec::<u8>::gen(bit_size);
        assert_eq!(vec.len(), 16);
        let mut bytes = [0u8; 16];
        bytes.copy_from_slice(&vec);
        Address { bytes: bytes }
    }
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        self.bytes.encode(s)
    }
    fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
        let vec = try!(Vec::<u8>::decode(d));
        assert_eq!(vec.len(), 16);
        let mut bytes = [0u8; 16];
        bytes.copy_from_slice(&vec);
        Ok(Address { bytes: bytes })
    }
}

#[derive(Debug, Clone, Eq, PartialOrd)]
pub struct NodeData {
    pub public_key: [u8; PUBLIC_KEY_LENGTH],
    pub path: Path,
    pub version: u64,
}

impl PartialEq for NodeData {
    fn eq(&self, other: &NodeData) -> bool {
        self.public_key == other.public_key
    }
}

impl Ord for NodeData {
    fn cmp(&self, other: &NodeData) -> Ordering {
        self.public_key.cmp(&other.public_key)
    }
}

impl Hash for NodeData {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.public_key.hash(state);
    }
}

type Node = DhtNode<Address, NodeData>;
<|endoftext|>


<commit_before>use editor::Editor;
use parse::{Inst, Parameter};
use key::Key;
use mode::{Mode, CommandMode, PrimitiveMode};
use insert::{InsertOptions, InsertMode};
use redraw::RedrawTask;
use buffer::Buffer;

// TODO: Move the command definitions outta here
impl Editor {
    /// Execute an instruction
    pub fn exec(&mut self, Inst(para, cmd): Inst) {
        use key::Key::*;
        use mode::Mode::*;
        use mode::PrimitiveMode::*;
        use mode::CommandMode::*;

        let n = para.d();
        let bef = self.pos();
        let mut mov = false;

        if cmd.key == Key::Char(' ') && self.key_state.shift {

            let mode = self.cursor().mode;

            match mode {
                Primitive(Prompt) => self.prompt = String::new(),
                Primitive(Insert(_)) => {
                    let left = self.left(1);
                    self.goto(left);
                }
                _ => {}
            }
            self.cursor_mut().mode = Mode::Command(CommandMode::Normal);

        } else if self.key_state.alt && cmd.key == Key::Char(' ') {

            self.next_cursor();

        } else if self.key_state.alt {

            if let Some(m) = self.to_motion(Inst(para, cmd)) {
                self.goto(m);
            }

        } else {
            match self.cursor().mode {
                Command(Normal) => match cmd.key {
                    //                    // { for debuging
                    //                    Char('n') => {
                    //                        let p = self.next(n);
                    //                        if let Some(p) = p {
                    //                            self.goto(p);
                    //                        }
                    //                    },
                    //                    Char('p') => {
                    //                        let p = self.previous(n);
                    //                        if let Some(p) = p {
                    //                            self.goto(p);
                    //                        }
                    //                    },
                    //                    // }
                    Char('i') => {
                        self.cursor_mut().mode =
                            Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                                mode: InsertMode::Insert,
                            }));

                    }
                    Char('a') => {
                        let pos = self.right(1, false);
                        self.goto( pos );
                        self.cursor_mut().mode =
                            Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                                mode: InsertMode::Insert,
                            }));

                    }
                    Char('o') => {
                        let y = self.y();
                        let ind = if self.options.autoindent {
                            self.buffer.get_indent(y).to_owned()
                        } else {
                            String::new()
                        };
                        let last = ind.len();
                        self.buffer.insert_line(y, ind.into());
                        self.goto((last, y + 1));
                        self.cursor_mut().mode =
                            Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                                mode: InsertMode::Insert,
                            }));
                    }
                    Char('h') => {
                        let left = self.left(n);
                        self.goto(left);
                        mov = true;
                    }
                    Char('j') => {
                        let down = self.down(n);
                        self.goto(down);
                        mov = true;
                    }
                    Char('k') => {
                        let up = self.up(n);
                        self.goto(up);
                        mov = true;
                    }
                    Char('l') => {
                        let right = self.right(n, true);
                        self.goto(right);
                        mov = true;
                    }
                    Char('J') => {
                        let down = self.down(15 * n);
                        self.goto(down);
                        mov = true;
                    }
                    Char('K') => {
                        let up = self.up(15 * n);
                        self.goto(up);
                        mov = true;
                    }
                    Char('x') => {
                        self.delete();
                        let bounded = self.bound(self.pos(), true);
                        self.goto(bounded);
                    }
                    Char('X') => {
                        self.backspace();
                        let bounded = self.bound(self.pos(), true);
                        self.goto(bounded);
                    }
                    Char('L') => {
                        let ln_end = (self.buffer[self.y()].len(), self.y());
                        self.goto(ln_end);
                        mov = true;
                    }
                    Char('H') => {
                        self.cursor_mut().x = 0;
                        mov = true;
                    }
                    Char('r') => {
                        let (x, y) = self.pos();
                        let c = self.get_char();
                        self.buffer[y].remove(x);
                        self.buffer[y].insert(x, c);
                    }
                    Char('R') => {
                        self.cursor_mut().mode =
                            Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                                mode: InsertMode::Replace,
                            }));
                    }
                    Char('d') => {
                        let ins = self.get_inst();
                        if let Some(m) = self.to_motion_unbounded(ins) {
                            self.remove_rb(m);
                        }
                    }
                    Char('G') => {
                        let last = self.buffer.len() - 1;
                        self.goto((0, last));
                        mov = true;
                    }
                    Char('g') => {
                        if let Parameter::Int(n) = para {
                            self.goto((0, n - 1));
                            mov = true;
                        } else {
                            let inst = self.get_inst();
                            if let Some(m) = self.to_motion(inst) {
                                self.goto(m); // fix
                                mov = true;
                            }
                        }

                    }
                    Char('b') => {
                        // Branch cursor
                        if self.cursors.len() < 255 {
                            let cursor = self.cursor().clone();
                            self.cursors.insert(self.current_cursor as usize, cursor);
                            self.next_cursor();
                        }
                        else {
                            self.status_bar.msg = format!("At max 255 cursors");
                        }
                    }
                    Char('B') => {
                        // Delete cursor
                        if self.cursors.len() > 1 {
                            self.cursors.remove(self.current_cursor as usize);
                            self.prev_cursor();
                        }
                        else {
                            self.status_bar.msg = format!("No other cursors!");
                        }
                    }
                    Char('t') => {
                        let ch = self.get_char();

                        let pos = self.next_ocur(ch, n);
                        if let Some(p) = pos {
                            let y = self.y();
                            self.goto((p, y));
                            mov = true;
                        }
                    }
                    Char('f') => {
                        let ch = self.get_char();

                        let pos = self.previous_ocur(ch, n);
                        if let Some(p) = pos {
                            let y = self.y();
                            self.goto((p, y));
                            mov = true;
                        }
                    }
                    Char(';') => {
                        self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Prompt);
                    }
                    Char(' ') => {
                        self.next_cursor();
                    }
                    Char('z') => {
                        let Inst(param, cmd) = self.get_inst();
                        match param {
                            Parameter::Null => {
                                if let Some(m) = self.to_motion(Inst(param, cmd)) {
                                    self.scroll_y = m.1;
                                    self.goto(m);
                                }
                            }
                            Parameter::Int(n) => {
                                self.scroll_y = n;
                            }
                        }
                        self.redraw_task = RedrawTask::Full;
                    }
                    Char('Z') => {
                        self.scroll_y = self.y() - 3;
                        self.redraw_task = RedrawTask::Full;
                    }
                    Char('~') => {
                        self.invert_chars(n);
                    }
                    Char(c) => {
                        self.status_bar.msg = format!("Unknown command: {}", c);
                        self.redraw_task = RedrawTask::StatusBar;
                    }
                    _ => {
                        self.status_bar.msg = format!("Unknown command");
                        self.redraw_task = RedrawTask::StatusBar;
                    }
                },
                Primitive(Insert(opt)) => {
                    self.insert(cmd.key, opt);
                }
                Primitive(Prompt) => {
                    match cmd.key {
                        Char('\n') => {
                            self.cursor_mut().mode = Command(Normal);
                            let cmd = self.prompt.clone();

                            self.invoke(cmd);
                            self.prompt = String::new();
                        }
                        Backspace => {
                            self.prompt.pop();
                        }
                        Char(c) => self.prompt.push(c),
                        _ => {}
                    }
                    self.redraw_task = RedrawTask::StatusBar;
                }
            }
        }
        if mov {
            self.redraw_task = RedrawTask::Cursor(bef, self.pos());
        }
    }
}
<commit_msg>Fix r panic<commit_after>use editor::Editor;
use parse::{Inst, Parameter};
use key::Key;
use mode::{Mode, CommandMode, PrimitiveMode};
use insert::{InsertOptions, InsertMode};
use redraw::RedrawTask;
use buffer::Buffer;

// TODO: Move the command definitions outta here
impl Editor {
    /// Execute an instruction
    pub fn exec(&mut self, Inst(para, cmd): Inst) {
        use key::Key::*;
        use mode::Mode::*;
        use mode::PrimitiveMode::*;
        use mode::CommandMode::*;

        let n = para.d();
        let bef = self.pos();
        let mut mov = false;

        if cmd.key == Key::Char(' ') && self.key_state.shift {

            let mode = self.cursor().mode;

            match mode {
                Primitive(Prompt) => self.prompt = String::new(),
                Primitive(Insert(_)) => {
                    let left = self.left(1);
                    self.goto(left);
                }
                _ => {}
            }
            self.cursor_mut().mode = Mode::Command(CommandMode::Normal);

        } else if self.key_state.alt && cmd.key == Key::Char(' ') {

            self.next_cursor();

        } else if self.key_state.alt {

            if let Some(m) = self.to_motion(Inst(para, cmd)) {
                self.goto(m);
            }

        } else {
            match self.cursor().mode {
                Command(Normal) => match cmd.key {
                    //                    // { for debuging
                    //                    Char('n') => {
                    //                        let p = self.next(n);
                    //                        if let Some(p) = p {
                    //                            self.goto(p);
                    //                        }
                    //                    },
                    //                    Char('p') => {
                    //                        let p = self.previous(n);
                    //                        if let Some(p) = p {
                    //                            self.goto(p);
                    //                        }
                    //                    },
                    //                    // }
                    Char('i') => {
                        self.cursor_mut().mode =
                            Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                                mode: InsertMode::Insert,
                            }));

                    }
                    Char('a') => {
                        let pos = self.right(1, false);
                        self.goto( pos );
                        self.cursor_mut().mode =
                            Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                                mode: InsertMode::Insert,
                            }));

                    }
                    Char('o') => {
                        let y = self.y();
                        let ind = if self.options.autoindent {
                            self.buffer.get_indent(y).to_owned()
                        } else {
                            String::new()
                        };
                        let last = ind.len();
                        self.buffer.insert_line(y, ind.into());
                        self.goto((last, y + 1));
                        self.cursor_mut().mode =
                            Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                                mode: InsertMode::Insert,
                            }));
                    }
                    Char('h') => {
                        let left = self.left(n);
                        self.goto(left);
                        mov = true;
                    }
                    Char('j') => {
                        let down = self.down(n);
                        self.goto(down);
                        mov = true;
                    }
                    Char('k') => {
                        let up = self.up(n);
                        self.goto(up);
                        mov = true;
                    }
                    Char('l') => {
                        let right = self.right(n, true);
                        self.goto(right);
                        mov = true;
                    }
                    Char('J') => {
                        let down = self.down(15 * n);
                        self.goto(down);
                        mov = true;
                    }
                    Char('K') => {
                        let up = self.up(15 * n);
                        self.goto(up);
                        mov = true;
                    }
                    Char('x') => {
                        self.delete();
                        let bounded = self.bound(self.pos(), true);
                        self.goto(bounded);
                    }
                    Char('X') => {
                        self.backspace();
                        let bounded = self.bound(self.pos(), true);
                        self.goto(bounded);
                    }
                    Char('L') => {
                        let ln_end = (self.buffer[self.y()].len(), self.y());
                        self.goto(ln_end);
                        mov = true;
                    }
                    Char('H') => {
                        self.cursor_mut().x = 0;
                        mov = true;
                    }
                    Char('r') => {
                        let (x, y) = self.pos();
                        let c = self.get_char();
                        // If there is nothing in the current buffer
                        // ignore the command
                        if self.buffer[y].len() > 0 {
                            self.buffer[y].remove(x);
                        }
                        self.buffer[y].insert(x, c);

                    }
                    Char('R') => {
                        self.cursor_mut().mode =
                            Mode::Primitive(PrimitiveMode::Insert(InsertOptions {
                                mode: InsertMode::Replace,
                            }));
                    }
                    Char('d') => {
                        let ins = self.get_inst();
                        if let Some(m) = self.to_motion_unbounded(ins) {
                            self.remove_rb(m);
                        }
                    }
                    Char('G') => {
                        let last = self.buffer.len() - 1;
                        self.goto((0, last));
                        mov = true;
                    }
                    Char('g') => {
                        if let Parameter::Int(n) = para {
                            self.goto((0, n - 1));
                            mov = true;
                        } else {
                            let inst = self.get_inst();
                            if let Some(m) = self.to_motion(inst) {
                                self.goto(m); // fix
                                mov = true;
                            }
                        }

                    }
                    Char('b') => {
                        // Branch cursor
                        if self.cursors.len() < 255 {
                            let cursor = self.cursor().clone();
                            self.cursors.insert(self.current_cursor as usize, cursor);
                            self.next_cursor();
                        }
                        else {
                            self.status_bar.msg = format!("At max 255 cursors");
                        }
                    }
                    Char('B') => {
                        // Delete cursor
                        if self.cursors.len() > 1 {
                            self.cursors.remove(self.current_cursor as usize);
                            self.prev_cursor();
                        }
                        else {
                            self.status_bar.msg = format!("No other cursors!");
                        }
                    }
                    Char('t') => {
                        let ch = self.get_char();

                        let pos = self.next_ocur(ch, n);
                        if let Some(p) = pos {
                            let y = self.y();
                            self.goto((p, y));
                            mov = true;
                        }
                    }
                    Char('f') => {
                        let ch = self.get_char();

                        let pos = self.previous_ocur(ch, n);
                        if let Some(p) = pos {
                            let y = self.y();
                            self.goto((p, y));
                            mov = true;
                        }
                    }
                    Char(';') => {
                        self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Prompt);
                    }
                    Char(' ') => {
                        self.next_cursor();
                    }
                    Char('z') => {
                        let Inst(param, cmd) = self.get_inst();
                        match param {
                            Parameter::Null => {
                                if let Some(m) = self.to_motion(Inst(param, cmd)) {
                                    self.scroll_y = m.1;
                                    self.goto(m);
                                }
                            }
                            Parameter::Int(n) => {
                                self.scroll_y = n;
                            }
                        }
                        self.redraw_task = RedrawTask::Full;
                    }
                    Char('Z') => {
                        self.scroll_y = self.y() - 3;
                        self.redraw_task = RedrawTask::Full;
                    }
                    Char('~') => {
                        self.invert_chars(n);
                    }
                    Char(c) => {
                        self.status_bar.msg = format!("Unknown command: {}", c);
                        self.redraw_task = RedrawTask::StatusBar;
                    }
                    _ => {
                        self.status_bar.msg = format!("Unknown command");
                        self.redraw_task = RedrawTask::StatusBar;
                    }
                },
                Primitive(Insert(opt)) => {
                    self.insert(cmd.key, opt);
                }
                Primitive(Prompt) => {
                    match cmd.key {
                        Char('\n') => {
                            self.cursor_mut().mode = Command(Normal);
                            let cmd = self.prompt.clone();

                            self.invoke(cmd);
                            self.prompt = String::new();
                        }
                        Backspace => {
                            self.prompt.pop();
                        }
                        Char(c) => self.prompt.push(c),
                        _ => {}
                    }
                    self.redraw_task = RedrawTask::StatusBar;
                }
            }
        }
        if mov {
            self.redraw_task = RedrawTask::Cursor(bef, self.pos());
        }
    }
}
<|endoftext|>


<commit_before>use std::{cmp, ptr};

use self::ApplyResult::*;
use super::Leading::{self, Top, Bot};

const BCNT: u8 = 5;
const BCNT_: usize = BCNT as usize;

#[derive(Copy, Clone)]
struct SPart(u64);

#[derive(Copy, Clone)]
pub struct SPair {
    a: SPart,
    b: SPart,
}

/// A variable length pair.
#[derive(Clone)]
pub struct VPair {
    data: [u64; BCNT_],
    /// Who is leading.
    leading: Leading,
    /// How many bits of the first block are shared.
    prefix: u8,
    /// How many bits of the last block are used.
    used: u8,
    /// which block is last used one
    tail: u8,
}

#[derive(Copy, Clone)]
struct VHead {
    data: u64,
    /// How many bits are shared
    prefix: u8,
    /// How many bits are used
    used: u8,
}

impl VPair {
    pub fn new() -> VPair {
        VPair {
            data: [0; BCNT_],
            prefix: 0,
            used: 0,
            leading: Top,
            tail: 0,
        }
    }

    pub fn len(&self) -> usize {
        self.tail as usize + 1
    }

    pub fn is_complete(&self) -> bool {
        self.tail == 0 && self.used == 0
    }

    pub fn apply(&self, p: &SPair) -> Option<VPair> {
        let (mut lead, mut follow) = match self.leading {
            Top => (p.a, p.b),
            Bot => (p.b, p.a),
        };

        let mut head = self.head();

        match head.apply(&mut follow, &mut lead) {
            Mismatch => None,
            Match => Some(self.with_offset_prefix_and_add_lead(0, head.prefix, lead)),
            LeadSwitch => Some(self.switched_with_new_lead(follow)),
            MatchRemaining => {
                let mut head2 = self.head2();

                match head2.apply(&mut follow, &mut lead) {
                    Mismatch => None,
                    Match => Some(self.with_offset_prefix_and_add_lead(1, head2.prefix, lead)),
                    LeadSwitch => Some(self.switched_with_new_lead(follow)),
                    MatchRemaining => unreachable!("SPairs contain at most 56 bit, which always fit in 64 bit"),
                }
            }
        }
    }

    fn with_offset_prefix_and_add_lead(&self, offset: u8, prefix: u8, lead: SPart) -> VPair {
        let mut p = VPair {
            data: [0; BCNT_],
            prefix: prefix,
            used: self.used,
            leading: self.leading,
            tail: self.tail - offset
        };

        unsafe {
            ptr::copy_nonoverlapping(&self.data[offset as usize], &mut p.data[0], BCNT_ - offset as usize)

        }

        p.apply_lead(lead);

        p
    }

    fn switched_with_new_lead(&self, lead: SPart) -> VPair {
        let mut p = VPair {
            data: [0; BCNT_],
            prefix: 0,
            used: lead.len(),
            leading: self.leading.switched(),
            tail: 0,
        };

        p.data[0] = lead.data();

        p
    }

    fn apply_lead(&mut self, mut lead: SPart) {
        let pushable;

        { // make the borrowchecker happy
            let last = &mut self.data[self.tail as usize];

            // push all we can into the current byte
            pushable = cmp::min(64 - self.used, lead.len());
            *last |= lead.shift_data(pushable) << self.used;
        }

        let new_used = self.used + pushable;

        // if new_used is 64 need to open a new block
        if lead.len() == 0 && new_used < 64 {
            self.used = new_used;
        } else {
            self.push(lead.data());
            self.used = lead.len();
        }

        debug_assert!(self.used != 64);
    }

    fn push(&mut self, block: u64) {
        assert!(self.tail + 1 < BCNT, "lead too long, increase BCNT");
        self.tail += 1;
        self.data[self.tail as usize] = block;
    }

    fn head(&self) -> VHead {
        debug_assert!(self.used != 64);

        VHead {
            data: self.data[0],
            prefix: self.prefix,
            used: if self.tail > 0 { 64 } else { self.used },
        }
    }

    fn head2(&self) -> VHead {
        debug_assert!(self.tail > 0);

        VHead {
            data: self.data[1],
            prefix: 0,
            used: if self.tail > 1 { 64 } else { self. used },
        }
    }
}

enum ApplyResult {
    /// No match
    Mismatch,
    /// Completely matched, bits in lead need to be appended
    Match,
    /// Matched but end of block reached, repeat with second block
    MatchRemaining,
    /// Completely caught up, bits in follow make up a new block
    LeadSwitch,
}

impl SPart {
    fn data(&self) -> u64 {
        self.0 & 0x00FF_FFFF_FFFF_FFFF
    }

    fn len(&self) -> u8 {
        (self.0 >> 56) as u8
    }

    fn shift(&mut self, shift: u8) {
        let new_len = self.len() - shift;
        let new_val = self.data() >> shift;
        self.0 = ((new_len as u64) << 56) | new_val;
    }

    fn shift_data(&mut self, shift: u8) -> u64 {
        let data = self.0 & mask(shift);
        self.shift(shift);
        data
    }

    fn shift_prefix(a: &mut SPart, b: &mut SPart) {
        // after the xor the first mismatched bit is a one
        // theres no need for masking data since we need to use the min of the
        // lens and prefix anyway
        let prefix = (a.0 ^ b.0).trailing_zeros() as u8; // 0-64 always fit in an u8
        let prefix = cmp::min(prefix, cmp::min(a.len(), b.len()));
        a.shift(prefix);
        b.shift(prefix);
    }
}

impl VHead {
    fn apply(&mut self, follow: &mut SPart, lead: &mut SPart) -> ApplyResult {
        // fist, check that overlapping follows are equal
        let overlap = cmp::min(self.used - self.prefix, follow.len());

        // check
        let m = mask(overlap);
        let h = (self.data >> self.prefix) & m;
        let p = follow.data() & m;

        if h != p { return Mismatch; }

        // update
        self.prefix += overlap;
        follow.shift(overlap);

        if self.prefix == 64 {
            debug_assert!(self.used == 64);
            return MatchRemaining; // Reached the end of block, needs to be removed
        }

        // at this point follow has caught up to lead, so we can eliminate any common prefix from follow and lead
        SPart::shift_prefix(follow, lead);

        match (follow.len() == 0, lead.len() == 0) {
            (_, true) => LeadSwitch, // lead is empty, start a new block with follow
            (false, false) => Mismatch, // both have non matching bits remaining
            (true, false) => Match, // follow is empty
        }
    }
}

/// Create a bitmask of which the lower `cnt` bits are set.
fn mask(cnt: u8) -> u64 {
    (1 << cnt) - 1
}

impl<'a> From<&'a str> for SPart {
    fn from(s: &'a str) -> SPart {
        let mut val = 0u64;
        let mut len = 0u64;

        for b in s.bytes().rev() {
            len += 1;
            val <<= 1;

            match b {
                b'0' => (),
                b'1' => val |= 1,
                _ => panic!("invalid input byte: {}", b),
            }
        }

        assert!(len <= 56, "invalid input: too long");

        SPart((len << 56) | val)
    }
}

impl<'a> From<(&'a str, &'a str)> for SPair {
    fn from((a, b): (&'a str, &'a str)) -> SPair {
        SPair {
            a: a.into(),
            b: b.into(),
        }
    }
}
<commit_msg>add Copy to some types<commit_after>use std::{cmp, ptr};

use self::ApplyResult::*;
use super::Leading::{self, Top, Bot};

const BCNT: u8 = 5;
const BCNT_: usize = BCNT as usize;

#[derive(Copy, Clone)]
struct SPart(u64);

#[derive(Copy, Clone)]
pub struct SPair {
    a: SPart,
    b: SPart,
}

/// A variable length pair.
#[derive(Copy, Clone)]
pub struct VPair {
    data: [u64; BCNT_],
    /// Who is leading.
    leading: Leading,
    /// How many bits of the first block are shared.
    prefix: u8,
    /// How many bits of the last block are used.
    used: u8,
    /// which block is last used one
    tail: u8,
}

#[derive(Copy, Clone)]
struct VHead {
    data: u64,
    /// How many bits are shared
    prefix: u8,
    /// How many bits are used
    used: u8,
}

impl VPair {
    pub fn new() -> VPair {
        VPair {
            data: [0; BCNT_],
            prefix: 0,
            used: 0,
            leading: Top,
            tail: 0,
        }
    }

    pub fn len(&self) -> usize {
        self.tail as usize + 1
    }

    pub fn is_complete(&self) -> bool {
        self.tail == 0 && self.used == 0
    }

    pub fn apply(&self, p: &SPair) -> Option<VPair> {
        let (mut lead, mut follow) = match self.leading {
            Top => (p.a, p.b),
            Bot => (p.b, p.a),
        };

        let mut head = self.head();

        match head.apply(&mut follow, &mut lead) {
            Mismatch => None,
            Match => Some(self.with_offset_prefix_and_add_lead(0, head.prefix, lead)),
            LeadSwitch => Some(self.switched_with_new_lead(follow)),
            MatchRemaining => {
                let mut head2 = self.head2();

                match head2.apply(&mut follow, &mut lead) {
                    Mismatch => None,
                    Match => Some(self.with_offset_prefix_and_add_lead(1, head2.prefix, lead)),
                    LeadSwitch => Some(self.switched_with_new_lead(follow)),
                    MatchRemaining => unreachable!("SPairs contain at most 56 bit, which always fit in 64 bit"),
                }
            }
        }
    }

    fn with_offset_prefix_and_add_lead(&self, offset: u8, prefix: u8, lead: SPart) -> VPair {
        let mut p = VPair {
            data: [0; BCNT_],
            prefix: prefix,
            used: self.used,
            leading: self.leading,
            tail: self.tail - offset
        };

        unsafe {
            ptr::copy_nonoverlapping(&self.data[offset as usize], &mut p.data[0], BCNT_ - offset as usize)

        }

        p.apply_lead(lead);

        p
    }

    fn switched_with_new_lead(&self, lead: SPart) -> VPair {
        let mut p = VPair {
            data: [0; BCNT_],
            prefix: 0,
            used: lead.len(),
            leading: self.leading.switched(),
            tail: 0,
        };

        p.data[0] = lead.data();

        p
    }

    fn apply_lead(&mut self, mut lead: SPart) {
        let pushable;

        { // make the borrowchecker happy
            let last = &mut self.data[self.tail as usize];

            // push all we can into the current byte
            pushable = cmp::min(64 - self.used, lead.len());
            *last |= lead.shift_data(pushable) << self.used;
        }

        let new_used = self.used + pushable;

        // if new_used is 64 need to open a new block
        if lead.len() == 0 && new_used < 64 {
            self.used = new_used;
        } else {
            self.push(lead.data());
            self.used = lead.len();
        }

        debug_assert!(self.used != 64);
    }

    fn push(&mut self, block: u64) {
        assert!(self.tail + 1 < BCNT, "lead too long, increase BCNT");
        self.tail += 1;
        self.data[self.tail as usize] = block;
    }

    fn head(&self) -> VHead {
        debug_assert!(self.used != 64);

        VHead {
            data: self.data[0],
            prefix: self.prefix,
            used: if self.tail > 0 { 64 } else { self.used },
        }
    }

    fn head2(&self) -> VHead {
        debug_assert!(self.tail > 0);

        VHead {
            data: self.data[1],
            prefix: 0,
            used: if self.tail > 1 { 64 } else { self. used },
        }
    }
}

#[derive(Copy, Clone)]
enum ApplyResult {
    /// No match
    Mismatch,
    /// Completely matched, bits in lead need to be appended
    Match,
    /// Matched but end of block reached, repeat with second block
    MatchRemaining,
    /// Completely caught up, bits in follow make up a new block
    LeadSwitch,
}

impl SPart {
    fn data(&self) -> u64 {
        self.0 & 0x00FF_FFFF_FFFF_FFFF
    }

    fn len(&self) -> u8 {
        (self.0 >> 56) as u8
    }

    fn shift(&mut self, shift: u8) {
        let new_len = self.len() - shift;
        let new_val = self.data() >> shift;
        self.0 = ((new_len as u64) << 56) | new_val;
    }

    fn shift_data(&mut self, shift: u8) -> u64 {
        let data = self.0 & mask(shift);
        self.shift(shift);
        data
    }

    fn shift_prefix(a: &mut SPart, b: &mut SPart) {
        // after the xor the first mismatched bit is a one
        // theres no need for masking data since we need to use the min of the
        // lens and prefix anyway
        let prefix = (a.0 ^ b.0).trailing_zeros() as u8; // 0-64 always fit in an u8
        let prefix = cmp::min(prefix, cmp::min(a.len(), b.len()));
        a.shift(prefix);
        b.shift(prefix);
    }
}

impl VHead {
    fn apply(&mut self, follow: &mut SPart, lead: &mut SPart) -> ApplyResult {
        // fist, check that overlapping follows are equal
        let overlap = cmp::min(self.used - self.prefix, follow.len());

        // check
        let m = mask(overlap);
        let h = (self.data >> self.prefix) & m;
        let p = follow.data() & m;

        if h != p { return Mismatch; }

        // update
        self.prefix += overlap;
        follow.shift(overlap);

        if self.prefix == 64 {
            debug_assert!(self.used == 64);
            return MatchRemaining; // Reached the end of block, needs to be removed
        }

        // at this point follow has caught up to lead, so we can eliminate any common prefix from follow and lead
        SPart::shift_prefix(follow, lead);

        match (follow.len() == 0, lead.len() == 0) {
            (_, true) => LeadSwitch, // lead is empty, start a new block with follow
            (false, false) => Mismatch, // both have non matching bits remaining
            (true, false) => Match, // follow is empty
        }
    }
}

/// Create a bitmask of which the lower `cnt` bits are set.
fn mask(cnt: u8) -> u64 {
    (1 << cnt) - 1
}

impl<'a> From<&'a str> for SPart {
    fn from(s: &'a str) -> SPart {
        let mut val = 0u64;
        let mut len = 0u64;

        for b in s.bytes().rev() {
            len += 1;
            val <<= 1;

            match b {
                b'0' => (),
                b'1' => val |= 1,
                _ => panic!("invalid input byte: {}", b),
            }
        }

        assert!(len <= 56, "invalid input: too long");

        SPart((len << 56) | val)
    }
}

impl<'a> From<(&'a str, &'a str)> for SPair {
    fn from((a, b): (&'a str, &'a str)) -> SPair {
        SPair {
            a: a.into(),
            b: b.into(),
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::mem;

use super::{
    FAIL_STATE,
    AllBytesIter,
    StateIdx, AcAutomaton, Transitions, Match,
    usize_bytes, vec_bytes,
};
use super::autiter::Automaton;

/// A complete Aho-Corasick automaton.
///
/// This uses a single transition matrix that permits each input character
/// to move to the next state with a single lookup in the matrix.
///
/// This is as fast as it gets, but it is guaranteed to use a lot of memory.
/// Namely, it will use at least `4 * 256 * #states`, where the number of
/// states is capped at length of all patterns concatenated.
#[derive(Clone)]
pub struct FullAcAutomaton<P> {
    pats: Vec<P>,
    trans: Vec<StateIdx>,  // row-major, where states are rows
    out: Vec<Vec<usize>>, // indexed by StateIdx
    start_bytes: Vec<u8>,
}

impl<P: AsRef<[u8]>> FullAcAutomaton<P> {
    /// Build a new expanded Aho-Corasick automaton from an existing
    /// Aho-Corasick automaton.
    pub fn new<T: Transitions>(ac: AcAutomaton<P, T>) -> FullAcAutomaton<P> {
        let mut fac = FullAcAutomaton {
            pats: vec![],
            trans: vec![FAIL_STATE; 256 * ac.states.len()],
            out: vec![vec![]; ac.states.len()],
            start_bytes: vec![],
        };
        fac.build_matrix(&ac);
        fac.pats = ac.pats;
        fac.start_bytes = ac.start_bytes;
        fac
    }

    #[doc(hidden)]
    pub fn memory_usage(&self) -> usize {
        self.pats.iter()
            .map(|p| vec_bytes() + p.as_ref().len())
            .sum::<usize>()
        + (4 * self.trans.len())
        + self.out.iter()
              .map(|v| vec_bytes() + (usize_bytes() * v.len()))
              .sum::<usize>()
        + self.start_bytes.len()
    }

    #[doc(hidden)]
    pub fn heap_bytes(&self) -> usize {
        self.pats.iter()
            .map(|p| mem::size_of::<P>() + p.as_ref().len())
            .sum::<usize>()
        + (4 * self.trans.len())
        + self.out.iter()
              .map(|v| vec_bytes() + (usize_bytes() * v.len()))
              .sum::<usize>()
        + self.start_bytes.len()
    }

    fn set(&mut self, si: StateIdx, i: u8, goto: StateIdx) {
        let ns = self.num_states();
        self.trans[i as usize * ns + si as usize] = goto;
    }

    #[doc(hidden)]
    #[inline]
    pub fn num_states(&self) -> usize {
        self.out.len()
    }
}

impl<P: AsRef<[u8]>> Automaton<P> for FullAcAutomaton<P> {
    #[inline]
    fn next_state(&self, si: StateIdx, i: u8) -> StateIdx {
        let at = i as usize * self.num_states() + si as usize;
        unsafe { *self.trans.get_unchecked(at) }
    }

    #[inline]
    fn get_match(&self, si: StateIdx, outi: usize, texti: usize) -> Match {
        let pati = self.out[si as usize][outi];
        let patlen = self.pats[pati].as_ref().len();
        let start = texti + 1 - patlen;
        Match {
            pati: pati,
            start: start,
            end: start + patlen,
        }
    }

    #[inline]
    fn has_match(&self, si: StateIdx, outi: usize) -> bool {
        unsafe { outi < self.out.get_unchecked(si as usize).len() }
    }

    #[inline]
    fn start_bytes(&self) -> &[u8] {
        &self.start_bytes
    }

    #[inline]
    fn patterns(&self) -> &[P] {
        &self.pats
    }

    #[inline]
    fn pattern(&self, i: usize) -> &P {
        &self.pats[i]
    }
}

impl<P: AsRef<[u8]>> FullAcAutomaton<P> {
    fn build_matrix<T: Transitions>(&mut self, ac: &AcAutomaton<P, T>) {
        for (si, s) in ac.states.iter().enumerate().skip(1) {
            for b in AllBytesIter::new() {
                self.set(si as StateIdx, b, ac.next_state(si as StateIdx, b));
            }
            for &pati in &s.out {
                self.out[si].push(pati);
            }
        }
    }
}

impl<P: AsRef<[u8]> + fmt::Debug> fmt::Debug for FullAcAutomaton<P> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "FullAcAutomaton({:?})", self.pats)
    }
}
<commit_msg>perf: Use extend_from_slice instead of push (-2%)<commit_after>use std::fmt;
use std::mem;

use super::{
    FAIL_STATE,
    AllBytesIter,
    StateIdx, AcAutomaton, Transitions, Match,
    usize_bytes, vec_bytes,
};
use super::autiter::Automaton;

/// A complete Aho-Corasick automaton.
///
/// This uses a single transition matrix that permits each input character
/// to move to the next state with a single lookup in the matrix.
///
/// This is as fast as it gets, but it is guaranteed to use a lot of memory.
/// Namely, it will use at least `4 * 256 * #states`, where the number of
/// states is capped at length of all patterns concatenated.
#[derive(Clone)]
pub struct FullAcAutomaton<P> {
    pats: Vec<P>,
    trans: Vec<StateIdx>,  // row-major, where states are rows
    out: Vec<Vec<usize>>, // indexed by StateIdx
    start_bytes: Vec<u8>,
}

impl<P: AsRef<[u8]>> FullAcAutomaton<P> {
    /// Build a new expanded Aho-Corasick automaton from an existing
    /// Aho-Corasick automaton.
    pub fn new<T: Transitions>(ac: AcAutomaton<P, T>) -> FullAcAutomaton<P> {
        let mut fac = FullAcAutomaton {
            pats: vec![],
            trans: vec![FAIL_STATE; 256 * ac.states.len()],
            out: vec![vec![]; ac.states.len()],
            start_bytes: vec![],
        };
        fac.build_matrix(&ac);
        fac.pats = ac.pats;
        fac.start_bytes = ac.start_bytes;
        fac
    }

    #[doc(hidden)]
    pub fn memory_usage(&self) -> usize {
        self.pats.iter()
            .map(|p| vec_bytes() + p.as_ref().len())
            .sum::<usize>()
        + (4 * self.trans.len())
        + self.out.iter()
              .map(|v| vec_bytes() + (usize_bytes() * v.len()))
              .sum::<usize>()
        + self.start_bytes.len()
    }

    #[doc(hidden)]
    pub fn heap_bytes(&self) -> usize {
        self.pats.iter()
            .map(|p| mem::size_of::<P>() + p.as_ref().len())
            .sum::<usize>()
        + (4 * self.trans.len())
        + self.out.iter()
              .map(|v| vec_bytes() + (usize_bytes() * v.len()))
              .sum::<usize>()
        + self.start_bytes.len()
    }

    fn set(&mut self, si: StateIdx, i: u8, goto: StateIdx) {
        let ns = self.num_states();
        self.trans[i as usize * ns + si as usize] = goto;
    }

    #[doc(hidden)]
    #[inline]
    pub fn num_states(&self) -> usize {
        self.out.len()
    }
}

impl<P: AsRef<[u8]>> Automaton<P> for FullAcAutomaton<P> {
    #[inline]
    fn next_state(&self, si: StateIdx, i: u8) -> StateIdx {
        let at = i as usize * self.num_states() + si as usize;
        unsafe { *self.trans.get_unchecked(at) }
    }

    #[inline]
    fn get_match(&self, si: StateIdx, outi: usize, texti: usize) -> Match {
        let pati = self.out[si as usize][outi];
        let patlen = self.pats[pati].as_ref().len();
        let start = texti + 1 - patlen;
        Match {
            pati: pati,
            start: start,
            end: start + patlen,
        }
    }

    #[inline]
    fn has_match(&self, si: StateIdx, outi: usize) -> bool {
        unsafe { outi < self.out.get_unchecked(si as usize).len() }
    }

    #[inline]
    fn start_bytes(&self) -> &[u8] {
        &self.start_bytes
    }

    #[inline]
    fn patterns(&self) -> &[P] {
        &self.pats
    }

    #[inline]
    fn pattern(&self, i: usize) -> &P {
        &self.pats[i]
    }
}

impl<P: AsRef<[u8]>> FullAcAutomaton<P> {
    fn build_matrix<T: Transitions>(&mut self, ac: &AcAutomaton<P, T>) {
        for (si, s) in ac.states.iter().enumerate().skip(1) {
            for b in AllBytesIter::new() {
                self.set(si as StateIdx, b, ac.next_state(si as StateIdx, b));
            }
            self.out[si].extend_from_slice(&s.out);
        }
    }
}

impl<P: AsRef<[u8]> + fmt::Debug> fmt::Debug for FullAcAutomaton<P> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "FullAcAutomaton({:?})", self.pats)
    }
}
<|endoftext|>