<commit_before>use crate::value::AMQPValue;

use std::{
    collections::{BTreeMap, btree_map},
    borrow, fmt, str,
};

use serde::{Deserialize, Serialize};

/// Enumeration referencing all the available AMQP types
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub enum AMQPType {
    /// A bool
    Boolean,
    /// An i8
    ShortShortInt,
    /// A u8
    ShortShortUInt,
    /// An i16
    ShortInt,
    /// A u16
    ShortUInt,
    /// An i32
    LongInt,
    /// A u32
    LongUInt,
    /// An i64
    LongLongInt,
    /// A u64
    LongLongUInt,
    /// An f32
    Float,
    /// An f64
    Double,
    /// A decimal value represented by a scale and a value
    DecimalValue,
    /// Deprecated, a String
    ShortString,
    /// A String
    LongString,
    /// An array of AMQPValue
    FieldArray,
    /// A timestamp (u32)
    Timestamp,
    /// A Map<String, AMQPValue>
    FieldTable,
    /// An array of bytes, RabbitMQ specific
    ByteArray, /* ByteArray is specific to RabbitMQ */
    /// No value
    Void,
}

impl AMQPType {
    /// Get the AMQPType corresponding to the given id.
    /// We don't strictly follow the spec here but rather the RabbitMQ implementation
    /// 's' means ShortInt (like 'U') instead of ShortString
    /// 'l' and 'L' both mean LongLongInt (no LongLongUInt)
    pub fn from_id(id: char) -> Option<AMQPType> {
        match id {
            't' => Some(AMQPType::Boolean),
            'b' => Some(AMQPType::ShortShortInt),
            'B' => Some(AMQPType::ShortShortUInt),
            /* Specs says 'U', RabbitMQ says 's' (which means ShortString in specs) */
            's' |
            'U' => Some(AMQPType::ShortInt),
            'u' => Some(AMQPType::ShortUInt),
            'I' => Some(AMQPType::LongInt),
            'i' => Some(AMQPType::LongUInt),
            /* RabbitMQ treats both 'l' and 'L' as LongLongInt and ignores LongLongUInt */
            'L' |
            'l' => Some(AMQPType::LongLongInt),
            'f' => Some(AMQPType::Float),
            'd' => Some(AMQPType::Double),
            'D' => Some(AMQPType::DecimalValue),
            'S' => Some(AMQPType::LongString),
            'A' => Some(AMQPType::FieldArray),
            'T' => Some(AMQPType::Timestamp),
            'F' => Some(AMQPType::FieldTable),
            'x' => Some(AMQPType::ByteArray),
            'V' => Some(AMQPType::Void),
            _   => None,
        }
    }

    /// Get the id from an AMQPType
    /// We don't strictly follow the spec here but rather the RabbitMQ implementation
    /// ShortString doesn't have an id, we return '_' instead
    /// ShortInt is supposed to be 'U' but we use 's'
    /// LongLongUInt is supposed to be 'L' but we return 'l' as LongLongInt
    pub fn get_id(self) -> char {
        match self {
            AMQPType::Boolean        => 't',
            AMQPType::ShortShortInt  => 'b',
            AMQPType::ShortShortUInt => 'B',
            /* Specs says 'U', RabbitMQ says 's' (which means ShortString in specs) */
            AMQPType::ShortInt       => 's',
            AMQPType::ShortUInt      => 'u',
            AMQPType::LongInt        => 'I',
            AMQPType::LongUInt       => 'i',
            /* RabbitMQ treats both 'l' and 'L' as LongLongInt and ignores LongLongUInt */
            AMQPType::LongLongInt    |
            AMQPType::LongLongUInt   => 'l',
            AMQPType::Float          => 'f',
            AMQPType::Double         => 'd',
            AMQPType::DecimalValue   => 'D',
            /* ShortString only exists for internal usage, we shouldn't ever have to use this */
            AMQPType::ShortString    => '_',
            AMQPType::LongString     => 'S',
            AMQPType::FieldArray     => 'A',
            AMQPType::Timestamp      => 'T',
            AMQPType::FieldTable     => 'F',
            AMQPType::ByteArray      => 'x',
            AMQPType::Void           => 'V',
        }
    }
}

impl fmt::Display for AMQPType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

/// A bool
pub type Boolean        = bool;
/// An i8
pub type ShortShortInt  = i8;
/// A u8
pub type ShortShortUInt = u8;
/// An i16
pub type ShortInt       = i16;
/// A u16
pub type ShortUInt      = u16;
/// An i32
pub type LongInt        = i32;
/// A u32
pub type LongUInt       = u32;
/// An i64
pub type LongLongInt    = i64;
/// A u64
pub type LongLongUInt   = u64;
/// A f32
pub type Float          = f32;
/// A f64
pub type Double         = f64;
/// A timestamp (u32)
pub type Timestamp      = LongLongUInt;
/// No value
pub type Void           = ();

/// A String (deprecated)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
pub struct ShortString(String);
/// A String
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
pub struct LongString(String);
/// An array of AMQPValue
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
pub struct FieldArray(Vec<AMQPValue>);
/// A Map<String, AMQPValue>
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
pub struct FieldTable(BTreeMap<ShortString, AMQPValue>);
/// An array of bytes (RabbitMQ specific)
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct ByteArray(Vec<u8>);

/// A Decimal value composed of a scale and a value
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct DecimalValue {
    /// The scale of the value
    pub scale: ShortShortUInt,
    /// The actual value
    pub value: LongUInt,
}

/// A Reference pointing to a ShortString
pub struct ShortStringRef<'a>(pub &'a str);
/// A Reference pointing to a LongString
pub struct LongStringRef<'a>(pub &'a str);

impl<'a> ShortString {
    /// Get a reference to a ShortString
    pub fn as_ref(&'a self) -> ShortStringRef<'a> {
        ShortStringRef(&self.0)
    }

    /// Get a reference to a LongString as &str
    pub fn as_str(&'a self) -> &'a str {
        self.0.as_str()
    }

    /// Splits a string slice by whitespace.
    pub fn split_whitespace(&'a self) -> str::SplitWhitespace<'a> {
        self.0.split_whitespace()
    }
}

impl From<&str> for ShortString {
    fn from(s: &str) -> Self {
        Self(s.to_owned())
    }
}

impl borrow::Borrow<str> for ShortString {
    fn borrow(&self) -> &str {
        self.0.borrow()
    }
}

impl fmt::Display for ShortString {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl<'a> ShortStringRef<'a> {
    pub(crate) fn as_bytes(&self) -> &[u8] {
        self.0.as_bytes()
    }

    pub(crate) fn len(&self) -> usize {
        self.0.len()
    }
}

impl Default for ShortStringRef<'static> {
    fn default() -> Self {
        Self("")
    }
}

impl<'a> From<&'a str> for ShortStringRef<'a> {
    fn from(s: &'a str) -> Self {
        Self(s)
    }
}

impl<'a> LongString {
    /// Get a reference to a LongString
    pub fn as_ref(&'a self) -> LongStringRef<'a> {
        LongStringRef(&self.0)
    }

    /// Get a reference to a LongString as &str
    pub fn as_str(&'a self) -> &'a str {
        self.0.as_str()
    }

    /// Splits a string slice by whitespace.
    pub fn split_whitespace(&'a self) -> str::SplitWhitespace<'a> {
        self.0.split_whitespace()
    }
}

impl From<&str> for LongString {
    fn from(s: &str) -> Self {
        Self(s.to_owned())
    }
}

impl borrow::Borrow<str> for LongString {
    fn borrow(&self) -> &str {
        self.0.borrow()
    }
}

impl fmt::Display for LongString {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl<'a> LongStringRef<'a> {
    pub(crate) fn as_bytes(&self) -> &[u8] {
        self.0.as_bytes()
    }

    pub(crate) fn len(&self) -> usize {
        self.0.len()
    }
}

impl Default for LongStringRef<'static> {
    fn default() -> Self {
        Self("")
    }
}

impl<'a> From<&'a str> for LongStringRef<'a> {
    fn from(s: &'a str) -> Self {
        Self(s)
    }
}

impl FieldArray {
    pub(crate) fn as_slice(&self) -> &[AMQPValue] {
        self.0.as_slice()
    }

    pub(crate) fn push(&mut self, v: AMQPValue) {
        self.0.push(v);
    }
}

impl From<Vec<AMQPValue>> for FieldArray {
    fn from(v: Vec<AMQPValue>) -> Self {
        Self(v)
    }
}

impl FieldTable {
    /// Insert a new entry in the table
    pub fn insert(&mut self, k: ShortString, v: AMQPValue) {
        self.0.insert(k, v);
    }

    /// Check whether the table contains the given key
    pub fn contains_key(&self, k: &str) -> bool {
        self.0.contains_key(k)
    }
}

impl<'a> IntoIterator for &'a FieldTable {
    type Item = (&'a ShortString, &'a AMQPValue);
    type IntoIter = btree_map::Iter<'a, ShortString, AMQPValue>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.iter()
    }
}

impl From<BTreeMap<ShortString, AMQPValue>> for FieldTable {
    fn from(m: BTreeMap<ShortString, AMQPValue>) -> Self {
        Self(m)
    }
}

impl ByteArray {
    pub(crate) fn as_slice(&self) -> &[u8] {
        self.0.as_slice()
    }

    pub(crate) fn len(&self) -> usize {
        self.0.len()
    }
}

impl From<Vec<u8>> for ByteArray {
    fn from(v: Vec<u8>) -> Self {
        Self(v)
    }
}

impl From<&[u8]> for ByteArray {
    fn from(v: &[u8]) -> Self {
        Self(v.to_vec())
    }
}

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

    #[test]
    fn test_type_from_id() {
        assert_eq!(AMQPType::from_id('T'), Some(AMQPType::Timestamp));
        assert_eq!(AMQPType::from_id('S'), Some(AMQPType::LongString));
        assert_eq!(AMQPType::from_id('s'), Some(AMQPType::ShortInt));
        assert_eq!(AMQPType::from_id('U'), Some(AMQPType::ShortInt));
        assert_eq!(AMQPType::from_id('l'), Some(AMQPType::LongLongInt));
        assert_eq!(AMQPType::from_id('z'), None);
    }

    #[test]
    fn test_type_get_id() {
        assert_eq!(AMQPType::LongLongInt.get_id(),  'l');
        assert_eq!(AMQPType::LongLongUInt.get_id(), 'l');
        assert_eq!(AMQPType::ShortString.get_id(),  '_');
    }

    #[test]
    fn test_type_to_string() {
        assert_eq!(AMQPType::Boolean.to_string(), "Boolean");
        assert_eq!(AMQPType::Void.to_string(),    "Void");
    }
}
<commit_msg>types: add some other From impls<commit_after>use crate::value::AMQPValue;

