<commit_before>use std::io::{Read, BufRead, Error as IoError, ErrorKind};
use std::str::{from_utf8, Utf8Error};

use num::bigint::{BigInt, ToBigInt, Sign, ParseBigIntError};
use byteorder::{ReadBytesExt, LittleEndian, Error as ByteorderError};

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        ReadError(err: ByteorderError) {
            from()
        }
        IoError(err: IoError) {
            from()
        }
        UnknownOpcode(opcode: u8) {}
        InvalidInt {
            from(Utf8Error)
            from(ParseBigIntError)
        }
        InvalidString
        ExpectedTrailingL
        InvalidLong
    }
}

#[derive(Debug)]
pub enum OpCode {
    Int(BigInt),
    BinInt(i32),
    BinInt1(u8),
    BinInt2(u16),
    Long(BigInt),
    Long1(BigInt),
    Long4(BigInt),

    String(Vec<u8>),
    BinString(Vec<u8>),
    ShortBinString(Vec<u8>),

    None,

    NewTrue,
    NewFalse,

    Unicode(String),
    BinUnicode(String),

    Float(f64),
    BinFloat(f64),

    EmptyList,
    Append,
    Appends,
    List,

    EmptyTuple,
    Tuple,
    Tuple1,
    Tuple2,
    Tuple3,

    EmptyDict,
    Dict,
    SetItem,
    SetItems,

    Pop,
    Dup,
    Mark,
    PopMark,

    Get(usize),
    BinGet(usize),
    LongBinGet(usize),
    Put(usize),
    BinPut(usize),
    LongBinPut(usize),

    Ext1(u8),
    Ext2(u16),
    Ext4(i32),

    Global(Vec<u8>, Vec<u8>),
    Reduce,
    Build,
    Inst(Vec<u8>, Vec<u8>),
    Obj,
    NewObj,
    Proto(u8),
    Stop,
    PersId(Vec<u8>),
    BinPersId,
}

fn read_exact<R>(rd: &mut R, mut buf: &mut [u8]) -> Result<(), IoError> where R: Read {
    while !buf.is_empty() {
        match rd.read(buf) {
            Ok(0) => break,
            Ok(n) => { let tmp = buf; buf = &mut tmp[n..]; }
            Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
            Err(e) => return Err(e),
        }
    }
    if !buf.is_empty() {
        Err(IoError::new(ErrorKind::Other,
                       "failed to fill whole buffer"))
    } else {
        Ok(())
    }
}

pub fn read_until_newline<R>(rd: &mut R) -> Result<Vec<u8>, Error> where R: Read + BufRead {
    let mut buf = Vec::new();
    try!(rd.read_until('\n' as u8, &mut buf));

    // Skip last symbol — \n
    match buf.split_last() {
        None => Err(Error::InvalidString),
        Some((_last, init)) => Ok(init.to_vec()),
    }
}

pub fn read_long<R>(rd: &mut R, length: usize) -> Result<BigInt, Error> where R: Read + BufRead {
    let mut buf = vec![0; length];
    try!(read_exact(rd, buf.as_mut()));

    let mut n = BigInt::from_bytes_le(Sign::Plus, &buf);

    let last = match buf.last_mut() {
        None => return Err(Error::InvalidLong),
        Some(last) => last,
    };

    if *last > 127 {
        n = n - (1.to_bigint().unwrap() << (length * 8))
    }

    Ok(n)
}

pub fn read_opcode<R>(rd: &mut R) -> Result<OpCode, Error> where R: Read + BufRead {
    let marker = try!(rd.read_u8());
    return Ok(match marker {
        73 => {
            let s = try!(read_until_newline(rd));
            OpCode::Int(try!(try!(from_utf8(&s)).parse()))  // http://rust-num.github.io/num/num/bigint/struct.BigInt.html#method.parse_bytes
        },
        74 => OpCode::BinInt(try!(rd.read_i32::<LittleEndian>())),
        75 => OpCode::BinInt1(try!(rd.read_u8())),
        77 => OpCode::BinInt2(try!(rd.read_u16::<LittleEndian>())),
        76 => {
            let s = try!(read_until_newline(rd));

            let init = match s.split_last() {
                None => return Err(Error::InvalidString),
                Some((&76, init)) => init,
                Some(_) => return Err(Error::ExpectedTrailingL),
            };

            OpCode::Long(try!(try!(from_utf8(init)).parse()))
        },
        138 => {
            let length = try!(rd.read_u8());
            OpCode::Long1(try!(read_long(rd, length as usize)))

        },
        139 => {
            let length = try!(rd.read_i32::<LittleEndian>());
            OpCode::Long4(try!(read_long(rd, length as usize)))

        },
        c => return Err(Error::UnknownOpcode(c)),
    })
}

#[cfg(test)]
mod tests {
    use std::io::{Cursor};

    use num::{FromPrimitive};

    use super::{OpCode, Error, read_opcode};

    macro_rules! t {
        ($buffer: expr, $pat:pat, $result:expr) => ({
            match read_opcode(&mut Cursor::new(&$buffer[..])) {
                $pat => $result,
                other => {
                    println!("ERROR {:?}", other);
                    assert!(false)
                },
            }
        })
    }

    macro_rules! n {
        ($x: expr) => ({FromPrimitive::from_isize($x).unwrap()})
    }

    #[test]
    fn test_int() {
        t!(b"I", Err(Error::InvalidString), assert!(true));
        t!(b"I\n", Err(Error::InvalidInt), assert!(true));
        t!(b"Iabc\n", Err(Error::InvalidInt), assert!(true));
        t!(b"I123\n", Ok(OpCode::Int(n)), assert_eq!(n, n!(123)));
    }

    #[test]
    fn test_bin_int() {
        t!(b"J\x0a", Err(Error::ReadError(_)), assert!(true));
        t!(b"J\x0a\x00\x00\x00", Ok(OpCode::BinInt(n)), assert_eq!(n, 10));
        t!(b"J\x0a\x00\x00\x01", Ok(OpCode::BinInt(n)), assert_eq!(n, 16777226));
    }

    #[test]
    fn test_bin_int1() {
        t!(b"K", Err(Error::ReadError(_)), assert!(true));
        t!(b"K\x0a", Ok(OpCode::BinInt1(n)), assert_eq!(n, 10));
    }

    #[test]
    fn test_bin_int2() {
        t!(b"M\x0a", Err(Error::ReadError(_)), assert!(true));
        t!(b"M\x0a\x00\x00\x00", Ok(OpCode::BinInt2(n)), assert_eq!(n, 10));
        t!(b"M\x0a\x01\x00\x00", Ok(OpCode::BinInt2(n)), assert_eq!(n, 266));
    }

    #[test]
    fn test_long() {
        t!(b"L", Err(Error::InvalidString), assert!(true));
        t!(b"L\n", Err(Error::InvalidString), assert!(true));
        t!(b"Labc\n", Err(Error::ExpectedTrailingL), assert!(true));
        t!(b"LabcL\n", Err(Error::InvalidInt), assert!(true));
        t!(b"L123L\n", Ok(OpCode::Long(n)), assert_eq!(n, n!(123)));
    }

    #[test]
    fn test_long1() {
        t!(b"\x8a", Err(Error::ReadError(_)), assert!(true));
        t!(b"\x8a\x01\x0a", Ok(OpCode::Long1(n)), assert_eq!(n, n!(10)));
        t!(b"\x8a\x01\xf6", Ok(OpCode::Long1(n)), assert_eq!(n, n!(-10)));
        t!(b"\x8a\x02.\xfb", Ok(OpCode::Long1(n)), assert_eq!(n, n!(-1234)));
    }

    #[test]
    fn test_long4() {
        t!(b"\x8b\x0a", Err(Error::ReadError(_)), assert!(true));
        t!(b"\x8b\x01\x00\x00\x00\x0a", Ok(OpCode::Long4(n)), assert_eq!(n, n!(10)));
        t!(b"\x8b\x01\x00\x00\x00\xf6", Ok(OpCode::Long4(n)), assert_eq!(n, n!(-10)));
        t!(b"\x8b\x02\x00\x00\x00.\xfb", Ok(OpCode::Long4(n)), assert_eq!(n, n!(-1234)));
    }
}
<commit_msg>Add string types<commit_after>use std::io::{Read, BufRead, Error as IoError, ErrorKind};
use std::str::{from_utf8, Utf8Error};

use num::bigint::{BigInt, ToBigInt, Sign, ParseBigIntError};
use byteorder::{ReadBytesExt, LittleEndian, Error as ByteorderError};

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        ReadError(err: ByteorderError) {
            from()
        }
        IoError(err: IoError) {
            from()
        }
        UnknownOpcode(opcode: u8) {}
        InvalidInt {
            from(Utf8Error)
            from(ParseBigIntError)
        }
        InvalidString
        ExpectedTrailingL
        InvalidLong
    }
}

#[derive(Debug)]
pub enum OpCode {
    Int(BigInt),
    BinInt(i32),
    BinInt1(u8),
    BinInt2(u16),
    Long(BigInt),
    Long1(BigInt),
    Long4(BigInt),

    String(Vec<u8>),
    BinString(Vec<u8>),
    ShortBinString(Vec<u8>),

    None,

    NewTrue,
    NewFalse,

    Unicode(String),
    BinUnicode(String),

    Float(f64),
    BinFloat(f64),

    EmptyList,
    Append,
    Appends,
    List,

    EmptyTuple,
    Tuple,
    Tuple1,
    Tuple2,
    Tuple3,

    EmptyDict,
    Dict,
    SetItem,
    SetItems,

    Pop,
    Dup,
    Mark,
    PopMark,

    Get(usize),
    BinGet(usize),
    LongBinGet(usize),
    Put(usize),
    BinPut(usize),
    LongBinPut(usize),

    Ext1(u8),
    Ext2(u16),
    Ext4(i32),

    Global(Vec<u8>, Vec<u8>),
    Reduce,
    Build,
    Inst(Vec<u8>, Vec<u8>),
    Obj,
    NewObj,
    Proto(u8),
    Stop,
    PersId(Vec<u8>),
    BinPersId,
}

fn read_exact<R>(rd: &mut R, mut buf: &mut [u8]) -> Result<(), IoError> where R: Read {
    while !buf.is_empty() {
        match rd.read(buf) {
            Ok(0) => break,
            Ok(n) => { let tmp = buf; buf = &mut tmp[n..]; }
            Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
            Err(e) => return Err(e),
        }
    }
    if !buf.is_empty() {
        Err(IoError::new(ErrorKind::Other,
                       "failed to fill whole buffer"))
    } else {
        Ok(())
    }
}

pub fn read_until_newline<R>(rd: &mut R) -> Result<Vec<u8>, Error> where R: Read + BufRead {
    let mut buf = Vec::new();
    try!(rd.read_until('\n' as u8, &mut buf));

    // Skip last symbol — \n
    match buf.split_last() {
        None => Err(Error::InvalidString),
        Some((_last, init)) => Ok(init.to_vec()),
    }
}

