extern crate rustc_serialize;
use rustc_serialize::{Decodable, Encodable, Decoder, Encoder};
use std::str::from_utf8;
use nom::{alpha, digit, multispace, eof, IResult, Err};
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Ty {
String,
Void,
Byte,
Bool,
Binary,
I8,
I16,
I32,
I64,
Double,
List(Box<Ty>),
Set(Box<Ty>),
Map(Box<Ty>, Box<Ty>),
Ident(String)
}
impl From<String> for Ty {
fn from(val: String) -> Ty {
match &*val {
"string" => Ty::String,
"void" => Ty::Void,
"byte" => Ty::Byte,
"bool" => Ty::Bool,
"binary" => Ty::Binary,
"i8" => Ty::I8,
"i16" => Ty::I16,
"i32" => Ty::I32,
"i64" => Ty::I64,
"double" => Ty::Double,
_ => Ty::Ident(val)
}
}
}
impl Decodable for Ty {
fn decode<D: Decoder>(_d: &mut D) -> Result<Self, D::Error> {
unimplemented!()
}
}
impl Encodable for Ty {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
use self::Ty::*;
s.emit_enum("Ty", |s| {
match self {
&String => s.emit_enum_variant("string", 0, 0, |_| Ok(())),
&Void => s.emit_enum_variant("void", 1, 0, |_| Ok(())),
&Byte => s.emit_enum_variant("byte", 2, 0, |_| Ok(())),
&Bool => s.emit_enum_variant("bool", 3, 0, |_| Ok(())),
&Binary => s.emit_enum_variant("binary", 4, 0, |_| Ok(())),
&I8 => s.emit_enum_variant("i8", 5, 0, |_| Ok(())),
&I16 => s.emit_enum_variant("i16", 6, 0, |_| Ok(())),
&I32 => s.emit_enum_variant("i32", 7, 0, |_| Ok(())),
&I64 => s.emit_enum_variant("i64", 8, 0, |_| Ok(())),
&Double => s.emit_enum_variant("double", 8, 0, |_| Ok(())),
&List(ref ty) => s.emit_enum_variant("list", 10, 1, |s| {
try!(s.emit_enum_variant_arg(0, |s| {
ty.encode(s)
}));
Ok(())
}),
&Set(ref ty) => s.emit_enum_variant("set", 11, 1, |s| {
try!(s.emit_enum_variant_arg(0, |s| {
ty.encode(s)
}));
Ok(())
}),
&Map(ref kty, ref vty) => s.emit_enum_variant("map", 12, 1, |s| {
try!(s.emit_enum_variant_arg(0, |s| {
kty.encode(s)
}));
try!(s.emit_enum_variant_arg(1, |s| {
vty.encode(s)
}));
Ok(())
}),
&Ident(ref string) => s.emit_enum_variant("ident", 14, 1, |s| {
try!(s.emit_enum_variant_arg(0, |s| {
s.emit_str(&string)
}));
Ok(())
}),
}
})
}
}
impl Ty {
pub fn to_protocol(&self) -> String {
match self {
&Ty::String => "::tokio_thrift::protocol::ThriftType::String".to_string(),
&Ty::Void => "::tokio_thrift::protocol::ThriftType::Void".to_string(),
&Ty::Bool => "::tokio_thrift::protocol::ThriftType::Bool".to_string(),
&Ty::Byte => "::tokio_thrift::protocol::ThriftType::Byte".to_string(),
&Ty::Double => "::tokio_thrift::protocol::ThriftType::Double".to_string(),
&Ty::I16 => "::tokio_thrift::protocol::ThriftType::I16".to_string(),
&Ty::I32 => "::tokio_thrift::protocol::ThriftType::I32".to_string(),
&Ty::I64 => "::tokio_thrift::protocol::ThriftType::I64".to_string(),
&Ty::Map(_, _) => "::tokio_thrift::protocol::ThriftType::Map".to_string(),
&Ty::List(_) => "::tokio_thrift::protocol::ThriftType::List".to_string(),
&Ty::Set(_) => "::tokio_thrift::protocol::ThriftType::Set".to_string(),
&Ty::Binary => "::tokio_thrift::protocol::ThriftType::List".to_string(),
&Ty::Ident(ref s) => s.to_string(),
t => panic!("Not compatible with ThriftType: {:?}", t)
}
}
pub fn to_string(&self) -> String {
match self {
&Ty::String => "String".to_string(),
&Ty::Void => "()".to_string(),
&Ty::Byte => "u8".to_string(),
&Ty::Bool => "bool".to_string(),
&Ty::Binary => "Vec<i8>".to_string(),
&Ty::I8 => "i8".to_string(),
&Ty::I16 => "i16".to_string(),
&Ty::I32 => "i32".to_string(),
&Ty::I64 => "i64".to_string(),
&Ty::Double => "double".to_string(),
&Ty::List(ref s) => {
let inner = s.to_string();
format!("Vec<{}>", inner)
},
&Ty::Set(ref s) => {
let inner = s.to_string();
format!("HashSet<{}>", inner)
},
&Ty::Map(ref a, ref b) => {
let a = a.to_string();
let b = b.to_string();
format!("HashMap<{}, {}>", a, b)
},
&Ty::Ident(ref s) => {
s.clone()
}
}
}
}
#[derive(Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Document {
pub headers: Vec<Header>,
pub definitions: Vec<Definition>,
}
#[derive(Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum Header {
Include(Include),
Namespace(Namespace),
}
#[derive(Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum Definition {
Const(Const),
Typedef(Typedef),
Enum(Enum),
Struct(Struct),
Union(Union),
Exception(Exception),
Service(Service),
}
#[derive(Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Include {
pub path: String,
}
#[derive(Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Service {
pub extends: Option<String>,
pub ident: String,
pub methods: Vec<ServiceMethod>,
}
#[derive(Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct ServiceMethod {
pub oneway: bool,
pub ident: String,
pub ty: Ty,
pub args: Vec<StructField>,
pub throws: Option<Vec<StructField>>,
}
#[derive(Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Enum {
pub ident: String,
pub variants: Vec<Variant>,
}
#[derive(Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Variant {
pub ident: String,
pub seq: Option<i64>,
}
#[derive(Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Union {
pub ident: String,
pub fields: Vec<StructField>,
}
#[derive(Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Struct {
pub ident: String,
pub fields: Vec<StructField>,
}
#[derive(Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Exception {
pub ident: String,
pub fields: Vec<StructField>,
}
#[derive(Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct StructField {
pub seq: Option<i64>,
pub optional: bool,
pub ty: Ty,
pub ident: String,
pub value: Option<ConstValue>,
}
#[derive(Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Typedef {
pub ty: Ty,
pub ident: String,
}
#[derive(Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Const {
pub ident: String,
pub ty: Ty,
pub value: ConstValue,
}
#[derive(Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum ConstValue {
Int(i64),
Double(f64),
String(String),
List(Vec<ConstValue>),
Map,
}
#[derive(Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub struct Namespace {
pub lang: String,
pub module: String,
}
impl Document {
pub fn parse(input: &str) -> Result<Option<Self>, Err<&[u8], u32>> {
match document(input.as_bytes()) {
IResult::Done(i, d) => {
println!("{}", from_utf8(i).unwrap());
Ok(Some(d))
},
IResult::Incomplete(_) => Ok(None),
IResult::Error(e) => Err(e),
}
}
pub fn rearrange(&mut self) {
}
}
named!(document <Document>, chain!(
blank? ~
headers: many0!(chain!(h: header ~ blank?, || h)) ~
defs: many0!(chain!(d: definition ~ blank?, || d)) ~
eof
,
|| Document {
headers: headers,
definitions: defs,
}));
named!(header <Header>, alt!(
include => {Header::Include} |
namespace => {Header::Namespace}));
named!(include <Include>, chain!(
tag!("include") ~ blank ~
file: literal,
|| Include{
path: file,
}));
named!(namespace <Namespace>, chain!(
tag!("namespace") ~ blank ~
lang: identifier ~ blank ~
ns: identifier,
|| Namespace{
lang: lang,
module: ns,
}));
named!(definition <Definition>, alt!(
const_ => {Definition::Const}|
typedef => {Definition::Typedef}|
enum_ => {Definition::Enum}|
struct_ => {Definition::Struct}|
union => {Definition::Union}|
exception => {Definition::Exception}|
service => {Definition::Service}));
named!(const_ <Const>, chain!(
tag!("const") ~ blank ~
ty: field_type ~ blank ~
id: identifier ~ blank? ~
tag!("=") ~ blank? ~
value: const_value ~ blank? ~
list_separator?,
|| Const {
ident: id,
ty: ty,
value: value,
}));
named!(typedef <Typedef>, chain!(
tag!("typedef") ~ blank ~
ty: definition_type ~ blank ~
id: identifier,
|| Typedef{
ty: ty,
ident: id,
}));
named!(enum_ <Enum>, chain!(
tag!("enum") ~ blank ~
id: identifier ~ blank? ~
tag!("{") ~ blank? ~
variants: many0!(chain!(
variant: identifier ~
index: chain!(
blank? ~
tag!("=") ~
blank? ~
idx: int_constant, || idx)? ~
blank? ~
list_separator? ~
blank? ,
|| Variant{ident: variant, seq: index})) ~
tag!("}"),
|| Enum{
ident: id,
variants: variants,
}));
named!(struct_ <Struct>, chain!(
tag!("struct") ~ blank ~
id: identifier ~ blank? ~
tag!("{") ~
fields: many0!(chain!(blank? ~ f: field, || f)) ~
blank? ~
tag!("}") ,
|| Struct {
ident: id,
fields: fields,
}));
named!(union <Union>, chain!(
tag!("union") ~ blank ~
id: identifier ~ blank? ~
tag!("{") ~
fields: many0!(chain!(blank? ~ f: field, || f)) ~
blank? ~
tag!("}") ,
|| Union {
ident: id,
fields: fields,
}));
named!(exception <Exception>, chain!(
tag!("exception") ~ blank ~
id: identifier ~ blank? ~
tag!("{") ~
fields: many0!(chain!(blank? ~ f: field, || f)) ~
blank? ~
tag!("}") ,
|| Exception {
ident: id,
fields: fields,
}));
named!(service <Service>, chain!(
tag!("service") ~ blank ~
id: identifier ~ blank? ~
ext: chain!(tag!("extends") ~ blank ~
exid: identifier, || exid)? ~
blank? ~
tag!("{") ~ blank? ~
functions: many0!(chain!(f: function ~ blank?, || f)) ~
tag!("}") ,
|| Service{
extends: ext,
ident: id,
methods: functions,
}));
named!(field <StructField>, chain!(
idx: chain!(idx: field_id ~ blank?, || idx)? ~
req: chain!(req: field_req ~ blank, || req)? ~
ty: field_type ~ blank ~
id: identifier ~ blank? ~
value: chain!(tag!("=") ~ blank? ~
v: const_value, || v)? ~
list_separator?
,
|| StructField {
seq: idx,
optional: req.unwrap_or(false),
ty: ty,
ident: id,
value: value,
}));
named!(field_id <i64>, chain!(id: int_constant ~ blank? ~ tag!(":"), || id));
named!(field_req <bool>, alt!(
tag!("required") => {|_| false}|
tag!("optional") => {|_| true}));
named!(function <ServiceMethod>, chain!(
oneway: chain!(tag!("oneway") ~ blank?, ||())? ~
ty: function_type ~ blank ~
id: identifier ~ blank? ~
tag!("(") ~ blank? ~
args: many0!(chain!(f: field ~ blank?, || f)) ~
tag!(")") ~
throws: chain!(blank? ~ th: throws, || th)? ~
chain!(blank? ~ list_separator, ||())?
,
|| {
let oneway = oneway.is_some();
ServiceMethod{
oneway: oneway,
ident: id,
ty: ty,
args: args,
throws: throws,
}}));
named!(function_type <Ty>, alt!(
tag!("void") => {|_| Ty::Void} |
field_type));
named!(throws < Vec<StructField> >, chain!(
tag!("throws") ~ blank? ~
tag!("(") ~ blank? ~
fields: many0!(chain!(f: field ~ blank?, || f)) ~
tag!(")"),
|| fields));
named!(field_type <Ty>, alt!(
base_type |
container_type |
identifier => {|i| Ty::Ident(i)}));
named!(definition_type <Ty>, alt!(
base_type |
container_type));
named!(base_type <Ty>, alt!(
tag!("bool") => {|_| Ty::Bool} |
tag!("byte") => {|_| Ty::Byte} |
tag!("i8") => {|_| Ty::I8} |
tag!("i16") => {|_| Ty::I16} |
tag!("i32") => {|_| Ty::I32} |
tag!("i64") => {|_| Ty::I64} |
tag!("double") => {|_| Ty::Double} |
tag!("string") => {|_| Ty::String} |
tag!("binary") => {|_| Ty::Binary}));
named!(container_type <Ty>, alt!(map_type | set_type | list_type));
named!(map_type <Ty>, chain!(
tag!("map") ~ blank? ~
tag!("<") ~ blank? ~
k: field_type ~ blank? ~
tag!(",") ~ blank? ~
v: field_type ~ blank? ~
tag!(">"),
|| Ty::Map(Box::new(k), Box::new(v))));
named!(set_type <Ty>, chain!(
tag!("set") ~ blank? ~
tag!("<") ~ blank? ~
v: field_type ~ blank?
~ tag!(">"),
|| Ty::Set(Box::new(v))));
named!(list_type <Ty>, chain!(
tag!("list") ~ blank? ~
tag!("<") ~ blank? ~
v: field_type ~ blank?
~ tag!(">"),
|| Ty::List(Box::new(v))));
named!(const_value <ConstValue>, alt!(
double_constant => {ConstValue::Double} |
int_constant => {ConstValue::Int} |
literal => {ConstValue::String} |
identifier => {|_| panic!("identifier not supported")} |
const_list |
const_map));
named!(int_constant <i64>, chain!
(sgn: sgn? ~ n: map_res!(digit, from_utf8),
|| format!("{}{}", sgn.unwrap_or(""), n).parse::<i64>().unwrap()));
named!(double_constant <f64>, chain!(
sgn: sgn? ~
n: map_res!(digit, from_utf8) ~
fp: alt!(chain!(tag!(".") ~
frac: map_res!(digit, from_utf8) ~
pow: chain!(alt!(tag!("E") | tag!("e")) ~ p: int_constant, || p)?
,
|| (Some(frac), pow))
|
chain!(
alt!(tag!("E") | tag!("e")) ~
pow: int_constant,
|| (None, Some(pow))))
, || {
let sgn = sgn.unwrap_or("");
let (frac, pow) = fp;
let frac = frac.unwrap_or("0");
let pow = pow.map(|i| format!("e{}", i)).unwrap_or("".to_string());
let f = format!("{}{}.{}{}", sgn, n, frac, pow).parse::<f64>().expect("internal error: failed to parse double literal internally");
f
}));
named!(sgn <&str>, map_res!(alt!(tag!("+") | tag!("-")), from_utf8));
named!(const_list <ConstValue>, chain!(
tag!("[") ~ blank? ~
vs: many0!(chain!(
v: const_value ~ blank? ~
list_separator? ~ blank?, || v)) ~
tag!("]"),
|| ConstValue::List(vs)));
named!(const_map <ConstValue>, chain!(
tag!("{") ~ blank? ~
vs: many0!(chain!(
k: const_value ~ blank? ~
tag!(":") ~ blank? ~
v: const_value ~ blank? ~
list_separator? ~ blank?, || v)) ~
tag!("}"),
|| ConstValue::Map));
named!(literal <String>, map_res!(alt!(
chain!(tag!("\"") ~ s: is_not!("\"") ~ tag!("\""), || s) |
chain!(tag!("'") ~ s: is_not!("'") ~ tag!("'") , || s)),
|v| from_utf8(v).map(|s| s.to_string())));
fn cat_vec(vs: Vec<&[u8]>) -> Vec<u8> {
let mut ret = Vec::new();
for v in vs {
ret.extend_from_slice(v);
}
ret
}
named!(identifier <String>, chain!(
h: map_res!(alt!(alpha | tag!("_")), from_utf8) ~
t: map_res!(many0!(
alt!(
alpha |
digit |
is_a!("._"))),
|vs| from_utf8(&cat_vec(vs)).map(|s|s.to_string())),
|| format!("{}{}", h, t)));
named!(list_separator, alt!(tag!(",") | tag!(";")));
named!(blank <()>, map!(many1!(alt!(comment | map!(multispace, |_| ()))), |_|()));
named!(comment <()>, alt!(
chain!(
tag!("/*") ~
take_until_and_consume!("*/"),
||()) |
chain!(tag!("//") ~ take_until_and_consume!("\n"), ||()) |
chain!(tag!("#") ~ take_until_and_consume!("\n"), ||())));
#[test]
fn test_document() {
assert_eq!(document(b"include \"foo.thrift\" ").unwrap().1,
Document{
headers: vec![Header::Include(Include {path: "foo.thrift".to_string()})],
definitions: vec![]}
);
assert_eq!(document(b"const i32 foo = 1;").unwrap().1,
Document{
headers: vec![],
definitions: vec![Definition::Const(Const {ident: "foo".to_string(), ty: Ty::I32, value: ConstValue::Int(1)})]}
);
assert_eq!(document(b"
include \"foo.thrift\"
const i32 foo = 1
struct Foo {}
").unwrap().1,
Document{
headers: vec![Header::Include(Include {path: "foo.thrift".to_string()})],
definitions: vec![Definition::Const(Const {ident: "foo".to_string(), ty: Ty::I32, value: ConstValue::Int(1)}),
Definition::Struct(Struct {ident: "Foo".to_string(), fields: vec![],})]}
);
}
#[test]
fn test_header() {
assert_eq!(header(b"include \"foo.thrift\"").unwrap().1,
Header::Include(Include {path: "foo.thrift".to_string()})
);
assert_eq!(header(b"namespace rust aaaa").unwrap().1,
Header::Namespace(Namespace {
lang: "rust".to_string(),
module: "aaaa".to_string(),
}));
}
#[test]
fn test_include() {
assert_eq!(include(b"include \"foo.thrift\"").unwrap().1,
Include {path: "foo.thrift".to_string()}
);
}
#[test]
fn test_namespace() {
assert_eq!(namespace(b"namespace rust aaaa").unwrap().1, Namespace {
lang: "rust".to_string(),
module: "aaaa".to_string(),
});
assert_eq!(namespace(b"namespace ruby Aaa").unwrap().1, Namespace {
lang: "ruby".to_string(),
module: "Aaa".to_string(),
});
}
#[test]
fn test_definition() {
assert_eq!(definition(b"const i32 foo = 1;").unwrap().1,
Definition::Const(Const {ident: "foo".to_string(), ty: Ty::I32, value: ConstValue::Int(1)})
);
assert_eq!(definition(b"typedef string foo").unwrap().1,
Definition::Typedef(Typedef {ty: Ty::String, ident: "foo".to_string()}));
assert_eq!(definition(b"enum Foo {}").unwrap().1,
Definition::Enum(Enum {
ident: "Foo".to_string(),
variants: vec![],
}));
assert_eq!(definition(b"struct Foo {}").unwrap().1,
Definition::Struct(Struct {
ident: "Foo".to_string(),
fields: vec![],
}));
assert_eq!(definition(b"union Foo {}").unwrap().1,
Definition::Union(Union {
ident: "Foo".to_string(),
fields: vec![],
}));
assert_eq!(definition(b"exception Foo {}").unwrap().1,
Definition::Exception(Exception {
ident: "Foo".to_string(),
fields: vec![],
}));
assert_eq!(definition(b"service Foo {} ").unwrap().1,
Definition::Service(Service {
extends: None,
ident: "Foo".to_string(),
methods: vec![],
}));
}
#[test]
fn test_const() {
assert_eq!(const_(b"const i32 foo = 1;").unwrap().1,
Const {ident: "foo".to_string(), ty: Ty::I32, value: ConstValue::Int(1)}
);
assert_eq!(const_(b"const i32 foo = 1,").unwrap().1,
Const {ident: "foo".to_string(), ty: Ty::I32, value: ConstValue::Int(1)}
);
}
#[test]
fn test_typedef() {
assert_eq!(typedef(b"typedef string foo").unwrap().1,
Typedef {ty: Ty::String, ident: "foo".to_string()});
}
#[test]
fn test_enum() {
assert_eq!(enum_(b"enum Foo {}").unwrap().1,
Enum {
ident: "Foo".to_string(),
variants: vec![],
});
assert_eq!(enum_(b"enum Foo {
foo
}").unwrap().1,
Enum {
ident: "Foo".to_string(),
variants: vec![Variant{ident:"foo".to_string(), seq: None}]
});
assert_eq!(enum_(b"enum Foo {
foo
}").unwrap().1,
Enum {
ident: "Foo".to_string(),
variants: vec![Variant{ident: "foo".to_string(), seq: None}]
});
assert_eq!(enum_(b"enum Foo {
foo
bar
}").unwrap().1,
Enum {
ident: "Foo".to_string(),
variants: vec![Variant {ident: "foo".to_string(), seq: None},
Variant{ident: "bar".to_string(), seq: None}
]
});
assert_eq!(enum_(b"enum Foo {
foo,
bar,
}").unwrap().1,
Enum {
ident: "Foo".to_string(),
variants: vec![Variant{ident: "foo".to_string(), seq: None},
Variant{ident: "bar".to_string(), seq: None}
]
});
assert_eq!(enum_(b"enum Foo {
foo;
bar;
}").unwrap().1,
Enum {
ident: "Foo".to_string(),
variants: vec![Variant{ident: "foo".to_string(), seq: None},
Variant{ident: "bar".to_string(), seq: None}
]
});
}
#[test]
fn test_struct() {
assert_eq!(struct_(b"struct Foo {}").unwrap().1,
Struct {
ident: "Foo".to_string(),
fields: vec![],
});
assert_eq!(struct_(b"struct Foo {1: required string foo}").unwrap().1,
Struct {
ident: "Foo".to_string(),
fields: vec![
StructField {
seq: Some(1),
optional: false,
ident: "foo".to_string(),
ty: Ty::String,
value: None,
}],
});
}
#[test]
fn test_union() {
assert_eq!(union(b"union Foo {}").unwrap().1,
Union {
ident: "Foo".to_string(),
fields: vec![],
});
assert_eq!(union(b"union Foo {1: required string foo}").unwrap().1,
Union {
ident: "Foo".to_string(),
fields: vec![
StructField {
seq: Some(1),
optional: false,
ident: "foo".to_string(),
ty: Ty::String,
value: None,
}],
});
}
#[test]
fn test_exception() {
assert_eq!(exception(b"exception Foo {}").unwrap().1,
Exception{
ident: "Foo".to_string(),
fields: vec![],
});
assert_eq!(exception(b"exception Foo {1: required string foo}").unwrap().1,
Exception{
ident: "Foo".to_string(),
fields: vec![
StructField {
seq: Some(1),
optional: false,
ident: "foo".to_string(),
ty: Ty::String,
value: None,
}],
});
}
#[test]
fn test_service() {
assert_eq!(service(b"service Foo {
}
").unwrap().1, Service {
extends: None,
ident: "Foo".to_string(),
methods: vec![],
});
assert_eq!(service(b"service Foo {
void foo(),
}
").unwrap().1, Service {
extends: None,
ident: "Foo".to_string(),
methods: vec![
ServiceMethod {
oneway: false,
ident: "foo".to_string(),
ty: Ty::Void,
args: vec![],
throws: None,
}
],
});
assert_eq!(service(b"service Foo {
void foo();
}
").unwrap().1, Service {
extends: None,
ident: "Foo".to_string(),
methods: vec![
ServiceMethod {
oneway: false,
ident: "foo".to_string(),
ty: Ty::Void,
args: vec![],
throws: None,
}
],
});
assert_eq!(service(b"service Foo {
void foo()
void bar()
}
").unwrap().1, Service {
extends: None,
ident: "Foo".to_string(),
methods: vec![
ServiceMethod {
oneway: false,
ident: "foo".to_string(),
ty: Ty::Void,
args: vec![],
throws: None,
},
ServiceMethod {
oneway: false,
ident: "bar".to_string(),
ty: Ty::Void,
args: vec![],
throws: None,
}
],
});
assert_eq!(service(b"service Foo {
void foo();
void bar();
}
").unwrap().1, Service {
extends: None,
ident: "Foo".to_string(),
methods: vec![
ServiceMethod {
oneway: false,
ident: "foo".to_string(),
ty: Ty::Void,
args: vec![],
throws: None,
},
ServiceMethod {
oneway: false,
ident: "bar".to_string(),
ty: Ty::Void,
args: vec![],
throws: None,
}
],
});
assert_eq!(service(b"service Foo {
void foo(),
void bar(),
}
").unwrap().1, Service {
extends: None,
ident: "Foo".to_string(),
methods: vec![
ServiceMethod {
oneway: false,
ident: "foo".to_string(),
ty: Ty::Void,
args: vec![],
throws: None,
},
ServiceMethod {
oneway: false,
ident: "bar".to_string(),
ty: Ty::Void,
args: vec![],
throws: None,
}
],
});
assert_eq!(service(b"service Foo extends some.Bar {
void foo(),
}
").unwrap().1, Service {
extends: Some("some.Bar".to_string()),
ident: "Foo".to_string(),
methods: vec![
ServiceMethod {
oneway: false,
ident: "foo".to_string(),
ty: Ty::Void,
args: vec![],
throws: None,
},
],
});
}
#[test]
fn test_field() {
assert_eq!(field(b"string foo;").unwrap().1,
StructField {seq: None,
optional: false,
ident: "foo".to_string(),
ty: Ty::String,
value: None,
});
assert_eq!(field(b"1: string foo;").unwrap().1,
StructField {seq: Some(1),
optional: false,
ident: "foo".to_string(),
ty: Ty::String,
value: None,
});
assert_eq!(field(b"1: i32 foo;").unwrap().1,
StructField {seq: Some(1),
optional: false,
ident: "foo".to_string(),
ty: Ty::I32,
value: None,});
assert_eq!(field(b"1: i32 foo = 3;").unwrap().1,
StructField {seq: Some(1),
optional: false,
ident: "foo".to_string(),
ty: Ty::I32,
value: Some(ConstValue::Int(3)),
});
assert_eq!(field(b"2: required set<binary> foo,").unwrap().1,
StructField {seq: Some(2),
optional: false,
ident: "foo".to_string(),
ty: Ty::Set(Box::new(Ty::Binary)),
value: None,
});
assert_eq!(field(b"3: optional string foo;").unwrap().1,
StructField {seq: Some(3),
optional: true,
ident: "foo".to_string(),
ty: Ty::String,
value: None,
});
}
#[test]
fn test_field_id() {
assert_eq!(field_id(b"1:").unwrap().1, 1);
assert_eq!(field_id(b"1 :").unwrap().1, 1);
}
#[test]
fn test_field_req() {
assert_eq!(field_req(b"required").unwrap().1, false);
assert_eq!(field_req(b"optional").unwrap().1, true);
}
#[test]
fn test_function() {
assert_eq!(function(b"i32 foo();").unwrap().1,
ServiceMethod {
oneway: false,
ident: "foo".to_string(),
ty: Ty::I32,
args: vec![],
throws: None,
});
assert_eq!(function(b"i32 foo(1: string bar);").unwrap().1,
ServiceMethod {
oneway: false,
ident: "foo".to_string(),
ty: Ty::I32,
args: vec![
StructField {
seq: Some(1),
optional: false,
ident: "bar".to_string(),
ty: Ty::String,
value: None,
},
],
throws: None,
});
assert_eq!(function(b"i32 foo(1: required string bar);").unwrap().1,
ServiceMethod {
oneway: false,
ident: "foo".to_string(),
ty: Ty::I32,
args: vec![
StructField {
seq: Some(1),
optional: false,
ident: "bar".to_string(),
ty: Ty::String,
value: None,
},
],
throws: None,
});
assert_eq!(function(b"void foo(1: required string bar),").unwrap().1,
ServiceMethod {
oneway: false,
ident: "foo".to_string(),
ty: Ty::Void,
args: vec![
StructField {
seq: Some(1),
optional: false,
ident: "bar".to_string(),
ty: Ty::String,
value: None,
},
],
throws: None,
});
assert_eq!(function(b"oneway void foo(1: required string bar);").unwrap().1,
ServiceMethod {
oneway: true,
ident: "foo".to_string(),
ty: Ty::Void,
args: vec![
StructField {
seq: Some(1),
optional: false,
ident: "bar".to_string(),
ty: Ty::String,
value: None,
},
],
throws: None,
});
assert_eq!(function(b"oneway i32 foo(1: required string bar);").unwrap().1,
ServiceMethod {
oneway: true,
ident: "foo".to_string(),
ty: Ty::I32,
args: vec![
StructField {
seq: Some(1),
optional: false,
ident: "bar".to_string(),
ty: Ty::String,
value: None,
},
],
throws: None,
});
assert_eq!(function(b"i32 foo(1: required string bar; optional binary baz);").unwrap().1,
ServiceMethod {
oneway: false,
ident: "foo".to_string(),
ty: Ty::I32,
args: vec![
StructField {
seq: Some(1),
optional: false,
ident: "bar".to_string(),
ty: Ty::String,
value: None,
},
StructField {
seq: None,
optional: true,
ident: "baz".to_string(),
ty: Ty::Binary,
value: None,
},
],
throws: None,
});
assert_eq!(function(b"i32 foo(1: required string bar, 2: optional binary baz);").unwrap().1,
ServiceMethod {
oneway: false,
ident: "foo".to_string(),
ty: Ty::I32,
args: vec![
StructField {
seq: Some(1),
optional: false,
ident: "bar".to_string(),
ty: Ty::String,
value: None,
},
StructField {
seq: Some(2),
optional: true,
ident: "baz".to_string(),
ty: Ty::Binary,
value: None,
},
],
throws: None,
});
assert_eq!(function(b"i32 foo(1: required string bar) throws (1: list<i32> pee);").unwrap().1,
ServiceMethod {
oneway: false,
ident: "foo".to_string(),
ty: Ty::I32,
args: vec![
StructField {
seq: Some(1),
optional: false,
ident: "bar".to_string(),
ty: Ty::String,
value: None,
},
],
throws: Some(vec![
StructField {
seq: Some(1),
optional: false,
ident: "pee".to_string(),
ty: Ty::List(Box::new(Ty::I32)),
value: None,
}
]),
});
assert_eq!(function(b"i32 foo(1: required string bar) throws (1: list<i32> pee, 2: optional set<byte> poo),").unwrap().1,
ServiceMethod {
oneway: false,
ident: "foo".to_string(),
ty: Ty::I32,
args: vec![
StructField {
seq: Some(1),
optional: false,
ident: "bar".to_string(),
ty: Ty::String,
value: None,
},
],
throws: Some(vec![
StructField {
seq: Some(1),
optional: false,
ident: "pee".to_string(),
ty: Ty::List(Box::new(Ty::I32)),
value: None,
},
StructField {
seq: Some(2),
optional: true,
ident: "poo".to_string(),
ty: Ty::Set(Box::new(Ty::Byte)),
value: None,
},
]),
});
}
#[test]
fn test_function_type() {
assert_eq!(function_type(b"void").unwrap().1, Ty::Void);
assert_eq!(function_type(b"list<i32>").unwrap().1, Ty::List(Box::new(Ty::I32)));
assert_eq!(function_type(b"list<void>").unwrap().1, Ty::List(Box::new(Ty::Ident("void".to_string()))));
}
#[test]
fn test_throws() {
assert_eq!(throws(b"throws(1: string foo)").unwrap().1,
vec![StructField {seq: Some(1),
optional: false,
ident: "foo".to_string(),
ty: Ty::String,
value: None,
}]);
assert_eq!(throws(b"throws( 1: string foo )").unwrap().1,
vec![StructField {seq: Some(1),
optional: false,
ident: "foo".to_string(),
ty: Ty::String,
value: None,
}]
);
assert_eq!(throws(b"throws(1: string foo, 2: optional i32 bar)").unwrap().1,
vec![StructField {seq: Some(1),
optional: false,
ident: "foo".to_string(),
ty: Ty::String,
value: None,
},
StructField {seq: Some(2),
optional: true,
ident: "bar".to_string(),
ty: Ty::I32,
value: None,
}]
);
}
#[test]
fn test_field_type() {
assert_eq!(field_type(b"i8").unwrap().1, Ty::I8);
assert_eq!(field_type(b"list < i32 >").unwrap().1, Ty::List(Box::new(Ty::I32)));
assert_eq!(field_type(b"aaaa").unwrap().1, Ty::Ident("aaaa".to_string()));
}
#[test]
fn test_definition_type() {
assert_eq!(definition_type(b"i8").unwrap().1, Ty::I8);
assert_eq!(definition_type(b"list < i32 >").unwrap().1, Ty::List(Box::new(Ty::I32)));
}
#[test]
fn test_base_type() {
assert_eq!(base_type(b"bool").unwrap().1, Ty::Bool);
assert_eq!(base_type(b"byte").unwrap().1, Ty::Byte);
assert_eq!(base_type(b"i8").unwrap().1, Ty::I8);
assert_eq!(base_type(b"i16").unwrap().1, Ty::I16);
assert_eq!(base_type(b"i32").unwrap().1, Ty::I32);
assert_eq!(base_type(b"i64").unwrap().1, Ty::I64);
assert_eq!(base_type(b"double").unwrap().1, Ty::Double);
assert_eq!(base_type(b"string").unwrap().1, Ty::String);
assert_eq!(base_type(b"binary").unwrap().1, Ty::Binary);
}
#[test]
fn test_container_type() {
assert_eq!(container_type(b"map<i32, bool>").unwrap().1, Ty::Map(Box::new(Ty::I32), Box::new(Ty::Bool)));
assert_eq!(container_type(b"map < i32 , string >").unwrap().1, Ty::Map(Box::new(Ty::I32), Box::new(Ty::String)));
assert_eq!(container_type(b"map<map<i32, bool>, map<bool, i32>>").unwrap().1,
Ty::Map(Box::new(Ty::Map(Box::new(Ty::I32), Box::new(Ty::Bool))),
Box::new(Ty::Map(Box::new(Ty::Bool), Box::new(Ty::I32)))));
assert_eq!(container_type(b"set<i32>").unwrap().1, Ty::Set(Box::new(Ty::I32)));
assert_eq!(container_type(b"set < i32 >").unwrap().1, Ty::Set(Box::new(Ty::I32)));
assert_eq!(container_type(b"set<set<i32>>").unwrap().1, Ty::Set(Box::new(Ty::Set(Box::new(Ty::I32)))));
assert_eq!(container_type(b"list<i32>").unwrap().1, Ty::List(Box::new(Ty::I32)));
assert_eq!(container_type(b"list < i32 >").unwrap().1, Ty::List(Box::new(Ty::I32)));
assert_eq!(container_type(b"list<list<i32>>").unwrap().1, Ty::List(Box::new(Ty::List(Box::new(Ty::I32)))));
}
#[test]
fn test_map_type() {
assert_eq!(map_type(b"map<i32, bool>").unwrap().1, Ty::Map(Box::new(Ty::I32), Box::new(Ty::Bool)));
assert_eq!(map_type(b"map < i32 , string >").unwrap().1, Ty::Map(Box::new(Ty::I32), Box::new(Ty::String)));
assert_eq!(map_type(b"map<map<i32, bool>, map<bool, i32>>").unwrap().1,
Ty::Map(Box::new(Ty::Map(Box::new(Ty::I32), Box::new(Ty::Bool))),
Box::new(Ty::Map(Box::new(Ty::Bool), Box::new(Ty::I32)))));
}
#[test]
fn test_set_type() {
assert_eq!(set_type(b"set<i32>").unwrap().1, Ty::Set(Box::new(Ty::I32)));
assert_eq!(set_type(b"set < i32 >").unwrap().1, Ty::Set(Box::new(Ty::I32)));
assert_eq!(set_type(b"set<set<i32>>").unwrap().1, Ty::Set(Box::new(Ty::Set(Box::new(Ty::I32)))));
}
#[test]
fn test_list_type() {
assert_eq!(list_type(b"list<i32>").unwrap().1, Ty::List(Box::new(Ty::I32)));
assert_eq!(list_type(b"list < i32 >").unwrap().1, Ty::List(Box::new(Ty::I32)));
assert_eq!(list_type(b"list<list<i32>>").unwrap().1, Ty::List(Box::new(Ty::List(Box::new(Ty::I32)))));
}
#[test]
fn test_const_value() {
assert_eq!(const_value(b"1 ").unwrap().1, ConstValue::Int(1));
assert_eq!(const_value(b"-1 ").unwrap().1, ConstValue::Int(-1));
assert_eq!(const_value(b"1.0 ").unwrap().1, ConstValue::Double(1.0));
assert_eq!(const_value(b"-1.01 ").unwrap().1, ConstValue::Double(-1.01));
assert_eq!(const_value(b"'aaa'").unwrap().1, ConstValue::String("aaa".to_string()));
assert_eq!(const_value(b"\"aaa\"").unwrap().1, ConstValue::String("aaa".to_string()));
}
#[test]
fn test_int_constant() {
assert_eq!(int_constant(b"1").unwrap().1, 1);
assert_eq!(int_constant(b"-10").unwrap().1, -10);
}
#[test]
fn test_double_constant() {
println!("{:?}", double_constant(b"-1.0 "));
assert_eq!(double_constant(b"1.0 ").unwrap().1, 1.0);
assert_eq!(double_constant(b"-0.01 ").unwrap().1, -0.01);
assert_eq!(double_constant(b"-1.0e-2 ").unwrap().1, -0.01);
assert_eq!(double_constant(b"-1E2 ").unwrap().1, -100.0);
}
#[test]
fn test_literal() {
assert_eq!(literal(b"\"literal\"").unwrap().1, "literal".to_string());
assert_eq!(literal(b"'literal'").unwrap().1, "literal".to_string());
}
#[test]
fn test_identifier() {
assert_eq!(identifier(b"aiueo").unwrap().1, "aiueo".to_string());
assert_eq!(identifier(b"_aiueo").unwrap().1, "_aiueo".to_string());
assert_eq!(identifier(b"_aiu3o").unwrap().1, "_aiu3o".to_string());
assert_eq!(identifier(b"_aiu.o").unwrap().1, "_aiu.o".to_string());
}
#[test]
fn test_comment() {
assert_eq!(comment(b"# aaaaa
").unwrap().1, ());
assert_eq!(comment(b"// aaaaa
").unwrap().1, ());
assert_eq!(comment(b"/*aaa*/").unwrap().1, ());
assert_eq!(comment(b"/*
aaa
*/").unwrap().1, ());
assert_eq!(comment(b"/*
* aaa
*/").unwrap().1, ());
}