use std::{
    collections::{BTreeMap, btree_map},
    borrow, fmt, str,
};

use serde::{Deserialize, Serialize};

/// Enumeration referencing all the available AMQP types
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub enum AMQPType {
    /// A bool
    Boolean,
    /// An i8
    ShortShortInt,
    /// A u8
    ShortShortUInt,
    /// An i16
    ShortInt,
    /// A u16
    ShortUInt,
    /// An i32
    LongInt,
    /// A u32
    LongUInt,
    /// An i64
    LongLongInt,
    /// A u64
    LongLongUInt,
    /// An f32
    Float,
    /// An f64
    Double,
    /// A decimal value represented by a scale and a value
    DecimalValue,
    /// Deprecated, a String
    ShortString,
    /// A String
    LongString,
    /// An array of AMQPValue
    FieldArray,
    /// A timestamp (u32)
    Timestamp,
    /// A Map<String, AMQPValue>
    FieldTable,
    /// An array of bytes, RabbitMQ specific
    ByteArray, /* ByteArray is specific to RabbitMQ */
    /// No value
    Void,
}

impl AMQPType {
    /// Get the AMQPType corresponding to the given id.
    /// We don't strictly follow the spec here but rather the RabbitMQ implementation
    /// 's' means ShortInt (like 'U') instead of ShortString
    /// 'l' and 'L' both mean LongLongInt (no LongLongUInt)
    pub fn from_id(id: char) -> Option<AMQPType> {
        match id {
            't' => Some(AMQPType::Boolean),
            'b' => Some(AMQPType::ShortShortInt),
            'B' => Some(AMQPType::ShortShortUInt),
            /* Specs says 'U', RabbitMQ says 's' (which means ShortString in specs) */
            's' |
            'U' => Some(AMQPType::ShortInt),
            'u' => Some(AMQPType::ShortUInt),
            'I' => Some(AMQPType::LongInt),
            'i' => Some(AMQPType::LongUInt),
            /* RabbitMQ treats both 'l' and 'L' as LongLongInt and ignores LongLongUInt */
            'L' |
            'l' => Some(AMQPType::LongLongInt),
            'f' => Some(AMQPType::Float),
            'd' => Some(AMQPType::Double),
            'D' => Some(AMQPType::DecimalValue),
            'S' => Some(AMQPType::LongString),
            'A' => Some(AMQPType::FieldArray),
            'T' => Some(AMQPType::Timestamp),
            'F' => Some(AMQPType::FieldTable),
            'x' => Some(AMQPType::ByteArray),
            'V' => Some(AMQPType::Void),
            _   => None,
        }
    }

    /// Get the id from an AMQPType
    /// We don't strictly follow the spec here but rather the RabbitMQ implementation
    /// ShortString doesn't have an id, we return '_' instead
    /// ShortInt is supposed to be 'U' but we use 's'
    /// LongLongUInt is supposed to be 'L' but we return 'l' as LongLongInt
    pub fn get_id(self) -> char {
        match self {
            AMQPType::Boolean        => 't',
            AMQPType::ShortShortInt  => 'b',
            AMQPType::ShortShortUInt => 'B',
            /* Specs says 'U', RabbitMQ says 's' (which means ShortString in specs) */
            AMQPType::ShortInt       => 's',
            AMQPType::ShortUInt      => 'u',
            AMQPType::LongInt        => 'I',
            AMQPType::LongUInt       => 'i',
            /* RabbitMQ treats both 'l' and 'L' as LongLongInt and ignores LongLongUInt */
            AMQPType::LongLongInt    |
            AMQPType::LongLongUInt   => 'l',
            AMQPType::Float          => 'f',
            AMQPType::Double         => 'd',
            AMQPType::DecimalValue   => 'D',
            /* ShortString only exists for internal usage, we shouldn't ever have to use this */
            AMQPType::ShortString    => '_',
            AMQPType::LongString     => 'S',
            AMQPType::FieldArray     => 'A',
            AMQPType::Timestamp      => 'T',
            AMQPType::FieldTable     => 'F',
            AMQPType::ByteArray      => 'x',
            AMQPType::Void           => 'V',
        }
    }
}

impl fmt::Display for AMQPType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

/// A bool
pub type Boolean        = bool;
/// An i8
pub type ShortShortInt  = i8;
/// A u8
pub type ShortShortUInt = u8;
/// An i16
pub type ShortInt       = i16;
/// A u16
pub type ShortUInt      = u16;
/// An i32
pub type LongInt        = i32;
/// A u32
pub type LongUInt       = u32;
/// An i64
pub type LongLongInt    = i64;
/// A u64
pub type LongLongUInt   = u64;
/// A f32
pub type Float          = f32;
/// A f64
pub type Double         = f64;
/// A timestamp (u32)
pub type Timestamp      = LongLongUInt;
/// No value
pub type Void           = ();

/// A String (deprecated)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
pub struct ShortString(String);
/// A String
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
pub struct LongString(String);
/// An array of AMQPValue
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
pub struct FieldArray(Vec<AMQPValue>);
/// A Map<String, AMQPValue>
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
pub struct FieldTable(BTreeMap<ShortString, AMQPValue>);
/// An array of bytes (RabbitMQ specific)
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct ByteArray(Vec<u8>);

/// A Decimal value composed of a scale and a value
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct DecimalValue {
    /// The scale of the value
    pub scale: ShortShortUInt,
    /// The actual value
    pub value: LongUInt,
}

/// A Reference pointing to a ShortString
pub struct ShortStringRef<'a>(pub &'a str);
/// A Reference pointing to a LongString
pub struct LongStringRef<'a>(pub &'a str);

impl<'a> ShortString {
    /// Get a reference to a ShortString
    pub fn as_ref(&'a self) -> ShortStringRef<'a> {
        ShortStringRef(&self.0)
    }

    /// Get a reference to a LongString as &str
    pub fn as_str(&'a self) -> &'a str {
        self.0.as_str()
    }

    /// Splits a string slice by whitespace.
    pub fn split_whitespace(&'a self) -> str::SplitWhitespace<'a> {
        self.0.split_whitespace()
    }
}

impl From<String> for ShortString {
    fn from(s: String) -> Self {
        Self(s)
    }
}

impl From<&str> for ShortString {
    fn from(s: &str) -> Self {
        s.to_owned().into()
    }
}

impl borrow::Borrow<str> for ShortString {
    fn borrow(&self) -> &str {
        self.0.borrow()
    }
}

impl fmt::Display for ShortString {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl<'a> ShortStringRef<'a> {
    pub(crate) fn as_bytes(&self) -> &[u8] {
        self.0.as_bytes()
    }

    pub(crate) fn len(&self) -> usize {
        self.0.len()
    }
}

impl Default for ShortStringRef<'static> {
    fn default() -> Self {
        Self("")
    }
}

impl<'a> From<&'a str> for ShortStringRef<'a> {
    fn from(s: &'a str) -> Self {
        Self(s)
    }
}

impl<'a> LongString {
    /// Get a reference to a LongString
    pub fn as_ref(&'a self) -> LongStringRef<'a> {
        LongStringRef(&self.0)
    }

    /// Get a reference to a LongString as &str
    pub fn as_str(&'a self) -> &'a str {
        self.0.as_str()
    }

    /// Splits a string slice by whitespace.
    pub fn split_whitespace(&'a self) -> str::SplitWhitespace<'a> {
        self.0.split_whitespace()
    }
}

impl From<String> for LongString {
    fn from(s: String) -> Self {
        Self(s)
    }
}

impl From<&str> for LongString {
    fn from(s: &str) -> Self {
        s.to_owned().into()
    }
}

impl borrow::Borrow<str> for LongString {
    fn borrow(&self) -> &str {
        self.0.borrow()
    }
}

impl fmt::Display for LongString {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl<'a> LongStringRef<'a> {
    pub(crate) fn as_bytes(&self) -> &[u8] {
        self.0.as_bytes()
    }

    pub(crate) fn len(&self) -> usize {
        self.0.len()
    }
}

impl Default for LongStringRef<'static> {
    fn default() -> Self {
        Self("")
    }
}

impl<'a> From<&'a str> for LongStringRef<'a> {
    fn from(s: &'a str) -> Self {
        Self(s)
    }
}

impl FieldArray {
    pub(crate) fn as_slice(&self) -> &[AMQPValue] {
        self.0.as_slice()
    }

    pub(crate) fn push(&mut self, v: AMQPValue) {
        self.0.push(v);
    }
}

impl From<Vec<AMQPValue>> for FieldArray {
    fn from(v: Vec<AMQPValue>) -> Self {
        Self(v)
    }
}

impl FieldTable {
    /// Insert a new entry in the table
    pub fn insert(&mut self, k: ShortString, v: AMQPValue) {
        self.0.insert(k, v);
    }

    /// Check whether the table contains the given key
    pub fn contains_key(&self, k: &str) -> bool {
        self.0.contains_key(k)
    }
}

impl<'a> IntoIterator for &'a FieldTable {
    type Item = (&'a ShortString, &'a AMQPValue);
    type IntoIter = btree_map::Iter<'a, ShortString, AMQPValue>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.iter()
    }
}

impl From<BTreeMap<ShortString, AMQPValue>> for FieldTable {
    fn from(m: BTreeMap<ShortString, AMQPValue>) -> Self {
        Self(m)
    }
}

impl ByteArray {
    pub(crate) fn as_slice(&self) -> &[u8] {
        self.0.as_slice()
    }

    pub(crate) fn len(&self) -> usize {
        self.0.len()
    }
}

impl From<Vec<u8>> for ByteArray {
    fn from(v: Vec<u8>) -> Self {
        Self(v)
    }
}

impl From<&[u8]> for ByteArray {
    fn from(v: &[u8]) -> Self {
        Self(v.to_vec())
    }
}

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

    #[test]
    fn test_type_from_id() {
        assert_eq!(AMQPType::from_id('T'), Some(AMQPType::Timestamp));
        assert_eq!(AMQPType::from_id('S'), Some(AMQPType::LongString));
        assert_eq!(AMQPType::from_id('s'), Some(AMQPType::ShortInt));
        assert_eq!(AMQPType::from_id('U'), Some(AMQPType::ShortInt));
        assert_eq!(AMQPType::from_id('l'), Some(AMQPType::LongLongInt));
        assert_eq!(AMQPType::from_id('z'), None);
    }

    #[test]
    fn test_type_get_id() {
        assert_eq!(AMQPType::LongLongInt.get_id(),  'l');
        assert_eq!(AMQPType::LongLongUInt.get_id(), 'l');
        assert_eq!(AMQPType::ShortString.get_id(),  '_');
    }

    #[test]
    fn test_type_to_string() {
        assert_eq!(AMQPType::Boolean.to_string(), "Boolean");
        assert_eq!(AMQPType::Void.to_string(),    "Void");
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate petgraph;
extern crate test;

use test::Bencher;
use petgraph::prelude::*;

use petgraph::{EdgeType};
use petgraph::stable_graph::{
    node_index,
};

/// An almost full set
const FULL_A: &'static str = "
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 0 1 1 1 0 1
 1 1 1 1 1 1 1 1 1 1
";

#[bench]
fn full_edges_default(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);

    bench.iter(|| a.edges(node_index(1)).count())
}

#[bench]
fn full_edges_out(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);
    bench.iter(|| a.edges_directed(node_index(1), Outgoing).count())
}
#[bench]
fn full_edges_in(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);

    bench.iter(|| a.edges_directed(node_index(1), Incoming).count())
}