pub fn read_long<R>(rd: &mut R, length: usize) -> Result<BigInt, Error> where R: Read + BufRead {
    let mut buf = vec![0; length];
    try!(read_exact(rd, buf.as_mut()));

    let mut n = BigInt::from_bytes_le(Sign::Plus, &buf);

    let last = match buf.last_mut() {
        None => return Err(Error::InvalidLong),
        Some(last) => last,
    };

    if *last > 127 {
        n = n - (1.to_bigint().unwrap() << (length * 8))
    }

    Ok(n)
}

pub fn read_opcode<R>(rd: &mut R) -> Result<OpCode, Error> where R: Read + BufRead {
    let marker = try!(rd.read_u8());
    return Ok(match marker {
        73 => {
            let s = try!(read_until_newline(rd));
            OpCode::Int(try!(try!(from_utf8(&s)).parse()))  // http://rust-num.github.io/num/num/bigint/struct.BigInt.html#method.parse_bytes
        },
        74 => OpCode::BinInt(try!(rd.read_i32::<LittleEndian>())),
        75 => OpCode::BinInt1(try!(rd.read_u8())),
        77 => OpCode::BinInt2(try!(rd.read_u16::<LittleEndian>())),
        76 => {
            let s = try!(read_until_newline(rd));

            let init = match s.split_last() {
                None => return Err(Error::InvalidString),
                Some((&76, init)) => init,
                Some(_) => return Err(Error::ExpectedTrailingL),
            };

            OpCode::Long(try!(try!(from_utf8(init)).parse()))
        },
        138 => {
            let length = try!(rd.read_u8());
            OpCode::Long1(try!(read_long(rd, length as usize)))

        },
        139 => {
            let length = try!(rd.read_i32::<LittleEndian>());
            OpCode::Long4(try!(read_long(rd, length as usize)))

        },
        83 => {OpCode::String(try!(read_until_newline(rd)))} // TODO: escaping
        84 => {
            let length = try!(rd.read_i32::<LittleEndian>());
            let mut buf = vec![0; length as usize];
            try!(read_exact(rd, &mut buf));
            OpCode::BinString(buf)
        }
        85 => {
            let length = try!(rd.read_u8());
            let mut buf = vec![0; length as usize];
            try!(read_exact(rd, &mut buf));
            OpCode::ShortBinString(buf)
        }
        c => return Err(Error::UnknownOpcode(c)),
    })
}

#[cfg(test)]
mod tests {
    use std::io::{Cursor};

    use num::{FromPrimitive};

    use super::{OpCode, Error, read_opcode};

    macro_rules! t {
        ($buffer: expr, $pat:pat, $result:expr) => ({
            match read_opcode(&mut Cursor::new(&$buffer[..])) {
                $pat => $result,
                other => {
                    println!("ERROR {:?}", other);
                    assert!(false)
                },
            }
        })
    }

    macro_rules! n {
        ($x: expr) => ({FromPrimitive::from_isize($x).unwrap()})
    }

    #[test]
    fn test_int() {
        t!(b"I", Err(Error::InvalidString), assert!(true));
        t!(b"I\n", Err(Error::InvalidInt), assert!(true));
        t!(b"Iabc\n", Err(Error::InvalidInt), assert!(true));
        t!(b"I123\n", Ok(OpCode::Int(n)), assert_eq!(n, n!(123)));
    }

    #[test]
    fn test_bin_int() {
        t!(b"J\x0a", Err(Error::ReadError(_)), assert!(true));
        t!(b"J\x0a\x00\x00\x00", Ok(OpCode::BinInt(n)), assert_eq!(n, 10));
        t!(b"J\x0a\x00\x00\x01", Ok(OpCode::BinInt(n)), assert_eq!(n, 16777226));
    }

    #[test]
    fn test_bin_int1() {
        t!(b"K", Err(Error::ReadError(_)), assert!(true));
        t!(b"K\x0a", Ok(OpCode::BinInt1(n)), assert_eq!(n, 10));
    }

    #[test]
    fn test_bin_int2() {
        t!(b"M\x0a", Err(Error::ReadError(_)), assert!(true));
        t!(b"M\x0a\x00\x00\x00", Ok(OpCode::BinInt2(n)), assert_eq!(n, 10));
        t!(b"M\x0a\x01\x00\x00", Ok(OpCode::BinInt2(n)), assert_eq!(n, 266));
    }

    #[test]
    fn test_long() {
        t!(b"L", Err(Error::InvalidString), assert!(true));
        t!(b"L\n", Err(Error::InvalidString), assert!(true));
        t!(b"Labc\n", Err(Error::ExpectedTrailingL), assert!(true));
        t!(b"LabcL\n", Err(Error::InvalidInt), assert!(true));
        t!(b"L123L\n", Ok(OpCode::Long(n)), assert_eq!(n, n!(123)));
    }

    #[test]
    fn test_long1() {
        t!(b"\x8a", Err(Error::ReadError(_)), assert!(true));
        t!(b"\x8a\x01\x0a", Ok(OpCode::Long1(n)), assert_eq!(n, n!(10)));
        t!(b"\x8a\x01\xf6", Ok(OpCode::Long1(n)), assert_eq!(n, n!(-10)));
        t!(b"\x8a\x02.\xfb", Ok(OpCode::Long1(n)), assert_eq!(n, n!(-1234)));
    }

    #[test]
    fn test_long4() {
        t!(b"\x8b\x0a", Err(Error::ReadError(_)), assert!(true));
        t!(b"\x8b\x01\x00\x00\x00\x0a", Ok(OpCode::Long4(n)), assert_eq!(n, n!(10)));
        t!(b"\x8b\x01\x00\x00\x00\xf6", Ok(OpCode::Long4(n)), assert_eq!(n, n!(-10)));
        t!(b"\x8b\x02\x00\x00\x00.\xfb", Ok(OpCode::Long4(n)), assert_eq!(n, n!(-1234)));
    }

    #[test]
    fn test_string() {
        t!(b"S", Err(Error::InvalidString), assert!(true));
        t!(b"S\n", Ok(OpCode::String(s)), assert_eq!(s, b""));
        t!(b"Sabc\n", Ok(OpCode::String(s)), assert_eq!(s, b"abc"));
        t!(b"S123\n", Ok(OpCode::String(s)), assert_eq!(s, b"123"));
        t!(b"S\\n\n", Ok(OpCode::String(s)), assert_eq!(s, b"\\n"));
    }

    #[test]
    fn test_bin_string() {
        t!(b"T\x00\x00\x00\x00", Ok(OpCode::BinString(s)), assert_eq!(s, b""));
        t!(b"T\x03\x00\x00\x00abc", Ok(OpCode::BinString(s)), assert_eq!(s, b"abc"));
        t!(b"T\x03\x00\x00\x00123", Ok(OpCode::BinString(s)), assert_eq!(s, b"123"));
        t!(b"T\x02\x00\x00\x00\\n", Ok(OpCode::BinString(s)), assert_eq!(s, b"\\n"));
    }

    #[test]
    fn test_short_bin_string() {
        t!(b"U\x00", Ok(OpCode::ShortBinString(s)), assert_eq!(s, b""));
        t!(b"U\x03abc", Ok(OpCode::ShortBinString(s)), assert_eq!(s, b"abc"));
        t!(b"U\x03123", Ok(OpCode::ShortBinString(s)), assert_eq!(s, b"123"));
        t!(b"U\x02\\n", Ok(OpCode::ShortBinString(s)), assert_eq!(s, b"\\n"));
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

mod varlink_grammar {

    pub enum VType<'a> {
        Bool,
        Int8,
        UInt8,
        Int16,
        UInt16,
        Int32,
        UInt32,
        Int64,
        UInt64,
        Float32,
        Float64,
        VString,
        VTypename(&'a str),
        VStruct(Box<VStruct<'a>>),
    }

    pub struct VTypeExt<'a> {
        vtype: VType<'a>,
        nullable: bool,
        isarray: Option<Option<usize>>,
    }

    pub struct Argument<'a> {
        pub name: &'a str,
        pub vtypes : Vec<VTypeExt<'a>>,
    }

    pub struct VStruct<'a> {
        pub elts: Vec<Argument<'a>>,
    }

    pub struct Typedef<'a> {
        pub name: &'a str,
        pub vstruct : VStruct<'a>,
    }

    pub struct Method<'a> {
        pub name: &'a str,
        pub input : VStruct<'a>,
        pub output : VStruct<'a>,
    }

    enum MethodOrTypedef<'a> {
        Typedef(Typedef<'a>),
        Method(Method<'a>),
    }

    pub struct Interface<'a> {
        pub name: &'a str,
        pub methods: Vec<Method<'a>>,
        pub typedefs: Vec<Typedef<'a>>,
    }

    use std::fmt;

    impl<'a> fmt::Display for VType<'a> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            match *self {
                VType::Bool => write!(f, "Bool"),
                VType::Int8 => write!(f, "Int8"),
                VType::UInt8 => write!(f, "UInt8"),
                VType::Int16 => write!(f, "Int16"),
                VType::UInt16 => write!(f, "UInt16"),
                VType::Int32 => write!(f, "Int32"),
                VType::UInt32 => write!(f, "UInt32"),
                VType::Int64 => write!(f, "Int64"),
                VType::UInt64 => write!(f, "UInt64"),
                VType::Float32 => write!(f, "Float32"),
                VType::Float64 => write!(f, "Float64"),
                VType::VString => write!(f, "String"),
                VType::VTypename(ref s) => write!(f, "{}", s),
                VType::VStruct(ref v) => write!(f, "{}", v),
            }
        }
    }

    impl<'a> fmt::Display for VTypeExt<'a> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.vtype)?;
            if let Some(t) = self.isarray {
                match t {
                    Some(v) => write!(f, "[{}]", v)?,
                    None    => write!(f, "[]")?,
                }
            }
            if self.nullable {
                write!(f, "?")
            } else {
                Ok(())
            }
        }
    }

    impl<'a> fmt::Display for Argument<'a> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            if self.vtypes.len() == 1 {
                write!(f, "{}: {}", self.name, self.vtypes[0])?;
            } else {
                let mut iter = self.vtypes.iter();
                if let Some(fst) = iter.next() {
                    write!(f, "{}: {}", self.name, fst)?;
                    for elt in iter {
                        write!(f, "| {}", elt)?;
                    }
                }
            }
            Ok(())
        }
    }

    impl<'a> fmt::Display for VStruct<'a> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "(")?;
            let mut iter = self.elts.iter();
            if let Some(fst) = iter.next() {
                write!(f, "{}", fst)?;
                for elt in iter {
                    write!(f, ", {}", elt)?;
                }
            }
            write!(f, ")")
        }
    }

    impl<'a> fmt::Display for Interface<'a> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{} {{\n", self.name)?;
            for t in &self.typedefs {
                write!(f, "  type {} {};\n", t.name, t.vstruct)?;
            }
            for m in &self.methods {
                write!(f, "  {}{} -> {};\n", m.name, m.input, m.output)?;
            }
            write!(f, "}}\n")
        }
    }

    impl<'a> Interface<'a> {
        fn from_token(n: &'a str, ts: Vec<Typedef<'a>>, m: Method<'a>, mt: Vec<MethodOrTypedef<'a>>) -> Interface<'a> {
            let mut i = Interface { name: n, methods: Vec::new(), typedefs: Vec::new() };

            i.methods.push(m);

            for o in mt {
                match o {
                    MethodOrTypedef::Method(m) => i.methods.push(m),
                    MethodOrTypedef::Typedef(t) => i.typedefs.push(t)
                };
            }

            for t in ts {
                i.typedefs.push(t);
            }

            return i;
        }
    }

    include!(concat!(env!("OUT_DIR"), "/varlink_grammar.rs"));
}

#[cfg(test)]
use self::varlink_grammar::*;

#[test]
fn test_standard() {
    let ifaces = interfaces("
/**
 * The Varlink Service Interface is added to every varlink service. It provides
 * the Introspect method to be called by a client to retrieve the bootstrap
 * information from a service.
 */
org.varlink.service {
  type Type (name: string, typestring: string)
  type Method (
    name: string,
    monitor: bool,
    type_in: string,
    type_out: string
  )
  type Interface (name: string, types: Type[], methods: Method[])
  type Property (key: string, value: string)
  type InterfaceDescription (
    description: string,
    types: string[],
    methods: string[]
  )

  /**
   * Returns the machine readable information about a service. It contains the service
   * name, all available interfaces with their defined method calls and types.
   */
  Introspect(version: uint64) -> (name: string, interfaces: Interface[])

  /**
   * Returns the human readable description of a service.
   */
  Help() -> (
    description: string,
    properties: Property[],
    interfaces: InterfaceDescription[]
  )
}
")
        .unwrap();
    assert_eq!(ifaces[0].name, "org.varlink.service");
    assert_eq!(ifaces[0].to_string(), "org.varlink.service {
  type Type (name: String, typestring: String);
  type Method (name: String, monitor: Bool, type_in: String, type_out: String);
  type Interface (name: String, types: Type[], methods: Method[]);
  type Property (key: String, value: String);
  type InterfaceDescription (description: String, types: String[], methods: String[]);
  Introspect(version: UInt64) -> (name: String, interfaces: Interface[]);
  Help() -> (description: String, properties: Property[], interfaces: InterfaceDescription[]);
}
");

}

#[test]
fn test_one_method() {
    assert!(interfaces("/* comment */ foo.bar{ Foo()->() }").is_ok());
}

#[test]
fn test_one_method_no_type() {
    assert!(interfaces("foo.bar{ Foo()->(b:) }").is_err());
}

#[test]
fn test_domainnames() {
    assert!(interfaces("org.varlink.service {F()->()}").is_ok());
    assert!(interfaces("com.example.0example {F()->()}").is_ok());
    assert!(interfaces("com.example.example-dash {F()->()}").is_ok());
    assert!(interfaces("xn--lgbbat1ad8j.example.algeria {F()->()}").is_ok());
    assert!(interfaces("com.-example.leadinghyphen {F()->()}").is_err());
    assert!(interfaces("com.example-.danglinghyphen- {F()->()}").is_err());
    assert!(interfaces("Com.example.uppercase-toplevel {F()->()}").is_err());
    assert!(interfaces("Co9.exmaple.number-toplevel {F()->()}").is_err());
    assert!(interfaces("com.Example {F()->()}").is_err());
}

#[test]
fn test_no_method() {
    assert!(interfaces("
org.varlink.service {
  type Interface (name: string, types: Type[], methods: Method[])
  type Property (key: string, value: string)
}
")
        .is_err());
}

#[test]
fn test_type_no_args() {
    assert!(interfaces("foo.bar{ type I () F()->() }").is_ok());
}

#[test]
fn test_type_one_arg() {
    assert!(interfaces("foo.bar{ type I (b:bool) F()->() }").is_ok());
}

#[test]
fn test_type_one_array() {
    assert!(interfaces("foo.bar{ type I (b:bool[]) F()->() }").is_ok());
    assert!(interfaces("foo.bar{ type I (b:bool[ ]) F()->() }").is_err());
    assert!(interfaces("foo.bar{ type I (b:bool[1]) F()->() }").is_ok());
    assert!(interfaces("foo.bar{ type I (b:bool[ 1 ]) F()->() }").is_err());
    assert!(interfaces("foo.bar{ type I (b:bool[ 1 1 ]) F()->() }").is_err());
}

#[test]
fn test_method_struct_optional() {
    assert!(interfaces("foo.bar{ Foo(foo: (i: int64, b: bool)? )->()}").is_ok());
}

#[test]
fn test_method_struct_array_optional() {
    assert!(interfaces("foo.bar{ Foo(foo: (i: int64, b: bool)[]? )->()}").is_ok());
}

#[test]
fn test_method_struct_array_optional_wrong() {
    assert!(interfaces("foo.bar{ Foo(foo: (i: int64, b: bool)?[]) -> ()}").is_err());
}

#[test]
fn test_format() {
    let i = interfaces("foo.bar{ type I (b:bool[1]) F()->() }").unwrap();
    assert_eq!(i[0].to_string(), "foo.bar {
  type I (b: Bool[1]);
  F() -> ();
}
");
}
<commit_msg>lowercase types<commit_after>#![allow(dead_code)]

mod varlink_grammar {

    pub enum VType<'a> {
        Bool,
        Int8,
        UInt8,
        Int16,
        UInt16,
        Int32,
        UInt32,
        Int64,
        UInt64,
        Float32,
        Float64,
        VString,
        VTypename(&'a str),
        VStruct(Box<VStruct<'a>>),
    }

    pub struct VTypeExt<'a> {
        vtype: VType<'a>,
        nullable: bool,
        isarray: Option<Option<usize>>,
    }

    pub struct Argument<'a> {
        pub name: &'a str,
        pub vtypes : Vec<VTypeExt<'a>>,
    }

    pub struct VStruct<'a> {
        pub elts: Vec<Argument<'a>>,
    }

    pub struct Typedef<'a> {
        pub name: &'a str,
        pub vstruct : VStruct<'a>,
    }

    pub struct Method<'a> {
        pub name: &'a str,
        pub input : VStruct<'a>,
        pub output : VStruct<'a>,
    }

    enum MethodOrTypedef<'a> {
        Typedef(Typedef<'a>),
        Method(Method<'a>),
    }

    pub struct Interface<'a> {
        pub name: &'a str,
        pub methods: Vec<Method<'a>>,
        pub typedefs: Vec<Typedef<'a>>,
    }

    use std::fmt;

    impl<'a> fmt::Display for VType<'a> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            match *self {
                VType::Bool => write!(f, "bool"),
                VType::Int8 => write!(f, "int8"),
                VType::UInt8 => write!(f, "uint8"),
                VType::Int16 => write!(f, "int16"),
                VType::UInt16 => write!(f, "uint16"),
                VType::Int32 => write!(f, "int32"),
                VType::UInt32 => write!(f, "uint32"),
                VType::Int64 => write!(f, "int64"),
                VType::UInt64 => write!(f, "uint64"),
                VType::Float32 => write!(f, "float32"),
                VType::Float64 => write!(f, "float64"),
                VType::VString => write!(f, "string"),
                VType::VTypename(ref s) => write!(f, "{}", s),
                VType::VStruct(ref v) => write!(f, "{}", v),
            }
        }
    }

    impl<'a> fmt::Display for VTypeExt<'a> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.vtype)?;
            if let Some(t) = self.isarray {
                match t {
                    Some(v) => write!(f, "[{}]", v)?,
                    None    => write!(f, "[]")?,
                }
            }
            if self.nullable {
                write!(f, "?")
            } else {
                Ok(())
            }
        }
    }

    impl<'a> fmt::Display for Argument<'a> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            if self.vtypes.len() == 1 {
                write!(f, "{}: {}", self.name, self.vtypes[0])?;
            } else {
                let mut iter = self.vtypes.iter();
                if let Some(fst) = iter.next() {
                    write!(f, "{}: {}", self.name, fst)?;
                    for elt in iter {
                        write!(f, "| {}", elt)?;
                    }
                }
            }
            Ok(())
        }
    }

    impl<'a> fmt::Display for VStruct<'a> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "(")?;
            let mut iter = self.elts.iter();
            if let Some(fst) = iter.next() {
                write!(f, "{}", fst)?;
                for elt in iter {
                    write!(f, ", {}", elt)?;
                }
            }
            write!(f, ")")
        }
    }

    impl<'a> fmt::Display for Interface<'a> {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{} {{\n", self.name)?;
            for t in &self.typedefs {
                write!(f, "  type {} {};\n", t.name, t.vstruct)?;
            }
            for m in &self.methods {
                write!(f, "  {}{} -> {};\n", m.name, m.input, m.output)?;
            }
            write!(f, "}}\n")
        }
    }

    impl<'a> Interface<'a> {
        fn from_token(n: &'a str, ts: Vec<Typedef<'a>>, m: Method<'a>, mt: Vec<MethodOrTypedef<'a>>) -> Interface<'a> {
            let mut i = Interface { name: n, methods: Vec::new(), typedefs: Vec::new() };

            i.methods.push(m);

            for o in mt {
                match o {
                    MethodOrTypedef::Method(m) => i.methods.push(m),
                    MethodOrTypedef::Typedef(t) => i.typedefs.push(t)
                };
            }

            for t in ts {
                i.typedefs.push(t);
            }

            return i;
        }
    }

    include!(concat!(env!("OUT_DIR"), "/varlink_grammar.rs"));
}

#[cfg(test)]
use self::varlink_grammar::*;