/// Parse a text adjacency matrix format into a directed graph
fn parse_stable_graph<Ty: EdgeType>(s: &str) -> StableGraph<(), (), Ty>
{
    let mut gr = StableGraph::default();
    let s = s.trim();
    let lines = s.lines().filter(|l| !l.is_empty());
    for (row, line) in lines.enumerate() {
        for (col, word) in line.split(' ')
                                .filter(|s| s.len() > 0)
                                .enumerate()
        {
            let has_edge = word.parse::<i32>().unwrap();
            assert!(has_edge == 0 || has_edge == 1);
            if has_edge == 0 {
                continue;
            }
            while col >= gr.node_count() || row >= gr.node_count() {
                gr.add_node(());
            }
            gr.update_edge(node_index(row), node_index(col), ());
        }
    }
    gr
}

<commit_msg>Add benchmarks for neighbors on stablegraph<commit_after>#![feature(test)]

extern crate petgraph;
extern crate test;

use test::Bencher;
use petgraph::prelude::*;

use petgraph::{EdgeType};
use petgraph::stable_graph::{
    node_index,
};

/// An almost full set
const FULL_A: &'static str = "
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 0 1 1 1 0 1
 1 1 1 1 1 1 1 1 1 1
";

#[bench]
fn full_edges_default(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);

    bench.iter(|| a.edges(node_index(1)).count())
}

#[bench]
fn full_edges_out(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);
    bench.iter(|| a.edges_directed(node_index(1), Outgoing).count())
}
#[bench]
fn full_edges_in(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);

    bench.iter(|| a.edges_directed(node_index(1), Incoming).count())
}

#[bench]
fn neighbors_default(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);

    bench.iter(|| a.neighbors(node_index(1)).count())
}

#[bench]
fn neighbors_out(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);
    bench.iter(|| a.neighbors_directed(node_index(1), Outgoing).count())
}
#[bench]
fn neighbors_in(bench: &mut Bencher)
{
    let a = parse_stable_graph::<Directed>(FULL_A);

    bench.iter(|| a.neighbors_directed(node_index(1), Incoming).count())
}

/// Parse a text adjacency matrix format into a directed graph
fn parse_stable_graph<Ty: EdgeType>(s: &str) -> StableGraph<(), (), Ty>
{
    let mut gr = StableGraph::default();
    let s = s.trim();
    let lines = s.lines().filter(|l| !l.is_empty());
    for (row, line) in lines.enumerate() {
        for (col, word) in line.split(' ')
                                .filter(|s| s.len() > 0)
                                .enumerate()
        {
            let has_edge = word.parse::<i32>().unwrap();
            assert!(has_edge == 0 || has_edge == 1);
            if has_edge == 0 {
                continue;
            }
            while col >= gr.node_count() || row >= gr.node_count() {
                gr.add_node(());
            }
            gr.update_edge(node_index(row), node_index(col), ());
        }
    }
    gr
}

<|endoftext|>


<commit_before>use crate::{process::Process, timer::Timer, InterruptHandle};

use log::info;
use slotmap::{Key, KeyData, SlotMap};
use snafu::{ResultExt, Snafu};
use std::{
    path::Path,
    result, str, thread,
    time::{Duration, Instant},
};
use sysinfo::{ProcessRefreshKind, RefreshKind, System, SystemExt};
use wasmtime::{
    Caller, Config, Engine, Extern, Linker, Memory, Module, OptLevel, Store, Trap, TypedFunc,
};

/// An error that is returned when the creation of a new runtime fails.
#[derive(Debug, Snafu)]
#[snafu(context(suffix(false)))]
pub enum CreationError {
    /// Failed creating the WebAssembly engine.
    EngineCreation {
        /// The underlying error.
        source: anyhow::Error,
    },
    /// Failed loading the WebAssembly module.
    ModuleLoading {
        /// The underlying error.
        source: anyhow::Error,
    },
    /// Failed linking the WebAssembly module.
    #[snafu(display("Failed linking the function `{name}` to the WebAssembly module."))]
    LinkFunction {
        /// The name of the function that failed to link.
        name: &'static str,
        /// The underlying error.
        source: anyhow::Error,
    },
    /// Failed instantiating the WebAssembly module.
    ModuleInstantiation {
        /// The underlying error.
        source: anyhow::Error,
    },
    /// The WebAssembly module has no exported function named `update`, which is
    /// a required function.
    MissingUpdateFunction {
        /// The underlying error.
        source: anyhow::Error,
    },
    /// The WebAssembly module has no exported function memory called `memory`,
    /// which is a requirement.
    MissingMemory,
}

/// An error that is returned when executing the WebAssembly module fails.
#[derive(Debug, Snafu)]
#[snafu(context(suffix(false)))]
pub enum RunError {
    /// Failed running the `update` function.
    RunUpdate {
        /// The underlying error.
        source: Trap,
    },
}

slotmap::new_key_type! {
    struct ProcessKey;
}

pub struct Context<T: Timer> {
    tick_rate: Duration,
    processes: SlotMap<ProcessKey, Process>,
    timer: T,
    memory: Option<Memory>,
    process_list: ProcessList,
}

pub struct ProcessList {
    system: System,
    last_check: Instant,
}

impl ProcessList {
    fn new() -> Self {
        Self {
            system: System::new_with_specifics(
                RefreshKind::new().with_processes(ProcessRefreshKind::new()),
            ),
            last_check: Instant::now() - Duration::from_secs(1),
        }
    }

    pub fn refresh(&mut self) {
        let now = Instant::now();
        if now - self.last_check >= Duration::from_secs(1) {
            self.system
                .refresh_processes_specifics(ProcessRefreshKind::new());
            self.last_check = now;
        }
    }

    pub fn process_by_name(&self, name: &str) -> Vec<&sysinfo::Process> {
        self.system.process_by_name(name)
    }

    pub fn is_open(&self, pid: sysinfo::Pid) -> bool {
        self.system.process(pid).is_some()
    }
}

/// An auto splitter runtime that allows using an auto splitter provided as a
/// WebAssembly module to control a timer.
pub struct Runtime<T: Timer> {
    store: Store<Context<T>>,
    update: TypedFunc<(), ()>,
    prev_time: Instant,
}

impl<T: Timer> Runtime<T> {
    /// Creates a new runtime with the given path to the WebAssembly module and
    /// the timer that the module then controls.
    pub fn new<P: AsRef<Path>>(path: P, timer: T) -> Result<Self, CreationError> {
        let engine = Engine::new(
            Config::new()
                .cranelift_opt_level(OptLevel::Speed)
                .interruptable(true),
        )
        .context(EngineCreation)?;

        let mut store = Store::new(
            &engine,
            Context {
                processes: SlotMap::with_key(),
                tick_rate: Duration::from_secs(1) / 120,
                timer,
                memory: None,
                process_list: ProcessList::new(),
            },
        );

        let module = Module::from_file(&engine, path).context(ModuleLoading)?;
        let mut linker = Linker::new(&engine);
        bind_interface(&mut linker)?;
        let instance = linker
            .instantiate(&mut store, &module)
            .context(ModuleInstantiation)?;

        let update = instance
            .get_typed_func(&mut store, "update")
            .context(MissingUpdateFunction)?;

        if let Some(Extern::Memory(mem)) = instance.get_export(&mut store, "memory") {
            store.data_mut().memory = Some(mem);
        } else {
            return Err(CreationError::MissingMemory);
        }

        Ok(Self {
            store,
            update,
            prev_time: Instant::now(),
        })
    }

    /// Accesses an interrupt handle that allows you to interrupt the ongoing
    /// execution of the WebAssembly module. A WebAssembly module may
    /// accidentally or maliciously loop forever, which is why this is needed.
    pub fn interrupt_handle(&self) -> InterruptHandle {
        self.store
            .interrupt_handle()
            .expect("We configured the runtime to produce an interrupt handle.")
    }

    /// Runs the exported `update` function of the WebAssembly module a single
    /// time. If the module has not been configured yet, this will also call the
    /// optional `configure` function beforehand.
    pub fn step(&mut self) -> Result<(), RunError> {
        self.update.call(&mut self.store, ()).context(RunUpdate)
    }

    /// Sleeps until the next tick based on the current tick rate. The auto
    /// splitter can change this tick rate. It is 120Hz by default.
    pub fn sleep(&mut self) {
        let target = self.store.data().tick_rate;
        let delta = self.prev_time.elapsed();
        if delta < target {
            thread::sleep(target - delta);
        }
        self.prev_time = Instant::now();
    }
}

fn bind_interface<T: Timer>(linker: &mut Linker<Context<T>>) -> Result<(), CreationError> {
    linker
        .func_wrap(
            "env",
            "timer_start",
            |mut caller: Caller<'_, Context<T>>| {
                caller.data_mut().timer.start();
            },
        )
        .context(LinkFunction {
            name: "timer_start",
        })?
        .func_wrap(
            "env",
            "timer_split",
            |mut caller: Caller<'_, Context<T>>| {
                caller.data_mut().timer.split();
            },
        )
        .context(LinkFunction {
            name: "timer_split",
        })?
        .func_wrap(
            "env",
            "timer_reset",
            |mut caller: Caller<'_, Context<T>>| {
                caller.data_mut().timer.reset();
            },
        )
        .context(LinkFunction {
            name: "timer_reset",
        })?
        .func_wrap("env", "timer_pause_game_time", {
            |mut caller: Caller<'_, Context<T>>| caller.data_mut().timer.pause_game_time()
        })
        .context(LinkFunction {
            name: "timer_pause_game_time",
        })?
        .func_wrap("env", "timer_resume_game_time", {
            |mut caller: Caller<'_, Context<T>>| caller.data_mut().timer.resume_game_time()
        })
        .context(LinkFunction {
            name: "timer_resume_game_time",
        })?
        .func_wrap("env", "timer_set_game_time", {
            |mut caller: Caller<'_, Context<T>>, secs: i64, nanos: i32| {
                caller
                    .data_mut()
                    .timer
                    .set_game_time(time::Duration::new(secs, nanos));
            }
        })
        .context(LinkFunction {
            name: "timer_set_game_time",
        })?
        .func_wrap("env", "runtime_set_tick_rate", {
            |mut caller: Caller<'_, Context<T>>, ticks_per_sec: f64| {
                info!(target: "Auto Splitter", "New Tick Rate: {ticks_per_sec}");
                caller.data_mut().tick_rate = Duration::from_secs_f64(ticks_per_sec.recip());
            }
        })
        .context(LinkFunction {
            name: "runtime_set_tick_rate",
        })?
        .func_wrap("env", "timer_get_state", {
            |caller: Caller<'_, Context<T>>| caller.data().timer.state() as u32
        })
        .context(LinkFunction {
            name: "timer_get_state",
        })?
        .func_wrap("env", "runtime_print_message", {
            |mut caller: Caller<'_, Context<T>>, ptr: u32, len: u32| {
                let message = read_str(&mut caller, ptr, len)?;
                info!(target: "Auto Splitter", "{message}");
                Ok(())
            }
        })
        .context(LinkFunction {
            name: "runtime_print_message",
        })?
        .func_wrap("env", "timer_set_variable", {
            |mut caller: Caller<'_, Context<T>>,
             name_ptr: u32,
             name_len: u32,
             value_ptr: u32,
             value_len: u32|
             -> result::Result<(), Trap> {
                let name = read_str(&mut caller, name_ptr, name_len)?;
                let value = read_str(&mut caller, value_ptr, value_len)?;
                caller.data_mut().timer.set_variable(&name, &value);
                Ok(())
            }
        })
        .context(LinkFunction {
            name: "timer_set_variable",
        })?
        .func_wrap("env", "process_attach", {
            |mut caller: Caller<'_, Context<T>>, ptr: u32, len: u32| {
                let process_name = read_str(&mut caller, ptr, len)?;
                Ok(
                    if let Ok(p) =
                        Process::with_name(&process_name, &mut caller.data_mut().process_list)
                    {
                        info!(target: "Auto Splitter", "Attached to a new process: {process_name}");
                        caller.data_mut().processes.insert(p).data().as_ffi()
                    } else {
                        0
                    },
                )
            }
        })
        .context(LinkFunction {
            name: "process_attach",
        })?
        .func_wrap("env", "process_detach", {
            |mut caller: Caller<'_, Context<T>>, process: u64| {
                caller
                    .data_mut()
                    .processes
                    .remove(ProcessKey::from(KeyData::from_ffi(process as u64)))
                    .ok_or_else(|| Trap::new(format!("Invalid process handle {process}")))?;
                info!(target: "Auto Splitter", "Detached from a process.");
                Ok(())
            }
        })
        .context(LinkFunction {
            name: "process_detach",
        })?
        .func_wrap("env", "process_is_open", {
            |mut caller: Caller<'_, Context<T>>, process: u64| {
                let ctx = caller.data_mut();
                let proc = ctx
                    .processes
                    .get(ProcessKey::from(KeyData::from_ffi(process as u64)))
                    .ok_or_else(|| Trap::new(format!("Invalid process handle: {process}")))?;
                Ok(proc.is_open(&mut ctx.process_list) as u32)
            }
        })
        .context(LinkFunction {
            name: "process_is_open",
        })?
        .func_wrap("env", "process_get_module_address", {
            |mut caller: Caller<'_, Context<T>>, process: u64, ptr: u32, len: u32| {
                let module_name = read_str(&mut caller, ptr, len)?;
                Ok(caller
                    .data_mut()
                    .processes
                    .get_mut(ProcessKey::from(KeyData::from_ffi(process as u64)))
                    .ok_or_else(|| Trap::new(format!("Invalid process handle: {process}")))?
                    .module_address(&module_name)
                    .unwrap_or_default())
            }
        })
        .context(LinkFunction {
            name: "process_get_module_address",
        })?
        .func_wrap("env", "process_read", {
            |mut caller: Caller<'_, Context<T>>,
             process: u64,
             address: u64,
             buf_ptr: u32,
             buf_len: u32| {
                let (slice, context) = caller
                    .data()
                    .memory
                    .unwrap()
                    .data_and_store_mut(&mut caller);
                Ok(context
                    .processes
                    .get(ProcessKey::from(KeyData::from_ffi(process as u64)))
                    .ok_or_else(|| Trap::new(format!("Invalid process handle: {process}")))?
                    .read_mem(
                        address,
                        slice
                            .get_mut(buf_ptr as usize..(buf_ptr + buf_len) as usize)
                            .ok_or_else(|| Trap::new("Out of bounds"))?,
                    )
                    .is_ok() as u32)
            }
        })
        .context(LinkFunction {
            name: "process_read",
        })?;
    Ok(())
}

fn read_str<T: Timer>(
    caller: &mut Caller<'_, Context<T>>,
    ptr: u32,
    len: u32,
) -> result::Result<String, Trap> {
    let data = caller
        .data()
        .memory
        .unwrap()
        .data(&caller)
        .get(ptr as usize..(ptr + len) as usize)
        .ok_or_else(|| Trap::new("Pointer out of bounds"))?;
    let s = str::from_utf8(data).map_err(|_| Trap::new("Invalid utf-8"))?;
    Ok(s.to_string())
}
<commit_msg>Borrow the memory from the auto splitter<commit_after>use crate::{process::Process, timer::Timer, InterruptHandle};

use log::info;
use slotmap::{Key, KeyData, SlotMap};
use snafu::{ResultExt, Snafu};
use std::{
    path::Path,
    result, str, thread,
    time::{Duration, Instant},
};
use sysinfo::{ProcessRefreshKind, RefreshKind, System, SystemExt};
use wasmtime::{
    Caller, Config, Engine, Extern, Linker, Memory, Module, OptLevel, Store, Trap, TypedFunc,
};

/// An error that is returned when the creation of a new runtime fails.
#[derive(Debug, Snafu)]
#[snafu(context(suffix(false)))]
pub enum CreationError {
    /// Failed creating the WebAssembly engine.
    EngineCreation {
        /// The underlying error.
        source: anyhow::Error,
    },
    /// Failed loading the WebAssembly module.
    ModuleLoading {
        /// The underlying error.
        source: anyhow::Error,
    },
    /// Failed linking the WebAssembly module.
    #[snafu(display("Failed linking the function `{name}` to the WebAssembly module."))]
    LinkFunction {
        /// The name of the function that failed to link.
        name: &'static str,
        /// The underlying error.
        source: anyhow::Error,
    },
    /// Failed instantiating the WebAssembly module.
    ModuleInstantiation {
        /// The underlying error.
        source: anyhow::Error,
    },
    /// The WebAssembly module has no exported function named `update`, which is
    /// a required function.
    MissingUpdateFunction {
        /// The underlying error.
        source: anyhow::Error,
    },
    /// The WebAssembly module has no exported function memory called `memory`,
    /// which is a requirement.
    MissingMemory,
}

/// An error that is returned when executing the WebAssembly module fails.
#[derive(Debug, Snafu)]
#[snafu(context(suffix(false)))]
pub enum RunError {
    /// Failed running the `update` function.
    RunUpdate {
        /// The underlying error.
        source: Trap,
    },
}

slotmap::new_key_type! {
    struct ProcessKey;
}

pub struct Context<T: Timer> {
    tick_rate: Duration,
    processes: SlotMap<ProcessKey, Process>,
    timer: T,
    memory: Option<Memory>,
    process_list: ProcessList,
}

pub struct ProcessList {
    system: System,
    last_check: Instant,
}

impl ProcessList {
    fn new() -> Self {
        Self {
            system: System::new_with_specifics(
                RefreshKind::new().with_processes(ProcessRefreshKind::new()),
            ),
            last_check: Instant::now() - Duration::from_secs(1),
        }
    }

    pub fn refresh(&mut self) {
        let now = Instant::now();
        if now - self.last_check >= Duration::from_secs(1) {
            self.system
                .refresh_processes_specifics(ProcessRefreshKind::new());
            self.last_check = now;
        }
    }

    pub fn process_by_name(&self, name: &str) -> Vec<&sysinfo::Process> {
        self.system.process_by_name(name)
    }

    pub fn is_open(&self, pid: sysinfo::Pid) -> bool {
        self.system.process(pid).is_some()
    }
}

/// An auto splitter runtime that allows using an auto splitter provided as a
/// WebAssembly module to control a timer.
pub struct Runtime<T: Timer> {
    store: Store<Context<T>>,
    update: TypedFunc<(), ()>,
    prev_time: Instant,
}

impl<T: Timer> Runtime<T> {
    /// Creates a new runtime with the given path to the WebAssembly module and
    /// the timer that the module then controls.
    pub fn new<P: AsRef<Path>>(path: P, timer: T) -> Result<Self, CreationError> {
        let engine = Engine::new(
            Config::new()
                .cranelift_opt_level(OptLevel::Speed)
                .interruptable(true),
        )
        .context(EngineCreation)?;

        let mut store = Store::new(
            &engine,
            Context {
                processes: SlotMap::with_key(),
                tick_rate: Duration::from_secs(1) / 120,
                timer,
                memory: None,
                process_list: ProcessList::new(),
            },
        );

        let module = Module::from_file(&engine, path).context(ModuleLoading)?;
        let mut linker = Linker::new(&engine);
        bind_interface(&mut linker)?;
        let instance = linker
            .instantiate(&mut store, &module)
            .context(ModuleInstantiation)?;

        let update = instance
            .get_typed_func(&mut store, "update")
            .context(MissingUpdateFunction)?;

        if let Some(Extern::Memory(mem)) = instance.get_export(&mut store, "memory") {
            store.data_mut().memory = Some(mem);
        } else {
            return Err(CreationError::MissingMemory);
        }

        Ok(Self {
            store,
            update,
            prev_time: Instant::now(),
        })
    }

    /// Accesses an interrupt handle that allows you to interrupt the ongoing
    /// execution of the WebAssembly module. A WebAssembly module may
    /// accidentally or maliciously loop forever, which is why this is needed.
    pub fn interrupt_handle(&self) -> InterruptHandle {
        self.store
            .interrupt_handle()
            .expect("We configured the runtime to produce an interrupt handle.")
    }