#[test]
fn test_standard() {
    let ifaces = interfaces("
/**
 * The Varlink Service Interface is added to every varlink service. It provides
 * the Introspect method to be called by a client to retrieve the bootstrap
 * information from a service.
 */
org.varlink.service {
  type Type (name: string, typestring: string)
  type Method (
    name: string,
    monitor: bool,
    type_in: string,
    type_out: string
  )
  type Interface (name: string, types: Type[], methods: Method[])
  type Property (key: string, value: string)
  type InterfaceDescription (
    description: string,
    types: string[],
    methods: string[]
  )

  /**
   * Returns the machine readable information about a service. It contains the service
   * name, all available interfaces with their defined method calls and types.
   */
  Introspect(version: uint64) -> (name: string, interfaces: Interface[])

  /**
   * Returns the human readable description of a service.
   */
  Help() -> (
    description: string,
    properties: Property[],
    interfaces: InterfaceDescription[]
  )
}
")
        .unwrap();
    assert_eq!(ifaces[0].name, "org.varlink.service");
    assert_eq!(ifaces[0].to_string(), "org.varlink.service {
  type Type (name: string, typestring: string);
  type Method (name: string, monitor: bool, type_in: string, type_out: string);
  type Interface (name: string, types: Type[], methods: Method[]);
  type Property (key: string, value: string);
  type InterfaceDescription (description: string, types: string[], methods: string[]);
  Introspect(version: uint64) -> (name: string, interfaces: Interface[]);
  Help() -> (description: string, properties: Property[], interfaces: InterfaceDescription[]);
}
");

}

#[test]
fn test_one_method() {
    assert!(interfaces("/* comment */ foo.bar{ Foo()->() }").is_ok());
}

#[test]
fn test_one_method_no_type() {
    assert!(interfaces("foo.bar{ Foo()->(b:) }").is_err());
}

#[test]
fn test_domainnames() {
    assert!(interfaces("org.varlink.service {F()->()}").is_ok());
    assert!(interfaces("com.example.0example {F()->()}").is_ok());
    assert!(interfaces("com.example.example-dash {F()->()}").is_ok());
    assert!(interfaces("xn--lgbbat1ad8j.example.algeria {F()->()}").is_ok());
    assert!(interfaces("com.-example.leadinghyphen {F()->()}").is_err());
    assert!(interfaces("com.example-.danglinghyphen- {F()->()}").is_err());
    assert!(interfaces("Com.example.uppercase-toplevel {F()->()}").is_err());
    assert!(interfaces("Co9.exmaple.number-toplevel {F()->()}").is_err());
    assert!(interfaces("com.Example {F()->()}").is_err());
}

#[test]
fn test_no_method() {
    assert!(interfaces("
org.varlink.service {
  type Interface (name: string, types: Type[], methods: Method[])
  type Property (key: string, value: string)
}
")
        .is_err());
}

#[test]
fn test_type_no_args() {
    assert!(interfaces("foo.bar{ type I () F()->() }").is_ok());
}

#[test]
fn test_type_one_arg() {
    assert!(interfaces("foo.bar{ type I (b:bool) F()->() }").is_ok());
}

#[test]
fn test_type_one_array() {
    assert!(interfaces("foo.bar{ type I (b:bool[]) F()->() }").is_ok());
    assert!(interfaces("foo.bar{ type I (b:bool[ ]) F()->() }").is_err());
    assert!(interfaces("foo.bar{ type I (b:bool[1]) F()->() }").is_ok());
    assert!(interfaces("foo.bar{ type I (b:bool[ 1 ]) F()->() }").is_err());
    assert!(interfaces("foo.bar{ type I (b:bool[ 1 1 ]) F()->() }").is_err());
}

#[test]
fn test_method_struct_optional() {
    assert!(interfaces("foo.bar{ Foo(foo: (i: int64, b: bool)? )->()}").is_ok());
}

#[test]
fn test_method_struct_array_optional() {
    assert!(interfaces("foo.bar{ Foo(foo: (i: int64, b: bool)[]? )->()}").is_ok());
}

#[test]
fn test_method_struct_array_optional_wrong() {
    assert!(interfaces("foo.bar{ Foo(foo: (i: int64, b: bool)?[]) -> ()}").is_err());
}

#[test]
fn test_format() {
    let i = interfaces("foo.bar{ type I (b:bool[1]) F()->() }").unwrap();
    assert_eq!(i[0].to_string(), "foo.bar {
  type I (b: bool[1]);
  F() -> ();
}
");
}

#[test]
fn test_box() {
    let i = interfaces("foo.bar{ F()->(s: (a: bool)) }").unwrap();
    println!("{}", i[0]);
    assert_eq!(i[0].to_string(), "foo.bar {
  F() -> (s: (a: bool));
}
");
}
<|endoftext|>


<commit_before>use nom::IResult;
use std::str;

pub use common::Operator;
use select::*;
use insert::*;

#[derive(Clone, Debug, PartialEq)]
pub enum SqlQuery {
    Insert(InsertStatement),
    Select(SelectStatement),
}

#[derive(Clone, Debug, PartialEq)]
pub struct Column {
    pub name: String,
    pub table: Option<String>,
}

impl<'a> From<&'a str> for Column {
    fn from(c: &str) -> Column {
        match c.find(".") {
            None => {
                Column {
                    name: String::from(c),
                    table: None,
                }
            }
            Some(i) => {
                Column {
                    name: String::from(&c[i..]),
                    table: Some(String::from(&c[0..i - 1])),
                }
            }
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum ConditionBase {
    Field(Column),
    Literal(String),
    Placeholder,
}

#[derive(Clone, Debug, PartialEq)]
pub struct ConditionTree {
    pub operator: Operator,
    pub left: Option<Box<ConditionExpression>>,
    pub right: Option<Box<ConditionExpression>>,
}

#[derive(Clone, Debug, PartialEq)]
pub enum ConditionExpression {
    ComparisonOp(ConditionTree),
    LogicalOp(ConditionTree),
    Base(ConditionBase),
}

/// Parse sequence of SQL statements, divided by semicolons or newlines
// named!(pub query_list<&[u8], Vec<SqlQuery> >,
//    many1!(map_res!(selection, |s| { SqlQuery::Select(s) }))
// );

pub fn parse_query(input: &str) -> Result<SqlQuery, &str> {
    // we process all queries in lowercase to avoid having to deal with capitalization in the
    // parser.
    let q_bytes = String::from(input).into_bytes();

    // TODO(malte): appropriately pass through errors from nom
    match insertion(&q_bytes) {
        IResult::Done(_, o) => return Ok(SqlQuery::Insert(o)),
        _ => (),
    };

    match selection(&q_bytes) {
        IResult::Done(_, o) => return Ok(SqlQuery::Select(o)),
        _ => (),
    };

    Err("failed to parse query")
}
<commit_msg>Make `FieldExpression` public<commit_after>use nom::IResult;
use std::str;

pub use common::{FieldExpression, Operator};
use select::*;
use insert::*;

#[derive(Clone, Debug, PartialEq)]
pub enum SqlQuery {
    Insert(InsertStatement),
    Select(SelectStatement),
}

#[derive(Clone, Debug, PartialEq)]
pub struct Column {
    pub name: String,
    pub table: Option<String>,
}

impl<'a> From<&'a str> for Column {
    fn from(c: &str) -> Column {
        match c.find(".") {
            None => {
                Column {
                    name: String::from(c),
                    table: None,
                }
            }
            Some(i) => {
                Column {
                    name: String::from(&c[i..]),
                    table: Some(String::from(&c[0..i - 1])),
                }
            }
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum ConditionBase {
    Field(Column),
    Literal(String),
    Placeholder,
}

#[derive(Clone, Debug, PartialEq)]
pub struct ConditionTree {
    pub operator: Operator,
    pub left: Option<Box<ConditionExpression>>,
    pub right: Option<Box<ConditionExpression>>,
}

#[derive(Clone, Debug, PartialEq)]
pub enum ConditionExpression {
    ComparisonOp(ConditionTree),
    LogicalOp(ConditionTree),
    Base(ConditionBase),
}

/// Parse sequence of SQL statements, divided by semicolons or newlines
// named!(pub query_list<&[u8], Vec<SqlQuery> >,
//    many1!(map_res!(selection, |s| { SqlQuery::Select(s) }))
// );

pub fn parse_query(input: &str) -> Result<SqlQuery, &str> {
    // we process all queries in lowercase to avoid having to deal with capitalization in the
    // parser.
    let q_bytes = String::from(input).into_bytes();

    // TODO(malte): appropriately pass through errors from nom
    match insertion(&q_bytes) {
        IResult::Done(_, o) => return Ok(SqlQuery::Insert(o)),
        _ => (),
    };

    match selection(&q_bytes) {
        IResult::Done(_, o) => return Ok(SqlQuery::Select(o)),
        _ => (),
    };

    Err("failed to parse query")
}
<|endoftext|>


<commit_before>use std::str::from_utf8;
use nom::IResult;

#[derive(Debug,PartialEq,Eq)]
pub struct PosixHeader<'a> {
    pub name:     & 'a str,
    pub mode:     & 'a str,
    pub uid:      u64,
    pub gid:      u64,
    pub size:     u64,
    pub mtime:    u64,
    pub chksum:   & 'a str,
    pub typeflag: char, /* TODO: enum */
    pub linkname: & 'a str,
    pub ustar:    Option<UStarHeader<'a>>
}

#[derive(Debug,PartialEq,Eq)]
pub struct UStarHeader<'a> {
    pub magic:    & 'a str,
    pub version:  & 'a str,
    pub uname:    & 'a str,
    pub gname:    & 'a str,
    pub devmajor: & 'a str,
    pub devminor: & 'a str,
    pub prefix:   & 'a str,
}

#[derive(Debug,PartialEq,Eq)]
pub struct TarEntry<'a> {
    pub header:   PosixHeader<'a>,
    pub contents: & 'a str
}

/* TODO: validation */
fn str_to_u64(s: &str, base: u64) -> u64 {
    let mut u = 0;
    let mut f = 1;

    for c in s.chars().rev().skip_while(|&c| c == '\0') {
        u += f * ((c as u64) - ('0' as u64));
        f *= base;
    }

    u
}

pub fn octal_to_u64(o: &str) -> u64 {
    str_to_u64(o, 8)
}

pub fn decimal_to_u64(d: &str) -> u64 {
    str_to_u64(d, 10)
}

fn parse_ustar(i: &[u8]) -> IResult<&[u8], Option<UStarHeader>> {
    chain!(i,
        magic:    map_res!(take!(6),   from_utf8) ~
        version:  map_res!(take!(2),   from_utf8) ~
        uname:    map_res!(take!(32),  from_utf8) ~
        gname:    map_res!(take!(32),  from_utf8) ~
        devmajor: map_res!(take!(8),   from_utf8) ~
        devminor: map_res!(take!(8),   from_utf8) ~
        prefix:   map_res!(take!(155), from_utf8),
        ||{
            match magic {
                "ustar" => Some(UStarHeader {
                    magic:    magic,
                    version:  version,
                    uname:    uname,
                    gname:    gname,
                    devmajor: devmajor,
                    devminor: devminor,
                    prefix:   prefix
                }),
                _ => None,
            }
        }
    )
}

fn parse_header(i: &[u8]) -> IResult<&[u8], PosixHeader> {
    chain!(i,
        name:     map_res!(take!(100), from_utf8) ~
        mode:     map_res!(take!(8),   from_utf8) ~
        uid:      map_res!(take!(8),   from_utf8) ~
        gid:      map_res!(take!(8),   from_utf8) ~
        size:     map_res!(take!(12),  from_utf8) ~
        mtime:    map_res!(take!(12),  from_utf8) ~
        chksum:   map_res!(take!(8),   from_utf8) ~
        typeflag: take!(1)                        ~
        linkname: map_res!(take!(100), from_utf8) ~
        ustar:    parse_ustar                     ~
        take!(12), /* padding to 512 */
        ||{
            PosixHeader {
                name:     name,
                mode:     mode,
                uid:      decimal_to_u64(uid),
                gid:      decimal_to_u64(gid),
                size:     octal_to_u64(size),
                mtime:    octal_to_u64(mtime), /* TODO: u64 */
                chksum:   chksum,
                typeflag: typeflag[0] as char,
                linkname: linkname,
                ustar:    ustar
            }
        }
    )
}

fn parse_contents(i: &[u8], size: u64) -> IResult<&[u8], &str> {
    let trailing = size % 512;
    let padding = match trailing {
        0 => 0,
        t => 512 - t
    };
    chain!(i,
        contents: map_res!(take!(size as usize), from_utf8) ~
        take!(padding as usize),
        ||{
            contents
        }
    )
}

macro_rules! apply (
 ($i:expr, $fun:expr, $arg:expr ) => ( $fun( $i, $arg ) );
);

fn parse_entry(i: &[u8]) -> IResult<&[u8], TarEntry> {
    chain!(i,
        header:   parse_header ~
        contents: apply!(parse_contents, header.size),
        ||{
            TarEntry {
                header: header,
                contents: contents
            }
        }
    )
}

pub fn parse_tar(i: &[u8]) -> IResult<&[u8], Vec<TarEntry>> {
    many0!(i, parse_entry)
}

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

    #[test]
    fn octal_to_u32_test() {
        match octal_to_u32("756") {
            494 => {},
            o => panic!("octal_to_u32 failed, expected 494 but got {}", o)
        }
        match octal_to_u32("") {
            0 => {},
            o => panic!("octal_to_u32 failed, expected 0 but got {}", o)
        }
    }

    #[test]
    fn decimal_to_u32_test() {
        match decimal_to_u32("756") {
            756 => {},
            d => panic!("decimal_to_u32 failed, expected 756 but got {}", d)
        }
        match decimal_to_u32("") {
            0 => {},
            d => panic!("decimal_to_u32 failed, expected 0 but got {}", d)
        }
    }
}
<commit_msg>use upstream nom apply! macro<commit_after>use std::str::from_utf8;
use nom::IResult;

#[derive(Debug,PartialEq,Eq)]
pub struct PosixHeader<'a> {
    pub name:     & 'a str,
    pub mode:     & 'a str,
    pub uid:      u64,
    pub gid:      u64,
    pub size:     u64,
    pub mtime:    u64,
    pub chksum:   & 'a str,
    pub typeflag: char, /* TODO: enum */
    pub linkname: & 'a str,
    pub ustar:    Option<UStarHeader<'a>>
}

#[derive(Debug,PartialEq,Eq)]
pub struct UStarHeader<'a> {
    pub magic:    & 'a str,
    pub version:  & 'a str,
    pub uname:    & 'a str,
    pub gname:    & 'a str,
    pub devmajor: & 'a str,
    pub devminor: & 'a str,
    pub prefix:   & 'a str,
}

#[derive(Debug,PartialEq,Eq)]
pub struct TarEntry<'a> {
    pub header:   PosixHeader<'a>,
    pub contents: & 'a str
}

/* TODO: validation */
fn str_to_u64(s: &str, base: u64) -> u64 {
    let mut u = 0;
    let mut f = 1;

    for c in s.chars().rev().skip_while(|&c| c == '\0') {
        u += f * ((c as u64) - ('0' as u64));
        f *= base;
    }

    u
}

pub fn octal_to_u64(o: &str) -> u64 {
    str_to_u64(o, 8)
}

pub fn decimal_to_u64(d: &str) -> u64 {
    str_to_u64(d, 10)
}

fn parse_ustar(i: &[u8]) -> IResult<&[u8], Option<UStarHeader>> {
    chain!(i,
        magic:    map_res!(take!(6),   from_utf8) ~
        version:  map_res!(take!(2),   from_utf8) ~
        uname:    map_res!(take!(32),  from_utf8) ~
        gname:    map_res!(take!(32),  from_utf8) ~
        devmajor: map_res!(take!(8),   from_utf8) ~
        devminor: map_res!(take!(8),   from_utf8) ~
        prefix:   map_res!(take!(155), from_utf8),
        ||{
            match magic {
                "ustar" => Some(UStarHeader {
                    magic:    magic,
                    version:  version,
                    uname:    uname,
                    gname:    gname,
                    devmajor: devmajor,
                    devminor: devminor,
                    prefix:   prefix
                }),
                _ => None,
            }
        }
    )
}

fn parse_header(i: &[u8]) -> IResult<&[u8], PosixHeader> {
    chain!(i,
        name:     map_res!(take!(100), from_utf8) ~
        mode:     map_res!(take!(8),   from_utf8) ~
        uid:      map_res!(take!(8),   from_utf8) ~
        gid:      map_res!(take!(8),   from_utf8) ~
        size:     map_res!(take!(12),  from_utf8) ~
        mtime:    map_res!(take!(12),  from_utf8) ~
        chksum:   map_res!(take!(8),   from_utf8) ~
        typeflag: take!(1)                        ~
        linkname: map_res!(take!(100), from_utf8) ~
        ustar:    parse_ustar                     ~
        take!(12), /* padding to 512 */
        ||{
            PosixHeader {
                name:     name,
                mode:     mode,
                uid:      decimal_to_u64(uid),
                gid:      decimal_to_u64(gid),
                size:     octal_to_u64(size),
                mtime:    octal_to_u64(mtime), /* TODO: u64 */
                chksum:   chksum,
                typeflag: typeflag[0] as char,
                linkname: linkname,
                ustar:    ustar
            }
        }
    )
}

fn parse_contents(i: &[u8], size: u64) -> IResult<&[u8], &str> {
    let trailing = size % 512;
    let padding = match trailing {
        0 => 0,
        t => 512 - t
    };
    chain!(i,
        contents: map_res!(take!(size as usize), from_utf8) ~
        take!(padding as usize),
        ||{
            contents
        }
    )
}

fn parse_entry(i: &[u8]) -> IResult<&[u8], TarEntry> {
    chain!(i,
        header:   parse_header ~
        contents: apply!(parse_contents, header.size),
        ||{
            TarEntry {
                header: header,
                contents: contents
            }
        }
    )
}

pub fn parse_tar(i: &[u8]) -> IResult<&[u8], Vec<TarEntry>> {
    many0!(i, parse_entry)
}

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

    #[test]
    fn octal_to_u32_test() {
        match octal_to_u32("756") {
            494 => {},
            o => panic!("octal_to_u32 failed, expected 494 but got {}", o)
        }
        match octal_to_u32("") {
            0 => {},
            o => panic!("octal_to_u32 failed, expected 0 but got {}", o)
        }
    }

    #[test]
    fn decimal_to_u32_test() {
        match decimal_to_u32("756") {
            756 => {},
            d => panic!("decimal_to_u32 failed, expected 756 but got {}", d)
        }
        match decimal_to_u32("") {
            0 => {},
            d => panic!("decimal_to_u32 failed, expected 0 but got {}", d)
        }
    }
}
<|endoftext|>


<commit_before>
/*
 * Interpreter for Basic C like language
 * Parser Module
 */
use std::string::String;
use lexer::*;
use ast::*;

pub struct Parser {
    pub tokenStream: TokenStream,  // TokenStream
    pub token: Token,              // Current token
    pub span: Option<Span>,        // Span of current token
    pub tokenCount: usize,         // Total token count of TokenStream
    pub currentIndex: usize        // Current token index of TokenStream
}

impl Parser {
    pub fn new(_tokenStream: TokenStream, _span: Option<Span>) -> Parser {
        let _tokenCount = _tokenStream.tokens.len();
        let _currentToken = _tokenStream.currentToken();

        Parser {
            tokenStream: _tokenStream,
            token: _currentToken,
            span: None,
            tokenCount: _tokenCount,
            currentIndex: 0
        }
    }

    pub fn tokenToString(&self) -> String {
        self.token.tokenType.toString()
    }

    fn unexpectedToken(&self, c: char) { // TODO: Make more user friendly errors. It is temporary.
        panic!("Unexpected token: {:?}", c);
    }

    fn eatToken(&mut self, expectedToken: &TokenType) -> bool {
        let isExist = self.checkToken(expectedToken);

        if isExist {
            let result = self.advanceToken();
            return true;
        }

        return false;
    }

    fn checkToken(&mut self, expectedToken: &TokenType) -> bool {
        self.token.tokenType == *expectedToken
    }

    fn advanceToken(&mut self) -> bool {
        self.currentIndex += 1;

        if self.currentIndex == self.tokenCount {
            return false;
        }

        self.token = self.tokenStream.nextToken();
        return true;
    }

    pub fn parse(&mut self) -> Expr {

        match self.token.tokenType {
            TokenType::Keyword(String::from("int")) => Expr {span: None, node: self.parseInteger()},
            TokenType::Keyword(String::from("string")) => Expr {span: None, node: self.parseString()},
            TokenType::Keyword(String::from("print")) => Expr {span: None, node: self.parsePrint()},
            _ => unimplemented!()
        }
    }

    fn parseInteger(&self) {
        unimplemented!()
    }

    fn parseString(&self) {
        unimplemented!()
    }

    fn parsePrint(&self) {
        unimplemented!()
    }
}
<commit_msg>Part of parseInteger function Added.<commit_after>
/*
 * Interpreter for Basic C like language
 * Parser Module
 */
use std::string::String;
use lexer::*;
use ast::*;

pub struct Parser {
    pub tokenStream: TokenStream,  // TokenStream
    pub token: Token,              // Current token
    pub span: Option<Span>,        // Span of current token
    pub tokenCount: usize,         // Total token count of TokenStream
    pub currentIndex: usize        // Current token index of TokenStream
}

impl Parser {
    pub fn new(mut _tokenStream: TokenStream, _span: Option<Span>) -> Parser {
        let _tokenCount = _tokenStream.tokens.len();
        let _currentToken = _tokenStream.currentToken();

        Parser {
            tokenStream: _tokenStream,
            token: _currentToken,
            span: None,
            tokenCount: _tokenCount,
            currentIndex: 0
        }
    }

    pub fn tokenToString(&self) -> String {
        self.token.tokenType.toString()
    }

    fn unexpectedToken(&self, tt: TokenType) { // TODO: Make more user friendly errors. It is temporary.
        panic!("Unexpected token found. Found: {:?}", tt);
    }

    fn eatToken(&mut self, expectedToken: TokenType) -> bool {
        let isExist = self.checkToken(expectedToken);

        if isExist {
            let result = self.advanceToken();
            return true;
        }

        return false;
    }

    fn checkToken(&mut self, expectedToken: &TokenType) -> bool {
        self.token.tokenType == *expectedToken
    }

    fn advanceToken(&mut self) -> bool {
        self.currentIndex += 1;

        if self.currentIndex == self.tokenCount {
            return false;
        }

        self.token = self.tokenStream.nextToken();
        return true;
    }

    pub fn parse(&mut self) -> Expr {

        match self.token.tokenType {
            TokenType::Keyword(ref x) if x == "int" => Expr {span: None, node: self.parseInteger()},
            TokenType::Keyword(ref x) if x == "string" => Expr {span: None, node: self.parseString()},
            TokenType::Keyword(ref x) if x == "print" => Expr {span: None, node: self.parsePrint()},
            _ => unimplemented!()
        }
    }