    /// Runs the exported `update` function of the WebAssembly module a single
    /// time. If the module has not been configured yet, this will also call the
    /// optional `configure` function beforehand.
    pub fn step(&mut self) -> Result<(), RunError> {
        self.update.call(&mut self.store, ()).context(RunUpdate)
    }

    /// Sleeps until the next tick based on the current tick rate. The auto
    /// splitter can change this tick rate. It is 120Hz by default.
    pub fn sleep(&mut self) {
        let target = self.store.data().tick_rate;
        let delta = self.prev_time.elapsed();
        if delta < target {
            thread::sleep(target - delta);
        }
        self.prev_time = Instant::now();
    }
}

fn bind_interface<T: Timer>(linker: &mut Linker<Context<T>>) -> Result<(), CreationError> {
    linker
        .func_wrap(
            "env",
            "timer_start",
            |mut caller: Caller<'_, Context<T>>| {
                caller.data_mut().timer.start();
            },
        )
        .context(LinkFunction {
            name: "timer_start",
        })?
        .func_wrap(
            "env",
            "timer_split",
            |mut caller: Caller<'_, Context<T>>| {
                caller.data_mut().timer.split();
            },
        )
        .context(LinkFunction {
            name: "timer_split",
        })?
        .func_wrap(
            "env",
            "timer_reset",
            |mut caller: Caller<'_, Context<T>>| {
                caller.data_mut().timer.reset();
            },
        )
        .context(LinkFunction {
            name: "timer_reset",
        })?
        .func_wrap("env", "timer_pause_game_time", {
            |mut caller: Caller<'_, Context<T>>| caller.data_mut().timer.pause_game_time()
        })
        .context(LinkFunction {
            name: "timer_pause_game_time",
        })?
        .func_wrap("env", "timer_resume_game_time", {
            |mut caller: Caller<'_, Context<T>>| caller.data_mut().timer.resume_game_time()
        })
        .context(LinkFunction {
            name: "timer_resume_game_time",
        })?
        .func_wrap("env", "timer_set_game_time", {
            |mut caller: Caller<'_, Context<T>>, secs: i64, nanos: i32| {
                caller
                    .data_mut()
                    .timer
                    .set_game_time(time::Duration::new(secs, nanos));
            }
        })
        .context(LinkFunction {
            name: "timer_set_game_time",
        })?
        .func_wrap("env", "runtime_set_tick_rate", {
            |mut caller: Caller<'_, Context<T>>, ticks_per_sec: f64| {
                info!(target: "Auto Splitter", "New Tick Rate: {ticks_per_sec}");
                caller.data_mut().tick_rate = Duration::from_secs_f64(ticks_per_sec.recip());
            }
        })
        .context(LinkFunction {
            name: "runtime_set_tick_rate",
        })?
        .func_wrap("env", "timer_get_state", {
            |caller: Caller<'_, Context<T>>| caller.data().timer.state() as u32
        })
        .context(LinkFunction {
            name: "timer_get_state",
        })?
        .func_wrap("env", "runtime_print_message", {
            |mut caller: Caller<'_, Context<T>>, ptr: u32, len: u32| {
                let (memory, _) = memory_and_context(&mut caller);
                let message = read_str(memory, ptr, len)?;
                info!(target: "Auto Splitter", "{message}");
                Ok(())
            }
        })
        .context(LinkFunction {
            name: "runtime_print_message",
        })?
        .func_wrap("env", "timer_set_variable", {
            |mut caller: Caller<'_, Context<T>>,
             name_ptr: u32,
             name_len: u32,
             value_ptr: u32,
             value_len: u32|
             -> result::Result<(), Trap> {
                let (memory, context) = memory_and_context(&mut caller);
                let name = read_str(memory, name_ptr, name_len)?;
                let value = read_str(memory, value_ptr, value_len)?;
                context.timer.set_variable(name, value);
                Ok(())
            }
        })
        .context(LinkFunction {
            name: "timer_set_variable",
        })?
        .func_wrap("env", "process_attach", {
            |mut caller: Caller<'_, Context<T>>, ptr: u32, len: u32| {
                let (memory, context) = memory_and_context(&mut caller);
                let process_name = read_str(memory, ptr, len)?;
                Ok(
                    if let Ok(p) = Process::with_name(process_name, &mut context.process_list) {
                        info!(target: "Auto Splitter", "Attached to a new process: {process_name}");
                        context.processes.insert(p).data().as_ffi()
                    } else {
                        0
                    },
                )
            }
        })
        .context(LinkFunction {
            name: "process_attach",
        })?
        .func_wrap("env", "process_detach", {
            |mut caller: Caller<'_, Context<T>>, process: u64| {
                caller
                    .data_mut()
                    .processes
                    .remove(ProcessKey::from(KeyData::from_ffi(process as u64)))
                    .ok_or_else(|| Trap::new(format!("Invalid process handle {process}")))?;
                info!(target: "Auto Splitter", "Detached from a process.");
                Ok(())
            }
        })
        .context(LinkFunction {
            name: "process_detach",
        })?
        .func_wrap("env", "process_is_open", {
            |mut caller: Caller<'_, Context<T>>, process: u64| {
                let ctx = caller.data_mut();
                let proc = ctx
                    .processes
                    .get(ProcessKey::from(KeyData::from_ffi(process as u64)))
                    .ok_or_else(|| Trap::new(format!("Invalid process handle: {process}")))?;
                Ok(proc.is_open(&mut ctx.process_list) as u32)
            }
        })
        .context(LinkFunction {
            name: "process_is_open",
        })?
        .func_wrap("env", "process_get_module_address", {
            |mut caller: Caller<'_, Context<T>>, process: u64, ptr: u32, len: u32| {
                let (memory, context) = memory_and_context(&mut caller);
                let module_name = read_str(memory, ptr, len)?;
                Ok(context
                    .processes
                    .get_mut(ProcessKey::from(KeyData::from_ffi(process as u64)))
                    .ok_or_else(|| Trap::new(format!("Invalid process handle: {process}")))?
                    .module_address(module_name)
                    .unwrap_or_default())
            }
        })
        .context(LinkFunction {
            name: "process_get_module_address",
        })?
        .func_wrap("env", "process_read", {
            |mut caller: Caller<'_, Context<T>>,
             process: u64,
             address: u64,
             buf_ptr: u32,
             buf_len: u32| {
                let (memory, context) = memory_and_context(&mut caller);
                Ok(context
                    .processes
                    .get(ProcessKey::from(KeyData::from_ffi(process as u64)))
                    .ok_or_else(|| Trap::new(format!("Invalid process handle: {process}")))?
                    .read_mem(address, read_slice_mut(memory, buf_ptr, buf_len)?)
                    .is_ok() as u32)
            }
        })
        .context(LinkFunction {
            name: "process_read",
        })?;
    Ok(())
}

fn memory_and_context<'a, T: Timer>(
    caller: &'a mut Caller<'_, Context<T>>,
) -> (&'a mut [u8], &'a mut Context<T>) {
    caller.data().memory.unwrap().data_and_store_mut(caller)
}

fn read_slice(memory: &[u8], ptr: u32, len: u32) -> Result<&[u8], Trap> {
    memory
        .get(ptr as usize..(ptr + len) as usize)
        .ok_or_else(|| Trap::new("Out of bounds pointer and length pair."))
}

fn read_slice_mut(memory: &mut [u8], ptr: u32, len: u32) -> Result<&mut [u8], Trap> {
    memory
        .get_mut(ptr as usize..(ptr + len) as usize)
        .ok_or_else(|| Trap::new("Out of bounds pointer and length pair."))
}

fn read_str(memory: &[u8], ptr: u32, len: u32) -> Result<&str, Trap> {
    let slice = read_slice(memory, ptr, len)?;
    str::from_utf8(slice).map_err(|_| Trap::new("Invalid utf-8"))
}
<|endoftext|>


<commit_before>//! Defines database & queries for macro expansion.

use std::sync::Arc;

use mbe::MacroRules;
use ra_db::{salsa, SourceDatabase};
use ra_prof::profile;
use ra_syntax::{AstNode, Parse, SyntaxNode};

use crate::{
    ast_id_map::AstIdMap, ExpansionInfo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallLoc,
    MacroDefId, MacroFile, MacroFileKind,
};

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ParseMacroWithInfo {
    pub parsed: Parse<SyntaxNode>,
    pub expansion_info: Arc<ExpansionInfo>,
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct MacroExpandInfo {
    pub arg_map: Arc<mbe::TokenMap>,
    pub def_map: Arc<mbe::TokenMap>,
}

// FIXME: rename to ExpandDatabase
#[salsa::query_group(AstDatabaseStorage)]
pub trait AstDatabase: SourceDatabase {
    fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;

    #[salsa::transparent]
    fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode>;

    #[salsa::interned]
    fn intern_macro(&self, macro_call: MacroCallLoc) -> MacroCallId;
    fn macro_arg(&self, id: MacroCallId) -> Option<(Arc<tt::Subtree>, Arc<mbe::TokenMap>)>;
    fn macro_def(&self, id: MacroDefId) -> Option<(Arc<mbe::MacroRules>, Arc<mbe::TokenMap>)>;
    fn parse_macro(&self, macro_file: MacroFile) -> Option<Parse<SyntaxNode>>;
    fn parse_macro_with_info(&self, macro_file: MacroFile) -> Option<ParseMacroWithInfo>;
    fn macro_expand(
        &self,
        macro_call: MacroCallId,
    ) -> Result<(Arc<tt::Subtree>, MacroExpandInfo), String>;

    fn macro_expansion_info(&self, macro_file: MacroFile) -> Option<Arc<ExpansionInfo>>;
}

pub(crate) fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
    let map =
        db.parse_or_expand(file_id).map_or_else(AstIdMap::default, |it| AstIdMap::from_source(&it));
    Arc::new(map)
}

pub(crate) fn macro_def(
    db: &dyn AstDatabase,
    id: MacroDefId,
) -> Option<(Arc<mbe::MacroRules>, Arc<mbe::TokenMap>)> {
    let macro_call = id.ast_id.to_node(db);
    let arg = macro_call.token_tree()?;
    let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| {
        log::warn!("fail on macro_def to token tree: {:#?}", arg);
        None
    })?;
    let rules = MacroRules::parse(&tt).ok().or_else(|| {
        log::warn!("fail on macro_def parse: {:#?}", tt);
        None
    })?;
    Some((Arc::new(rules), Arc::new(tmap)))
}

pub(crate) fn macro_arg(
    db: &dyn AstDatabase,
    id: MacroCallId,
) -> Option<(Arc<tt::Subtree>, Arc<mbe::TokenMap>)> {
    let loc = db.lookup_intern_macro(id);
    let macro_call = loc.ast_id.to_node(db);
    let arg = macro_call.token_tree()?;
    let (tt, tmap) = mbe::ast_to_token_tree(&arg)?;
    Some((Arc::new(tt), Arc::new(tmap)))
}

pub(crate) fn macro_expand(
    db: &dyn AstDatabase,
    id: MacroCallId,
) -> Result<(Arc<tt::Subtree>, MacroExpandInfo), String> {
    let loc = db.lookup_intern_macro(id);
    let macro_arg = db.macro_arg(id).ok_or("Fail to args in to tt::TokenTree")?;

    let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?;
    let tt = macro_rules.0.expand(&macro_arg.0).map_err(|err| format!("{:?}", err))?;
    // Set a hard limit for the expanded tt
    let count = tt.count();
    if count > 65536 {
        return Err(format!("Total tokens count exceed limit : count = {}", count));
    }

    Ok((
        Arc::new(tt),
        MacroExpandInfo { arg_map: macro_arg.1.clone(), def_map: macro_rules.1.clone() },
    ))
}

pub(crate) fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> {
    match file_id.0 {
        HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()),
        HirFileIdRepr::MacroFile(macro_file) => {
            db.parse_macro(macro_file).map(|it| it.syntax_node())
        }
    }
}

pub(crate) fn parse_macro(
    db: &dyn AstDatabase,
    macro_file: MacroFile,
) -> Option<Parse<SyntaxNode>> {
    let _p = profile("parse_macro_query");
    db.parse_macro_with_info(macro_file).map(|r| r.parsed)
}

pub(crate) fn parse_macro_with_info(
    db: &dyn AstDatabase,
    macro_file: MacroFile,
) -> Option<ParseMacroWithInfo> {
    let macro_call_id = macro_file.macro_call_id;
    let tt = db
        .macro_expand(macro_call_id)
        .map_err(|err| {
            // Note:
            // The final goal we would like to make all parse_macro success,
            // such that the following log will not call anyway.
            log::warn!("fail on macro_parse: (reason: {})", err,);
        })
        .ok()?;
    let res = match macro_file.macro_file_kind {
        MacroFileKind::Items => {
            mbe::token_tree_to_items(&tt.0).ok().map(|(p, map)| (Parse::to_syntax(p), map))
        }
        MacroFileKind::Expr => {
            mbe::token_tree_to_expr(&tt.0).ok().map(|(p, map)| (Parse::to_syntax(p), map))
        }
    };

    res.map(|(parsed, exp_map)| {
        let expand_info = tt.1;
        let loc: MacroCallLoc = db.lookup_intern_macro(macro_call_id);

        let def_start =
            loc.def.ast_id.to_node(db).token_tree().map(|t| t.syntax().text_range().start());
        let arg_start =
            loc.ast_id.to_node(db).token_tree().map(|t| t.syntax().text_range().start());

        let arg_map = arg_start
            .map(|start| exp_map.ranges(&expand_info.arg_map, start))
            .unwrap_or_else(|| Vec::new());
        let def_map = def_start
            .map(|start| exp_map.ranges(&expand_info.def_map, start))
            .unwrap_or_else(|| Vec::new());

        let info = ExpansionInfo { arg_map, def_map };

        ParseMacroWithInfo { parsed, expansion_info: Arc::new(info) }
    })
}

pub(crate) fn macro_expansion_info(
    db: &dyn AstDatabase,
    macro_file: MacroFile,
) -> Option<Arc<ExpansionInfo>> {
    db.parse_macro_with_info(macro_file).map(|res| res.expansion_info.clone())
}
<commit_msg>Use ? and destructing to simplifed long code<commit_after>//! Defines database & queries for macro expansion.

use std::sync::Arc;

use mbe::MacroRules;
use ra_db::{salsa, SourceDatabase};
use ra_prof::profile;
use ra_syntax::{AstNode, Parse, SyntaxNode};

use crate::{
    ast_id_map::AstIdMap, ExpansionInfo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallLoc,
    MacroDefId, MacroFile, MacroFileKind,
};

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ParseMacroWithInfo {
    pub parsed: Parse<SyntaxNode>,
    pub expansion_info: Arc<ExpansionInfo>,
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct MacroExpandInfo {
    pub arg_map: Arc<mbe::TokenMap>,
    pub def_map: Arc<mbe::TokenMap>,
}

// FIXME: rename to ExpandDatabase
#[salsa::query_group(AstDatabaseStorage)]
pub trait AstDatabase: SourceDatabase {
    fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;

    #[salsa::transparent]
    fn parse_or_expand(&self, file_id: HirFileId) -> Option<SyntaxNode>;

    #[salsa::interned]
    fn intern_macro(&self, macro_call: MacroCallLoc) -> MacroCallId;
    fn macro_arg(&self, id: MacroCallId) -> Option<(Arc<tt::Subtree>, Arc<mbe::TokenMap>)>;
    fn macro_def(&self, id: MacroDefId) -> Option<(Arc<mbe::MacroRules>, Arc<mbe::TokenMap>)>;
    fn parse_macro(&self, macro_file: MacroFile) -> Option<Parse<SyntaxNode>>;
    fn parse_macro_with_info(&self, macro_file: MacroFile) -> Option<ParseMacroWithInfo>;
    fn macro_expand(
        &self,
        macro_call: MacroCallId,
    ) -> Result<(Arc<tt::Subtree>, MacroExpandInfo), String>;

    fn macro_expansion_info(&self, macro_file: MacroFile) -> Option<Arc<ExpansionInfo>>;
}

pub(crate) fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
    let map =
        db.parse_or_expand(file_id).map_or_else(AstIdMap::default, |it| AstIdMap::from_source(&it));
    Arc::new(map)
}

pub(crate) fn macro_def(
    db: &dyn AstDatabase,
    id: MacroDefId,
) -> Option<(Arc<mbe::MacroRules>, Arc<mbe::TokenMap>)> {
    let macro_call = id.ast_id.to_node(db);
    let arg = macro_call.token_tree()?;
    let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| {
        log::warn!("fail on macro_def to token tree: {:#?}", arg);
        None
    })?;
    let rules = MacroRules::parse(&tt).ok().or_else(|| {
        log::warn!("fail on macro_def parse: {:#?}", tt);
        None
    })?;
    Some((Arc::new(rules), Arc::new(tmap)))
}

pub(crate) fn macro_arg(
    db: &dyn AstDatabase,
    id: MacroCallId,
) -> Option<(Arc<tt::Subtree>, Arc<mbe::TokenMap>)> {
    let loc = db.lookup_intern_macro(id);
    let macro_call = loc.ast_id.to_node(db);
    let arg = macro_call.token_tree()?;
    let (tt, tmap) = mbe::ast_to_token_tree(&arg)?;
    Some((Arc::new(tt), Arc::new(tmap)))
}

pub(crate) fn macro_expand(
    db: &dyn AstDatabase,
    id: MacroCallId,
) -> Result<(Arc<tt::Subtree>, MacroExpandInfo), String> {
    let loc = db.lookup_intern_macro(id);
    let macro_arg = db.macro_arg(id).ok_or("Fail to args in to tt::TokenTree")?;

    let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?;
    let tt = macro_rules.0.expand(&macro_arg.0).map_err(|err| format!("{:?}", err))?;
    // Set a hard limit for the expanded tt
    let count = tt.count();
    if count > 65536 {
        return Err(format!("Total tokens count exceed limit : count = {}", count));
    }

    Ok((
        Arc::new(tt),
        MacroExpandInfo { arg_map: macro_arg.1.clone(), def_map: macro_rules.1.clone() },
    ))
}

pub(crate) fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> {
    match file_id.0 {
        HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()),
        HirFileIdRepr::MacroFile(macro_file) => {
            db.parse_macro(macro_file).map(|it| it.syntax_node())
        }
    }
}

pub(crate) fn parse_macro(
    db: &dyn AstDatabase,
    macro_file: MacroFile,
) -> Option<Parse<SyntaxNode>> {
    let _p = profile("parse_macro_query");
    db.parse_macro_with_info(macro_file).map(|r| r.parsed)
}

pub(crate) fn parse_macro_with_info(
    db: &dyn AstDatabase,
    macro_file: MacroFile,
) -> Option<ParseMacroWithInfo> {
    let macro_call_id = macro_file.macro_call_id;
    let tt = db
        .macro_expand(macro_call_id)
        .map_err(|err| {
            // Note:
            // The final goal we would like to make all parse_macro success,
            // such that the following log will not call anyway.
            log::warn!("fail on macro_parse: (reason: {})", err,);
        })
        .ok()?;

    let (parsed, exp_map) = match macro_file.macro_file_kind {
        MacroFileKind::Items => {
            mbe::token_tree_to_items(&tt.0).map(|(p, map)| (p.to_syntax(), map)).ok()?
        }
        MacroFileKind::Expr => {
            mbe::token_tree_to_expr(&tt.0).map(|(p, map)| (p.to_syntax(), map)).ok()?
        }
    };

    let expand_info = tt.1;
    let loc: MacroCallLoc = db.lookup_intern_macro(macro_call_id);

    let arg_tt = loc.ast_id.to_node(db).token_tree();
    let def_tt = loc.def.ast_id.to_node(db).token_tree();

    let arg_start = arg_tt.map(|t| t.syntax().text_range().start());
    let def_start = def_tt.map(|t| t.syntax().text_range().start());

    let arg_map =
        arg_start.map(|start| exp_map.ranges(&expand_info.arg_map, start)).unwrap_or_default();
    let def_map =
        def_start.map(|start| exp_map.ranges(&expand_info.def_map, start)).unwrap_or_default();

    let info = ExpansionInfo { arg_map, def_map };

    Some(ParseMacroWithInfo { parsed, expansion_info: Arc::new(info) })
}

pub(crate) fn macro_expansion_info(
    db: &dyn AstDatabase,
    macro_file: MacroFile,
) -> Option<Arc<ExpansionInfo>> {
    db.parse_macro_with_info(macro_file).map(|res| res.expansion_info.clone())
}
<|endoftext|>


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

//! Benchmarks of PEG parsing libraries

#![feature(test)]

/// Run as:
/// ```
/// run nightly cargo bench --features "nom regex pom"
/// ```

use std::env;

extern crate xi_lang;

#[cfg(test)]
extern crate test;

#[cfg(feature = "pom")]
extern crate pom;

#[cfg(feature = "regex")]
extern crate regex;

#[cfg(feature = "nom")]
#[macro_use]
extern crate nom;

#[cfg(feature = "combine")]
extern crate combine;

const TEST_STR: &'static str = "1.2345e56";