    fn parseInteger(&self) -> Expr_ {
        let identifier : String;
        let number : String;
        let mut expr : Expr;

        if self.eatToken(TokenType::Identifier) {
            match self.token.tokenType {
                TokenType::Identifier(ref x) => identifier = x
            };

            if self.eatToken(TokenType::Equals) {
                if self.eatToken(TokenType::Number) {
                    match self.token.tokenType {
                        TokenType::Number(ref y) => {
                            number = y;
                            expr = Expr_::Assign {Identifier, Expr {span None, node: Expr_::Variable {number}}};
                        };
                    };

                }
            } else {
                self.unexpectedToken(TokenType::Equals);
            }
        } else {
            self.unexpectedToken(TokenType::Identifier);
        }
    }

    fn parseString(&self) -> Expr_ {
        unimplemented!()
    }

    fn parsePrint(&self) -> Expr_ {
        unimplemented!()
    }

    fn expectSemicolon(&self) {
        if self.eatToken(TokenType::Semicolon) {
            self.unexpectedToken(TokenType::Semicolon);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::{
    conversion::{apivec::ApiVec, AnalysisPhase, ConvertError},
    types::QualifiedName,
};
use itertools::Itertools;
use quote::ToTokens;
use std::collections::HashMap;
use std::iter::once;
use syn::{Token, Type};

/// Map from QualifiedName to original C++ name. Original C++ name does not
/// include the namespace; this can be assumed to be the same as the namespace
/// in the QualifiedName.
pub(crate) type CppNameMap = HashMap<QualifiedName, String>;

pub(crate) fn original_name_map_from_apis<T: AnalysisPhase>(apis: &ApiVec<T>) -> CppNameMap {
    apis.iter()
        .filter_map(|api| {
            api.cpp_name()
                .as_ref()
                .map(|cpp_name| (api.name().clone(), cpp_name.clone()))
        })
        .collect()
}

pub(crate) fn namespaced_name_using_original_name_map(
    qual_name: &QualifiedName,
    original_name_map: &CppNameMap,
) -> String {
    if let Some(cpp_name) = original_name_map.get(qual_name) {
        qual_name
            .get_namespace()
            .iter()
            .chain(once(cpp_name))
            .join("::")
    } else {
        qual_name.to_cpp_name()
    }
}

pub(crate) fn final_ident_using_original_name_map(
    qual_name: &QualifiedName,
    original_name_map: &CppNameMap,
) -> String {
    match original_name_map.get(qual_name) {
        Some(original_name) => {
            // If we have an original name, this may be a nested struct
            // (e.g. A::B). The final ident here is just 'B' so...
            original_name
                .rsplit_once("::")
                .map_or(original_name.clone(), |(_, original_name)| {
                    original_name.to_string()
                })
        }
        None => qual_name.get_final_cpp_item(),
    }
}

pub(crate) fn type_to_cpp(ty: &Type, cpp_name_map: &CppNameMap) -> Result<String, ConvertError> {
    match ty {
        Type::Path(typ) => {
            // If this is a std::unique_ptr we do need to pass
            // its argument through.
            let qual_name = QualifiedName::from_type_path(typ);
            let root = namespaced_name_using_original_name_map(&qual_name, cpp_name_map);
            if root == "Pin" {
                // Strip all Pins from type names when describing them in C++.
                let inner_type = &typ.path.segments.last().unwrap().arguments;
                if let syn::PathArguments::AngleBracketed(ab) = inner_type {
                    let inner_type = ab.args.iter().next().unwrap();
                    if let syn::GenericArgument::Type(gat) = inner_type {
                        return type_to_cpp(gat, cpp_name_map);
                    }
                }
                panic!("Pin<...> didn't contain the inner types we expected");
            }
            let suffix = match &typ.path.segments.last().unwrap().arguments {
                syn::PathArguments::AngleBracketed(ab) => {
                    let results: Result<Vec<_>, _> = ab
                        .args
                        .iter()
                        .map(|x| match x {
                            syn::GenericArgument::Type(gat) => type_to_cpp(gat, cpp_name_map),
                            _ => Ok("".to_string()),
                        })
                        .collect();
                    Some(results?.join(", "))
                }
                syn::PathArguments::None | syn::PathArguments::Parenthesized(_) => None,
            };
            match suffix {
                None => Ok(root),
                Some(suffix) => Ok(format!("{}<{}>", root, suffix)),
            }
        }
        Type::Reference(typr) => Ok(format!(
            "{}{}&",
            get_mut_string(&typr.mutability),
            type_to_cpp(typr.elem.as_ref(), cpp_name_map)?
        )),
        Type::Ptr(typp) => Ok(format!(
            "{}{}*",
            get_mut_string(&typp.mutability),
            type_to_cpp(typp.elem.as_ref(), cpp_name_map)?
        )),
        Type::Array(_)
        | Type::BareFn(_)
        | Type::Group(_)
        | Type::ImplTrait(_)
        | Type::Infer(_)
        | Type::Macro(_)
        | Type::Never(_)
        | Type::Paren(_)
        | Type::Slice(_)
        | Type::TraitObject(_)
        | Type::Tuple(_)
        | Type::Verbatim(_) => Err(ConvertError::UnsupportedType(
            ty.to_token_stream().to_string(),
        )),
        _ => Err(ConvertError::UnknownType(ty.to_token_stream().to_string())),
    }
}

fn get_mut_string(mutability: &Option<Token![mut]>) -> &'static str {
    match mutability {
        None => "const ",
        Some(_) => "",
    }
}
<commit_msg>Fix &str within generated C++.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::{
    conversion::{apivec::ApiVec, AnalysisPhase, ConvertError},
    types::QualifiedName,
};
use itertools::Itertools;
use quote::ToTokens;
use std::collections::HashMap;
use std::iter::once;
use syn::{Token, Type};

/// Map from QualifiedName to original C++ name. Original C++ name does not
/// include the namespace; this can be assumed to be the same as the namespace
/// in the QualifiedName.
pub(crate) type CppNameMap = HashMap<QualifiedName, String>;

pub(crate) fn original_name_map_from_apis<T: AnalysisPhase>(apis: &ApiVec<T>) -> CppNameMap {
    apis.iter()
        .filter_map(|api| {
            api.cpp_name()
                .as_ref()
                .map(|cpp_name| (api.name().clone(), cpp_name.clone()))
        })
        .collect()
}

pub(crate) fn namespaced_name_using_original_name_map(
    qual_name: &QualifiedName,
    original_name_map: &CppNameMap,
) -> String {
    if let Some(cpp_name) = original_name_map.get(qual_name) {
        qual_name
            .get_namespace()
            .iter()
            .chain(once(cpp_name))
            .join("::")
    } else {
        qual_name.to_cpp_name()
    }
}

pub(crate) fn final_ident_using_original_name_map(
    qual_name: &QualifiedName,
    original_name_map: &CppNameMap,
) -> String {
    match original_name_map.get(qual_name) {
        Some(original_name) => {
            // If we have an original name, this may be a nested struct
            // (e.g. A::B). The final ident here is just 'B' so...
            original_name
                .rsplit_once("::")
                .map_or(original_name.clone(), |(_, original_name)| {
                    original_name.to_string()
                })
        }
        None => qual_name.get_final_cpp_item(),
    }
}

pub(crate) fn type_to_cpp(ty: &Type, cpp_name_map: &CppNameMap) -> Result<String, ConvertError> {
    match ty {
        Type::Path(typ) => {
            // If this is a std::unique_ptr we do need to pass
            // its argument through.
            let qual_name = QualifiedName::from_type_path(typ);
            let root = namespaced_name_using_original_name_map(&qual_name, cpp_name_map);
            if root == "Pin" {
                // Strip all Pins from type names when describing them in C++.
                let inner_type = &typ.path.segments.last().unwrap().arguments;
                if let syn::PathArguments::AngleBracketed(ab) = inner_type {
                    let inner_type = ab.args.iter().next().unwrap();
                    if let syn::GenericArgument::Type(gat) = inner_type {
                        return type_to_cpp(gat, cpp_name_map);
                    }
                }
                panic!("Pin<...> didn't contain the inner types we expected");
            }
            let suffix = match &typ.path.segments.last().unwrap().arguments {
                syn::PathArguments::AngleBracketed(ab) => {
                    let results: Result<Vec<_>, _> = ab
                        .args
                        .iter()
                        .map(|x| match x {
                            syn::GenericArgument::Type(gat) => type_to_cpp(gat, cpp_name_map),
                            _ => Ok("".to_string()),
                        })
                        .collect();
                    Some(results?.join(", "))
                }
                syn::PathArguments::None | syn::PathArguments::Parenthesized(_) => None,
            };
            match suffix {
                None => Ok(root),
                Some(suffix) => Ok(format!("{}<{}>", root, suffix)),
            }
        }
        Type::Reference(typr) => match &*typr.elem {
            Type::Path(typ) if typ.path.is_ident("str") => Ok("rust::Str".into()),
            _ => Ok(format!(
                "{}{}&",
                get_mut_string(&typr.mutability),
                type_to_cpp(typr.elem.as_ref(), cpp_name_map)?
            )),
        },
        Type::Ptr(typp) => Ok(format!(
            "{}{}*",
            get_mut_string(&typp.mutability),
            type_to_cpp(typp.elem.as_ref(), cpp_name_map)?
        )),
        Type::Array(_)
        | Type::BareFn(_)
        | Type::Group(_)
        | Type::ImplTrait(_)
        | Type::Infer(_)
        | Type::Macro(_)
        | Type::Never(_)
        | Type::Paren(_)
        | Type::Slice(_)
        | Type::TraitObject(_)
        | Type::Tuple(_)
        | Type::Verbatim(_) => Err(ConvertError::UnsupportedType(
            ty.to_token_stream().to_string(),
        )),
        _ => Err(ConvertError::UnknownType(ty.to_token_stream().to_string())),
    }
}

fn get_mut_string(mutability: &Option<Token![mut]>) -> &'static str {
    match mutability {
        None => "const ",
        Some(_) => "",
    }
}
<|endoftext|>


<commit_before>use std::env;
use ansi_term::Colour::{Cyan, Blue, Red};
use ansi_term::ANSIStrings;
use git2;
use git2::{Repository, StatusOptions};
use regex::Regex;
use clap::{ArgMatches, App, SubCommand};

fn first_char(s: &str) -> String {
  let chars: Vec<char> = s.chars().collect();
  match chars.len() {
    0 => String::from(""),
    _ => chars[0].to_string(),
  }
}

fn fmt_current_path(cwd: &str) -> String {
  let friendly_path = if let Some(path) = env::home_dir() {
    Regex::new(path.to_str().unwrap()).unwrap().replace(cwd, "~").to_string()
  } else {
    String::from("")
  };

  let mut friendly_path_split: Vec<&str> = friendly_path.split('/').collect();
  let current_dir = friendly_path_split.pop().unwrap().to_string();
  let mut short_path: Vec<String> = friendly_path_split.iter().map(|s| first_char(s)).collect();
  short_path.push(current_dir);
  short_path.join("/")
}

fn repo_status(r: &Repository) -> Option<String> {
  let mut opts = StatusOptions::new();
  opts.include_untracked(true);
  let head = match r.head() {
    Ok(head) => head,
    Err(_) => return None
  };

  let shorthand = Cyan.paint(head.shorthand().unwrap().to_string());
  let statuses = match r.statuses(Some(&mut opts)) {
    Ok(statuses) => statuses,
    Err(_) => return None
  };

  let mut is_dirty = false;

  for entry in statuses.iter().filter(
    |e| e.status() != git2::STATUS_CURRENT,
  ) {
    is_dirty = match entry.status() {
      s if s.contains(git2::STATUS_INDEX_NEW) => true,
      s if s.contains(git2::STATUS_INDEX_MODIFIED) => true,
      s if s.contains(git2::STATUS_INDEX_DELETED) => true,
      s if s.contains(git2::STATUS_INDEX_RENAMED) => true,
      s if s.contains(git2::STATUS_INDEX_TYPECHANGE) => true,
      s if s.contains(git2::STATUS_WT_NEW) => true,
      s if s.contains(git2::STATUS_WT_MODIFIED) => true,
      s if s.contains(git2::STATUS_WT_DELETED) => true,
      s if s.contains(git2::STATUS_WT_RENAMED) => true,
      s if s.contains(git2::STATUS_WT_TYPECHANGE) => true,
      _ => false,
    };

    if is_dirty { break }
  }
  let mut out = vec![shorthand];
  if is_dirty {
    out.push(Red.bold().paint("*"));
  }

  Some(ANSIStrings(&out).to_string())
}

pub fn display(_sub: &ArgMatches) {
  let my_path = env::current_dir().unwrap();
  let display_path = Blue.paint(fmt_current_path(my_path.to_str().unwrap()));

  let branch = match Repository::open(my_path) {
    Ok(repo) => repo_status(&repo),
    Err(_e) => None,
  };
  let display_branch = Cyan.paint(branch.unwrap_or_default());

  println!("");
  println!("{} {}", display_path, display_branch);
}

pub fn cli_arguments<'a>() -> App<'a, 'a> {
  SubCommand::with_name("precmd")
}
<commit_msg>Use `Repository::discover` instead of `open`<commit_after>use std::env;
use ansi_term::Colour::{Cyan, Blue, Red};
use ansi_term::ANSIStrings;
use git2::{self, Repository, StatusOptions};
use regex::Regex;
use clap::{ArgMatches, App, SubCommand};