#[cfg(all(test, feature = "pom"))]
mod pom_benches {
    use pom::{Parser, DataInput};
    use pom::parser::{one_of, sym};
    use test::Bencher;
    use super::{test, TEST_STR};

    fn pom_number() -> Parser<u8, usize> {
        let integer = one_of(b"123456789") - one_of(b"0123456789").repeat(0..) | sym(b'0');
        let frac = sym(b'.') + one_of(b"0123456789").repeat(1..);
        let exp = one_of(b"eE") + one_of(b"+-").opt() + one_of(b"0123456789").repeat(1..);
        let number = sym(b'-').opt() + integer + frac.opt() + exp.opt();
        number.pos()
    }

    #[bench]
    fn bench_pom(b: &mut Bencher) {
        let parser = pom_number();

        b.iter(|| {
            let mut buf = DataInput::new(test::black_box(TEST_STR.as_bytes()));
            parser.parse(&mut buf)
        })
    }
}

#[cfg(all(test, feature = "regex"))]
mod regex_benches {
    use regex::Regex;
    use test::Bencher;
    use super::{test, TEST_STR};

    #[bench]
    fn bench_regex(b: &mut Bencher) {
        let re = Regex::new(r"^(0|[1-9][0-9]*)(\.[0-9]+)?([eE]([+-])?[0-9]+)?").unwrap();
        b.iter(|| {
            re.find(test::black_box(TEST_STR))
        })
    }
}

#[cfg(all(test, feature = "nom"))]
mod nom_benches {
    use nom::digit;
    use test::Bencher;
    use super::{test, TEST_STR};

    named!(digits <()>,
        fold_many1!(digit, (), |_, _| ())
    );

    named!(nom_num <()>, do_parse!(
        opt!(char!('-')) >>
        alt!(map!(char!('0'), |_| ()) | digits) >>
        opt!(do_parse!(char!('.') >> digits >> ())) >>
        opt!(do_parse!(alt!(char!('e') | char!('E')) >>
            opt!(alt!(char!('+') | char!('-'))) >>
            digits >> ())) >>
        ()
      )
    );

    #[cfg(feature = "nom")]
    #[bench]
    fn bench_nom(b: &mut Bencher) {
        b.iter(|| nom_num(test::black_box(TEST_STR.as_bytes())))
    }
}

#[cfg(all(test, feature = "combine"))]
mod combine_benches {
    use combine::*;
    use combine::range::take_while1;
    use test::Bencher;
    use super::{test, TEST_STR, is_digit};

    fn my_number(s: &[u8]) -> ParseResult<(), &[u8]> {
        (
            token(b'-').map(Some).or(value(None)),
            token(b'0').map(|_| &b"0"[..]).or(take_while1(is_digit)),
            optional((token(b'.'), take_while1(is_digit))),
            optional((token(b'e').or(token(b'E')), token(b'-').map(Some).or(token(b'+').map(Some)).or(value(None)), take_while1(is_digit))),
        ).map(|_| ()).parse_stream(s)
    }

    #[bench]
    fn bench_combine(b: &mut Bencher) {
        assert_eq!(parser(my_number).parse(TEST_STR.as_bytes()), Ok(((), &b""[..])));
        b.iter(|| {
            parser(my_number).parse(test::black_box(TEST_STR.as_bytes()))
        })
    }
}

use xi_lang::peg::{Peg, Optional, OneByte, Alt, OneOrMore};

fn is_digit(c: u8) -> bool {
    c >= b'0' && c <= b'9'
}

fn my_number(s: &[u8]) -> Option<usize> {
    (
        Optional('-'),
        Alt('0', OneOrMore(OneByte(is_digit))),
        Optional(('.', OneOrMore(OneByte(is_digit)))),
        Optional((Alt('e', 'E'), Optional(Alt('-', '+')), OneOrMore(OneByte(is_digit)))),
    ).p(s)
}

fn main() {
    if let Some(s) = env::args().skip(1).next() {
        println!("my: {:?}", my_number(s.as_bytes()));
        /*
        let mut buf = DataInput::new(s.as_bytes());
        println!("pom: {:?}", pom_number().parse(&mut buf));
        let re = Regex::new(r"^(0|[1-9][0-9]*)(\.[0-9]+)?([eE]([+-])?[0-9]+)?").unwrap();
        println!("regex: {:?}", re.find(&s));
        println!("nom: {:?}", nom_num(s.as_bytes()));
        */
    }
}

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

    #[bench]
    fn bench_my_peg(b: &mut Bencher) {
        b.iter(|| my_number(test::black_box(TEST_STR.as_bytes())))
    }

}
<commit_msg>rustfmt benches<commit_after>// Copyright 2017 The xi-editor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Benchmarks of PEG parsing libraries

#![feature(test)]

/// Run as:
/// ```
/// run nightly cargo bench --features "nom regex pom"
/// ```
use std::env;

extern crate xi_lang;

#[cfg(test)]
extern crate test;

#[cfg(feature = "pom")]
extern crate pom;

#[cfg(feature = "regex")]
extern crate regex;

#[cfg(feature = "nom")]
#[macro_use]
extern crate nom;

#[cfg(feature = "combine")]
extern crate combine;

const TEST_STR: &'static str = "1.2345e56";

#[cfg(all(test, feature = "pom"))]
mod pom_benches {
    use super::{test, TEST_STR};
    use pom::parser::{one_of, sym};
    use pom::{DataInput, Parser};
    use test::Bencher;

    fn pom_number() -> Parser<u8, usize> {
        let integer = one_of(b"123456789") - one_of(b"0123456789").repeat(0..) | sym(b'0');
        let frac = sym(b'.') + one_of(b"0123456789").repeat(1..);
        let exp = one_of(b"eE") + one_of(b"+-").opt() + one_of(b"0123456789").repeat(1..);
        let number = sym(b'-').opt() + integer + frac.opt() + exp.opt();
        number.pos()
    }

    #[bench]
    fn bench_pom(b: &mut Bencher) {
        let parser = pom_number();

        b.iter(|| {
            let mut buf = DataInput::new(test::black_box(TEST_STR.as_bytes()));
            parser.parse(&mut buf)
        })
    }
}

#[cfg(all(test, feature = "regex"))]
mod regex_benches {
    use super::{test, TEST_STR};
    use regex::Regex;
    use test::Bencher;

    #[bench]
    fn bench_regex(b: &mut Bencher) {
        let re = Regex::new(r"^(0|[1-9][0-9]*)(\.[0-9]+)?([eE]([+-])?[0-9]+)?").unwrap();
        b.iter(|| re.find(test::black_box(TEST_STR)))
    }
}

#[cfg(all(test, feature = "nom"))]
mod nom_benches {
    use super::{test, TEST_STR};
    use nom::digit;
    use test::Bencher;

    named!(digits<()>, fold_many1!(digit, (), |_, _| ()));

    named!(
        nom_num<()>,
        do_parse!(
            opt!(char!('-'))
                >> alt!(map!(char!('0'), |_| ()) | digits)
                >> opt!(do_parse!(char!('.') >> digits >> ()))
                >> opt!(do_parse!(
                    alt!(char!('e') | char!('E'))
                        >> opt!(alt!(char!('+') | char!('-')))
                        >> digits
                        >> ()
                ))
                >> ()
        )
    );

    #[cfg(feature = "nom")]
    #[bench]
    fn bench_nom(b: &mut Bencher) {
        b.iter(|| nom_num(test::black_box(TEST_STR.as_bytes())))
    }
}

#[cfg(all(test, feature = "combine"))]
mod combine_benches {
    use super::{is_digit, test, TEST_STR};
    use combine::range::take_while1;
    use combine::*;
    use test::Bencher;

    fn my_number(s: &[u8]) -> ParseResult<(), &[u8]> {
        (
            token(b'-').map(Some).or(value(None)),
            token(b'0').map(|_| &b"0"[..]).or(take_while1(is_digit)),
            optional((token(b'.'), take_while1(is_digit))),
            optional((
                token(b'e').or(token(b'E')),
                token(b'-').map(Some).or(token(b'+').map(Some)).or(value(None)),
                take_while1(is_digit),
            )),
        )
            .map(|_| ())
            .parse_stream(s)
    }

    #[bench]
    fn bench_combine(b: &mut Bencher) {
        assert_eq!(parser(my_number).parse(TEST_STR.as_bytes()), Ok(((), &b""[..])));
        b.iter(|| parser(my_number).parse(test::black_box(TEST_STR.as_bytes())))
    }
}

use xi_lang::peg::{Alt, OneByte, OneOrMore, Optional, Peg};

fn is_digit(c: u8) -> bool {
    c >= b'0' && c <= b'9'
}

fn my_number(s: &[u8]) -> Option<usize> {
    (
        Optional('-'),
        Alt('0', OneOrMore(OneByte(is_digit))),
        Optional(('.', OneOrMore(OneByte(is_digit)))),
        Optional((Alt('e', 'E'), Optional(Alt('-', '+')), OneOrMore(OneByte(is_digit)))),
    )
        .p(s)
}

fn main() {
    if let Some(s) = env::args().skip(1).next() {
        println!("my: {:?}", my_number(s.as_bytes()));
        /*
        let mut buf = DataInput::new(s.as_bytes());
        println!("pom: {:?}", pom_number().parse(&mut buf));
        let re = Regex::new(r"^(0|[1-9][0-9]*)(\.[0-9]+)?([eE]([+-])?[0-9]+)?").unwrap();
        println!("regex: {:?}", re.find(&s));
        println!("nom: {:?}", nom_num(s.as_bytes()));
        */
    }
}

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

    #[bench]
    fn bench_my_peg(b: &mut Bencher) {
        b.iter(|| my_number(test::black_box(TEST_STR.as_bytes())))
    }

}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! unlikely {
    ($e:expr) => {
        $e
    };
}

#[macro_export]
macro_rules! likely {
    ($e:expr) => {
        $e
    };
}

#[macro_export]
macro_rules! primitive_enum {
    (
        $(#[$meta:meta])* $visibility:vis
        enum $Name:ident: $PrimitiveType:ident {
            $($Variant:ident $(= $value:expr)?),*
            $(,)?
        }
    ) => {
        $(#[$meta])*
        #[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord)]
        #[repr($PrimitiveType)]
        $visibility enum $Name {
            $($Variant $(= $value)?),*
        }

        impl From<$PrimitiveType> for $Name {
            fn from(primitive: $PrimitiveType) -> $Name {
                unsafe { std::mem::transmute(primitive) }
            }
        }

        impl From<$Name> for $PrimitiveType {
            fn from(v: $Name) -> $PrimitiveType {
                v as $PrimitiveType
            }
        }
    };
}

#[macro_export]
macro_rules! bitfields {
    (
        $(#[$meta:meta])* $visibility:vis
        struct $Name:ident: $InnerType:ident {
            $( [$field_start:literal$(, $field_end:literal)?] $field_get:ident, $field_set:ident: $FieldType:ident ),* $(,)?
            $( readonly = $readonly:expr  $(,)?)?
        }
    ) => {
        $(#[$meta])*
        #[derive(Default, Copy, Clone, PartialEq, Eq, Debug)]
        $visibility struct $Name {
            pub value: $InnerType,
        }

        impl $Name {
            pub const READONLY: $InnerType = 0 $(| $readonly)?;

            pub const fn new(inner_value: $InnerType) -> Self {
                $Name { value: inner_value }
            }

            pub fn set_preserve_bits(&mut self, value: $InnerType) {
                self.value = (value & !Self::READONLY) | (self.value & Self::READONLY)
            }

            $(
                pub fn $field_get(&self) -> $FieldType {
                    let bits = $crate::extract_bits!(self.value, $field_start $(, $field_end)?);
                    $crate::from_bits!(bits, $InnerType, $FieldType)
                }

                pub fn $field_set(&mut self, value: $FieldType) {
                    let new_bits = <$InnerType>::from(value);
                    self.value = $crate::replace_bits!(self.value, new_bits, $field_start $(, $field_end)?);
                }
            )*
        }

        impl From<$InnerType> for $Name {
            fn from(inner_value: $InnerType) -> $Name {
                $Name { value: inner_value }
            }
        }

        impl From<$Name> for $InnerType {
            fn from(v: $Name) -> $InnerType {
                v.value
            }
        }
    };
}

#[macro_export]
macro_rules! extract_bits {
    ($value:expr, $start:expr) => {
        $crate::bits::Bits::bits($value, $start, $start)
    };

    ($value:expr, $start:expr, $end:expr) => {
        $crate::bits::Bits::bits($value, $start, $end)
    };
}

#[macro_export]
macro_rules! replace_bits {
    ($dst:expr, $src:expr, $start:expr) => {
        $crate::bits::Bits::replace_bits($dst, $start, $start, $src)
    };

    ($dst:expr, $src:expr, $start:expr, $end:expr) => {
        $crate::bits::Bits::replace_bits($dst, $start, $end, $src)
    };
}

#[macro_export]
macro_rules! from_bits {
    ($bits:expr, u32, u16) => {
        $bits as u16
    };

    ($bits:expr, $SrcType:ty, bool) => {
        $bits != 0
    };

    ($bits:expr, $SrcType:ty, $DstType:ty) => {
        <$DstType as From<$SrcType>>::from($bits)
    };
}
<commit_msg>Special case `u64` to `u16` conversion in bitfields.<commit_after>#[macro_export]
macro_rules! unlikely {
    ($e:expr) => {
        $e
    };
}

#[macro_export]
macro_rules! likely {
    ($e:expr) => {
        $e
    };
}

#[macro_export]
macro_rules! primitive_enum {
    (
        $(#[$meta:meta])* $visibility:vis
        enum $Name:ident: $PrimitiveType:ident {
            $($Variant:ident $(= $value:expr)?),*
            $(,)?
        }
    ) => {
        $(#[$meta])*
        #[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord)]
        #[repr($PrimitiveType)]
        $visibility enum $Name {
            $($Variant $(= $value)?),*
        }

        impl From<$PrimitiveType> for $Name {
            fn from(primitive: $PrimitiveType) -> $Name {
                unsafe { std::mem::transmute(primitive) }
            }
        }

        impl From<$Name> for $PrimitiveType {
            fn from(v: $Name) -> $PrimitiveType {
                v as $PrimitiveType
            }
        }
    };
}

#[macro_export]
macro_rules! bitfields {
    (
        $(#[$meta:meta])* $visibility:vis
        struct $Name:ident: $InnerType:ident {
            $( [$field_start:literal$(, $field_end:literal)?] $field_get:ident, $field_set:ident: $FieldType:ident ),* $(,)?
            $( readonly = $readonly:expr  $(,)?)?
        }
    ) => {
        $(#[$meta])*
        #[derive(Default, Copy, Clone, PartialEq, Eq, Debug)]
        $visibility struct $Name {
            pub value: $InnerType,
        }

        impl $Name {
            pub const READONLY: $InnerType = 0 $(| $readonly)?;

            pub const fn new(inner_value: $InnerType) -> Self {
                $Name { value: inner_value }
            }

            pub fn set_preserve_bits(&mut self, value: $InnerType) {
                self.value = (value & !Self::READONLY) | (self.value & Self::READONLY)
            }

            $(
                pub fn $field_get(&self) -> $FieldType {
                    let bits = $crate::extract_bits!(self.value, $field_start $(, $field_end)?);
                    $crate::from_bits!(bits, $InnerType, $FieldType)
                }

                pub fn $field_set(&mut self, value: $FieldType) {
                    let new_bits = <$InnerType>::from(value);
                    self.value = $crate::replace_bits!(self.value, new_bits, $field_start $(, $field_end)?);
                }
            )*
        }

        impl From<$InnerType> for $Name {
            fn from(inner_value: $InnerType) -> $Name {
                $Name { value: inner_value }
            }
        }

        impl From<$Name> for $InnerType {
            fn from(v: $Name) -> $InnerType {
                v.value
            }
        }
    };
}

#[macro_export]
macro_rules! extract_bits {
    ($value:expr, $start:expr) => {
        $crate::bits::Bits::bits($value, $start, $start)
    };

    ($value:expr, $start:expr, $end:expr) => {
        $crate::bits::Bits::bits($value, $start, $end)
    };
}

#[macro_export]
macro_rules! replace_bits {
    ($dst:expr, $src:expr, $start:expr) => {
        $crate::bits::Bits::replace_bits($dst, $start, $start, $src)
    };

    ($dst:expr, $src:expr, $start:expr, $end:expr) => {
        $crate::bits::Bits::replace_bits($dst, $start, $end, $src)
    };
}

#[macro_export]
macro_rules! from_bits {
    ($bits:expr, u32, u16) => {
        $bits as u16
    };

    ($bits:expr, u64, u16) => {
        $bits as u16
    };

    ($bits:expr, $SrcType:ty, bool) => {
        $bits != 0
    };

    ($bits:expr, $SrcType:ty, $DstType:ty) => {
        <$DstType as From<$SrcType>>::from($bits)
    };
}
<|endoftext|>


<commit_before>use super::prelude::v1::*;

/// An linked list (used for entries)
pub enum LinkedList<T> {
    Elem(T, Box<LinkedList<T>>),
    Nil,
}

impl<T> LinkedList<T> {
    /// Follow
    pub fn follow(&self) -> Option<&Self> {
        use self::LinkedList::*;
        match *self {
            Elem(_, box ref l) => {
                Some(l)
            },
            Nil => {
                None
            },
        }
    }

    /// Follow mutable
    pub fn follow_mut(&mut self) -> Option<&mut Self> {
        use self::LinkedList::*;
        match *self {
            Elem(_, box ref mut l) => {
                Some(l)
            },
            Nil => {
                None
            },
        }
    }

    /// Push
    pub fn push(&self, elem: T) -> Self {
        LinkedList::Elem(elem, Box::new(LinkedList::Nil))
    }
}

/// A entry in the hash map
pub struct Entry<K, V> {
    data: LinkedList<(K, V)>,
}

impl<K: PartialEq<K>, V> Entry<K, V> {
    pub fn get(&self, key: K) -> Option<&V> {
        let mut cur = self.data.follow();

        loop {
            let next;
            match cur {
                Some(&LinkedList::Elem((ref k, ref v), ref l)) => {
                    if &key == k {
                        return Some(v);
                    } else {
                        next = l.follow();
                    }
                },
                Some(&LinkedList::Nil) | None => {
                    return None;
                },
            }

            cur = next;
        }

    }
    pub fn get_mut(&mut self, key: K) -> Option<&mut V> {

        let mut cur = self.data.follow_mut();

        loop {
            cur = match cur {
                Some(x) => match *x {
                    LinkedList::Elem((ref k, ref mut v), ref mut l) => {
                        if &key == k {
                            return Some(v);
                        } else {
                            l.follow_mut()
                        }
                    },
                    LinkedList::Nil => {
                        return None;
                    },
                },
                None => {
                    return None;
                },
            }

        }
    }
}

/// A hashtable
pub struct HashMap<K, V> {
    data: [Entry<K, V>; 256],
}
<commit_msg>Clean up hash maps<commit_after>use super::prelude::v1::*;

/// An linked list (used for entries)
pub enum LinkedList<T> {
    Elem(T, Box<LinkedList<T>>),
    Nil,
}

impl<T> LinkedList<T> {
    /// Follow
    pub fn follow(&self) -> Option<&Self> {
        use self::LinkedList::*;
        match *self {
            Elem(_, box ref l) => {
                Some(l)
            },
            Nil => {
                None
            },
        }
    }

    /// Follow mutable
    pub fn follow_mut(&mut self) -> Option<&mut Self> {
        use self::LinkedList::*;
        match *self {
            Elem(_, box ref mut l) => {
                Some(l)
            },
            Nil => {
                None
            },
        }
    }

    /// Push
    pub fn push(&self, elem: T) -> Self {
        LinkedList::Elem(elem, Box::new(LinkedList::Nil))
    }
}

/// A entry in the hash map
pub struct Entry<K, V> {
    data: LinkedList<(K, V)>,
}

impl<K: PartialEq<K>, V> Entry<K, V> {
    pub fn get(&self, key: K) -> Option<&V> {
        let mut cur = self.data.follow();

        loop {
            cur = match cur {
                Some(&LinkedList::Elem((ref k, ref v), ref l)) => {
                    if &key == k {
                        return Some(v);
                    } else {
                        l.follow()
                    }
                },
                Some(&LinkedList::Nil) | None => {
                    return None;
                },
            }
        }

    }
    pub fn get_mut(&mut self, key: K) -> Option<&mut V> {

        let mut cur = self.data.follow_mut();

        loop {
            cur = match cur {
                Some(x) => match *x {
                    LinkedList::Elem((ref k, ref mut v), ref mut l) => {
                        if &key == k {
                            return Some(v);
                        } else {
                            l.follow_mut()
                        }
                    },
                    LinkedList::Nil => {
                        return None;
                    },
                },
                None => {
                    return None;
                },
            }

        }
    }
}

/// A hashtable
pub struct HashMap<K, V> {
    data: [Entry<K, V>; 256],
}
<|endoftext|>