fn first_char(s: &str) -> String {
  let chars: Vec<char> = s.chars().collect();
  match chars.len() {
    0 => String::from(""),
    _ => chars[0].to_string(),
  }
}

fn fmt_current_path(cwd: &str) -> String {
  let friendly_path = if let Some(path) = env::home_dir() {
    Regex::new(path.to_str().unwrap()).unwrap().replace(cwd, "~").to_string()
  } else {
    String::from("")
  };

  let mut friendly_path_split: Vec<&str> = friendly_path.split('/').collect();
  let current_dir = friendly_path_split.pop().unwrap().to_string();
  let mut short_path: Vec<String> = friendly_path_split.iter().map(|s| first_char(s)).collect();
  short_path.push(current_dir);
  short_path.join("/")
}

fn repo_status(r: &Repository) -> Option<String> {
  let mut opts = StatusOptions::new();
  opts.include_untracked(true);
  let head = match r.head() {
    Ok(head) => head,
    Err(_) => return None
  };

  let shorthand = Cyan.paint(head.shorthand().unwrap().to_string());
  let statuses = match r.statuses(Some(&mut opts)) {
    Ok(statuses) => statuses,
    Err(_) => return None
  };

  let mut is_dirty = false;

  for entry in statuses.iter().filter(
    |e| e.status() != git2::STATUS_CURRENT,
  ) {
    is_dirty = match entry.status() {
      s if s.contains(git2::STATUS_INDEX_NEW) => true,
      s if s.contains(git2::STATUS_INDEX_MODIFIED) => true,
      s if s.contains(git2::STATUS_INDEX_DELETED) => true,
      s if s.contains(git2::STATUS_INDEX_RENAMED) => true,
      s if s.contains(git2::STATUS_INDEX_TYPECHANGE) => true,
      s if s.contains(git2::STATUS_WT_NEW) => true,
      s if s.contains(git2::STATUS_WT_MODIFIED) => true,
      s if s.contains(git2::STATUS_WT_DELETED) => true,
      s if s.contains(git2::STATUS_WT_RENAMED) => true,
      s if s.contains(git2::STATUS_WT_TYPECHANGE) => true,
      _ => false,
    };

    if is_dirty { break }
  }
  let mut out = vec![shorthand];
  if is_dirty {
    out.push(Red.bold().paint("*"));
  }

  Some(ANSIStrings(&out).to_string())
}

pub fn display(_sub: &ArgMatches) {
  let my_path = env::current_dir().unwrap();
  let display_path = Blue.paint(fmt_current_path(my_path.to_str().unwrap()));

  let branch = match Repository::discover(my_path) {
    Ok(repo) => repo_status(&repo),
    Err(_e) => None,
  };
  let display_branch = Cyan.paint(branch.unwrap_or_default());

  println!("");
  println!("{} {}", display_path, display_branch);
}

pub fn cli_arguments<'a>() -> App<'a, 'a> {
  SubCommand::with_name("precmd")
}
<|endoftext|>


<commit_before>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;

use aho_corasick::{Automaton, AcAutomaton, FullAcAutomaton};
use memchr::memchr;

/// A prefix extracted from a compiled regular expression.
///
/// A regex prefix is a set of literal strings that *must* be matched at the
/// beginning of a regex in order for the entire regex to match.
///
/// There are a variety of ways to efficiently scan the search text for a
/// prefix. Currently, there are three implemented:
///
/// 1. The prefix is a single byte. Just use memchr.
/// 2. If the prefix is a set of two or more single byte prefixes, then
///    a single sparse map is created. Checking if there is a match is a lookup
///    in this map for each byte in the search text.
/// 3. In all other cases, build an Aho-Corasick automaton.
///
/// It's possible that there's room here for other substring algorithms,
/// such as Boyer-Moore for single-set prefixes greater than 1, or Rabin-Karp
/// for small sets of same-length prefixes.
#[derive(Clone)]
pub enum Prefix {
    /// No prefixes. (Never advances through the input.)
    Empty,
    /// A single byte prefix.
    Byte(u8),
    /// A set of two or more single byte prefixes.
    /// This could be reduced to a bitset, which would use only 8 bytes,
    /// but I don't think we care.
    Bytes {
        chars: Vec<u8>,
        sparse: Vec<bool>,
    },
    Single(SingleSearch),
    /// A full Aho-Corasick DFA automaton.
    Automaton(FullAcAutomaton<String>),
}

impl Prefix {
    /// Create a new prefix matching machine.
    pub fn new(mut pfxs: Vec<String>) -> Prefix {
        if pfxs.len() == 0 || pfxs[0].len() == 0 {
            Prefix::Empty
        } else if pfxs.len() == 1 && pfxs[0].len() == 1 {
            Prefix::Byte(pfxs[0].as_bytes()[0])
        } else if pfxs.len() >= 2 && pfxs.iter().all(|s| s.len() == 1) {
            let mut set = vec![false; 256];
            let mut chars = vec![];
            for p in pfxs {
                chars.push(p.as_bytes()[0]);
                set[p.as_bytes()[0] as usize] = true;
            }
            Prefix::Bytes { chars: chars, sparse: set }
        } else if pfxs.len() == 1 {
            Prefix::Single(SingleSearch::new(pfxs.pop().unwrap()))
        } else {
            Prefix::Automaton(AcAutomaton::new(pfxs).into_full())
        }
    }

    /// Find the position of a prefix in `haystack` if it exists.
    ///
    /// In the matching engines, we only actually need the starting index
    /// because the prefix is used to only skip ahead---the matching engine
    /// still needs to run over the prefix input. However, we return the ending
    /// location as well in case the prefix corresponds to the entire regex,
    /// in which case, you need the end of the match.
    pub fn find(&self, haystack: &str) -> Option<(usize, usize)> {
        use self::Prefix::*;
        match *self {
            Empty => Some((0, 0)),
            Byte(b) => memchr(b, haystack.as_bytes()).map(|i| (i, i+1)),
            Bytes { ref sparse, .. } => {
                find_singles(sparse, haystack.as_bytes())
            }
            Single(ref searcher) => {
                searcher.find(haystack).map(|i| (i, i + searcher.pat.len()))
            }
            Automaton(ref aut) => {
                aut.find(haystack).next().map(|m| (m.start, m.end))
            }
        }
    }

    /// Returns true iff this prefix is empty.
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns the number of prefixes in this machine.
    pub fn len(&self) -> usize {
        match *self {
            Prefix::Empty => 0,
            Prefix::Byte(_) => 1,
            Prefix::Bytes { ref chars, .. } => chars.len(),
            Prefix::Single(_) => 1,
            Prefix::Automaton(ref aut) => aut.len(),
        }
    }

    /// Returns true iff the prefix match preserves priority.
    ///
    /// For example, given the alternation `ab|a` and the target string `ab`,
    /// does the prefix machine guarantee that `ab` will match? (A full
    /// Aho-Corasick automaton does not!)
    pub fn preserves_priority(&self) -> bool {
        match *self {
            Prefix::Empty => true,
            Prefix::Byte(_) => true,
            Prefix::Bytes{..} => true,
            Prefix::Single(_) => true,
            Prefix::Automaton(ref aut) => {
                // Okay, so the automaton can respect priority in one
                // particular case: when every pattern is of the same length.
                // The trick is that the automaton will report the leftmost
                // match, which in this case, corresponds to the correct
                // match for the regex engine. If any other alternate matches
                // at the same position, then they must be exactly equivalent.

                // Guaranteed at least one prefix by construction, so use
                // that for the length.
                aut.patterns().iter().all(|p| p.len() == aut.pattern(0).len())
            }
        }
    }

    /// Returns all of the prefixes participating in this machine.
    ///
    /// For debug/testing only! (It allocates.)
    #[allow(dead_code)]
    pub fn prefixes(&self) -> Vec<String> {
        match *self {
            Prefix::Empty => vec![],
            Prefix::Byte(b) => vec![format!("{}", b as char)],
            Prefix::Bytes { ref chars, .. } => {
                chars.iter().map(|&b| format!("{}", b as char)).collect()
            }
            Prefix::Single(ref searcher) => vec![searcher.pat.clone()],
            Prefix::Automaton(ref aut) => aut.patterns().to_vec(),
        }
    }
}

/// Provides an implementation of fast subtring search.
///
/// In particular, this uses Boyer-Moore-Horspool with Tim Raita's twist:
/// https://en.wikipedia.org/wiki/Raita_Algorithm
///
/// I'm skeptical of the utility here, because benchmarks suggest that it is
/// difficult to beat Aho-Corasick on random text. Namely, both algorithms are
/// dominated by the performance of `memchr` for the leading byte prefix.
/// With that said, BMH does seem to surpass AC when the search text gets
/// longer (see the `easy0_1MB` vs. `easy1_1MB` benchmarks).
///
/// More analysis needs to be done to test this on different search texts.
#[derive(Clone, Debug)]
struct SingleSearch {
    pat: String,
    shift: Vec<usize>,
}

impl SingleSearch {
    fn new(pat: String) -> SingleSearch {
        assert!(pat.len() >= 1);
        let mut shift = vec![pat.len(); 256];
        for i in 0..(pat.len() - 1) {
            shift[pat.as_bytes()[i] as usize] = pat.len() - i - 1;
        }
        SingleSearch {
            pat: pat,
            shift: shift,
        }
    }

    fn find(&self, haystack: &str) -> Option<usize> {
        let pat = self.pat.as_bytes();
        let haystack = haystack.as_bytes();
        if haystack.len() < pat.len() {
            return None;
        }
        let mut i = match memchr(pat[0], haystack) {
            None => return None,
            Some(i) => i,
        };
        while i <= haystack.len() - pat.len() {
            let b = haystack[i + pat.len() - 1];
            if b == pat[pat.len() - 1]
               && haystack[i] == pat[0]
               && haystack[i + (pat.len() / 2)] == pat[pat.len() / 2]
               && pat == &haystack[i..i + pat.len()] {
                return Some(i);
            }
            i += self.shift[b as usize];
        }
        None
    }
}

/// A quick scan for multiple single byte prefixes using a sparse map.
fn find_singles(sparse: &[bool], haystack: &[u8]) -> Option<(usize, usize)> {
    // TODO: Improve this with ideas found in jetscii crate.
    for (hi, &b) in haystack.iter().enumerate() {
        if sparse[b as usize] {
            return Some((hi, hi+1));
        }
    }
    None
}

impl fmt::Debug for Prefix {
    #[allow(deprecated)] // connect => join in 1.3
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Prefix::Empty => write!(f, "Empty"),
            Prefix::Byte(b) => write!(f, "{:?}", b as char),
            Prefix::Bytes { ref chars, .. } => {
                let chars: Vec<String> =
                    chars.iter()
                         .map(|&c| format!("{:?}", c as char))
                         .collect();
                write!(f, "{}", chars.connect(", "))
            }
            Prefix::Single(ref searcher) => write!(f, "{:?}", searcher),
            Prefix::Automaton(ref aut) => write!(f, "{:?}", aut),
        }
    }
}
<commit_msg>Revert "Avoid repeated memchr in SingleSearch"<commit_after>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;

use aho_corasick::{Automaton, AcAutomaton, FullAcAutomaton};
use memchr::memchr;

/// A prefix extracted from a compiled regular expression.
///
/// A regex prefix is a set of literal strings that *must* be matched at the
/// beginning of a regex in order for the entire regex to match.
///
/// There are a variety of ways to efficiently scan the search text for a
/// prefix. Currently, there are three implemented:
///
/// 1. The prefix is a single byte. Just use memchr.
/// 2. If the prefix is a set of two or more single byte prefixes, then
///    a single sparse map is created. Checking if there is a match is a lookup
///    in this map for each byte in the search text.
/// 3. In all other cases, build an Aho-Corasick automaton.
///
/// It's possible that there's room here for other substring algorithms,
/// such as Boyer-Moore for single-set prefixes greater than 1, or Rabin-Karp
/// for small sets of same-length prefixes.
#[derive(Clone)]
pub enum Prefix {
    /// No prefixes. (Never advances through the input.)
    Empty,
    /// A single byte prefix.
    Byte(u8),
    /// A set of two or more single byte prefixes.
    /// This could be reduced to a bitset, which would use only 8 bytes,
    /// but I don't think we care.
    Bytes {
        chars: Vec<u8>,
        sparse: Vec<bool>,
    },
    Single(SingleSearch),
    /// A full Aho-Corasick DFA automaton.
    Automaton(FullAcAutomaton<String>),
}

impl Prefix {
    /// Create a new prefix matching machine.
    pub fn new(mut pfxs: Vec<String>) -> Prefix {
        if pfxs.len() == 0 || pfxs[0].len() == 0 {
            Prefix::Empty
        } else if pfxs.len() == 1 && pfxs[0].len() == 1 {
            Prefix::Byte(pfxs[0].as_bytes()[0])
        } else if pfxs.len() >= 2 && pfxs.iter().all(|s| s.len() == 1) {
            let mut set = vec![false; 256];
            let mut chars = vec![];
            for p in pfxs {
                chars.push(p.as_bytes()[0]);
                set[p.as_bytes()[0] as usize] = true;
            }
            Prefix::Bytes { chars: chars, sparse: set }
        } else if pfxs.len() == 1 {
            Prefix::Single(SingleSearch::new(pfxs.pop().unwrap()))
        } else {
            Prefix::Automaton(AcAutomaton::new(pfxs).into_full())
        }
    }

    /// Find the position of a prefix in `haystack` if it exists.
    ///
    /// In the matching engines, we only actually need the starting index
    /// because the prefix is used to only skip ahead---the matching engine
    /// still needs to run over the prefix input. However, we return the ending
    /// location as well in case the prefix corresponds to the entire regex,
    /// in which case, you need the end of the match.
    pub fn find(&self, haystack: &str) -> Option<(usize, usize)> {
        use self::Prefix::*;
        match *self {
            Empty => Some((0, 0)),
            Byte(b) => memchr(b, haystack.as_bytes()).map(|i| (i, i+1)),
            Bytes { ref sparse, .. } => {
                find_singles(sparse, haystack.as_bytes())
            }
            Single(ref searcher) => {
                searcher.find(haystack).map(|i| (i, i + searcher.pat.len()))
            }
            Automaton(ref aut) => {
                aut.find(haystack).next().map(|m| (m.start, m.end))
            }
        }
    }

    /// Returns true iff this prefix is empty.
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns the number of prefixes in this machine.
    pub fn len(&self) -> usize {
        match *self {
            Prefix::Empty => 0,
            Prefix::Byte(_) => 1,
            Prefix::Bytes { ref chars, .. } => chars.len(),
            Prefix::Single(_) => 1,
            Prefix::Automaton(ref aut) => aut.len(),
        }
    }

    /// Returns true iff the prefix match preserves priority.
    ///
    /// For example, given the alternation `ab|a` and the target string `ab`,
    /// does the prefix machine guarantee that `ab` will match? (A full
    /// Aho-Corasick automaton does not!)
    pub fn preserves_priority(&self) -> bool {
        match *self {
            Prefix::Empty => true,
            Prefix::Byte(_) => true,
            Prefix::Bytes{..} => true,
            Prefix::Single(_) => true,
            Prefix::Automaton(ref aut) => {
                // Okay, so the automaton can respect priority in one
                // particular case: when every pattern is of the same length.
                // The trick is that the automaton will report the leftmost
                // match, which in this case, corresponds to the correct
                // match for the regex engine. If any other alternate matches
                // at the same position, then they must be exactly equivalent.

                // Guaranteed at least one prefix by construction, so use
                // that for the length.
                aut.patterns().iter().all(|p| p.len() == aut.pattern(0).len())
            }
        }
    }

    /// Returns all of the prefixes participating in this machine.
    ///
    /// For debug/testing only! (It allocates.)
    #[allow(dead_code)]
    pub fn prefixes(&self) -> Vec<String> {
        match *self {
            Prefix::Empty => vec![],
            Prefix::Byte(b) => vec![format!("{}", b as char)],
            Prefix::Bytes { ref chars, .. } => {
                chars.iter().map(|&b| format!("{}", b as char)).collect()
            }
            Prefix::Single(ref searcher) => vec![searcher.pat.clone()],
            Prefix::Automaton(ref aut) => aut.patterns().to_vec(),
        }
    }
}

/// Provides an implementation of fast subtring search.
///
/// In particular, this uses Boyer-Moore-Horspool with Tim Raita's twist:
/// https://en.wikipedia.org/wiki/Raita_Algorithm
///
/// I'm skeptical of the utility here, because benchmarks suggest that it is
/// difficult to beat Aho-Corasick on random text. Namely, both algorithms are
/// dominated by the performance of `memchr` for the leading byte prefix.
/// With that said, BMH does seem to surpass AC when the search text gets
/// longer (see the `easy0_1MB` vs. `easy1_1MB` benchmarks).
///
/// More analysis needs to be done to test this on different search texts.
#[derive(Clone, Debug)]
struct SingleSearch {
    pat: String,
    shift: Vec<usize>,
}

impl SingleSearch {
    fn new(pat: String) -> SingleSearch {
        assert!(pat.len() >= 1);
        let mut shift = vec![pat.len(); 256];
        for i in 0..(pat.len() - 1) {
            shift[pat.as_bytes()[i] as usize] = pat.len() - i - 1;
        }
        SingleSearch {
            pat: pat,
            shift: shift,
        }
    }

    fn find(&self, haystack: &str) -> Option<usize> {
        let pat = self.pat.as_bytes();
        let haystack = haystack.as_bytes();
        if haystack.len() < pat.len() {
            return None;
        }
        let mut i = match memchr(pat[0], haystack) {
            None => return None,
            Some(i) => i,
        };
        while i <= haystack.len() - pat.len() {
            let b = haystack[i + pat.len() - 1];
            if b == pat[pat.len() - 1]
               && haystack[i] == pat[0]
               && haystack[i + (pat.len() / 2)] == pat[pat.len() / 2]
               && pat == &haystack[i..i + pat.len()] {
                return Some(i);
            }
            i += self.shift[b as usize];
            i += match memchr(pat[0], &haystack[i..]) {
                None => return None,
                Some(i) => i,
            };
        }
        None
    }
}

/// A quick scan for multiple single byte prefixes using a sparse map.
fn find_singles(sparse: &[bool], haystack: &[u8]) -> Option<(usize, usize)> {
    // TODO: Improve this with ideas found in jetscii crate.
    for (hi, &b) in haystack.iter().enumerate() {
        if sparse[b as usize] {
            return Some((hi, hi+1));
        }
    }
    None
}

impl fmt::Debug for Prefix {
    #[allow(deprecated)] // connect => join in 1.3
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Prefix::Empty => write!(f, "Empty"),
            Prefix::Byte(b) => write!(f, "{:?}", b as char),
            Prefix::Bytes { ref chars, .. } => {
                let chars: Vec<String> =
                    chars.iter()
                         .map(|&c| format!("{:?}", c as char))
                         .collect();
                write!(f, "{}", chars.connect(", "))
            }
            Prefix::Single(ref searcher) => write!(f, "{:?}", searcher),
            Prefix::Automaton(ref aut) => write!(f, "{:?}", aut),
        }
    }
}
<|endoftext|>