#![allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ThriftField {
pub field_id: i16,
pub name: String,
pub type_name: String,
pub required: bool,
}
#[derive(Debug, Clone)]
pub struct ThriftStruct {
pub name: String,
pub fields: Vec<ThriftField>,
}
#[derive(Debug, Clone)]
pub struct ThriftFunction {
pub name: String,
pub return_type: String,
pub parameters: Vec<ThriftField>,
pub is_oneway: bool,
}
#[derive(Debug, Clone)]
pub struct ThriftService {
pub name: String,
pub functions: Vec<ThriftFunction>,
}
#[derive(Debug, Default)]
pub struct ThriftServiceExport {
pub namespace: String,
pub structs: Vec<ThriftStruct>,
pub services: Vec<ThriftService>,
}
pub fn new_thrift_service_export(namespace: &str) -> ThriftServiceExport {
ThriftServiceExport {
namespace: namespace.to_owned(),
structs: Vec::new(),
services: Vec::new(),
}
}
pub fn add_thrift_struct(export: &mut ThriftServiceExport, name: &str) {
export.structs.push(ThriftStruct {
name: name.to_owned(),
fields: Vec::new(),
});
}
pub fn add_thrift_field(
export: &mut ThriftServiceExport,
id: i16,
name: &str,
type_name: &str,
required: bool,
) {
if let Some(s) = export.structs.last_mut() {
s.fields.push(ThriftField {
field_id: id,
name: name.to_owned(),
type_name: type_name.to_owned(),
required,
});
}
}
pub fn add_thrift_service(export: &mut ThriftServiceExport, name: &str) {
export.services.push(ThriftService {
name: name.to_owned(),
functions: Vec::new(),
});
}
pub fn add_thrift_function(
export: &mut ThriftServiceExport,
name: &str,
return_type: &str,
oneway: bool,
) {
if let Some(svc) = export.services.last_mut() {
svc.functions.push(ThriftFunction {
name: name.to_owned(),
return_type: return_type.to_owned(),
parameters: Vec::new(),
is_oneway: oneway,
});
}
}
pub fn thrift_struct_count(export: &ThriftServiceExport) -> usize {
export.structs.len()
}
pub fn thrift_service_count(export: &ThriftServiceExport) -> usize {
export.services.len()
}
pub fn total_thrift_functions(export: &ThriftServiceExport) -> usize {
export.services.iter().map(|s| s.functions.len()).sum()
}
pub fn find_thrift_service<'a>(
export: &'a ThriftServiceExport,
name: &str,
) -> Option<&'a ThriftService> {
export.services.iter().find(|s| s.name == name)
}
pub fn render_thrift_service_idl(svc: &ThriftService) -> String {
let fns: Vec<String> = svc
.functions
.iter()
.map(|f| {
let oneway = if f.is_oneway { "oneway " } else { "" };
format!(" {}{} {}()", oneway, f.return_type, f.name)
})
.collect();
format!("service {} {{\n{}\n}}", svc.name, fns.join("\n"))
}
pub fn thrift_service_export_to_json(export: &ThriftServiceExport) -> String {
format!(
r#"{{"namespace":"{}", "struct_count":{}, "service_count":{}}}"#,
export.namespace,
thrift_struct_count(export),
thrift_service_count(export)
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_export_empty() {
let e = new_thrift_service_export("oxihuman");
assert_eq!(thrift_struct_count(&e), 0);
assert_eq!(thrift_service_count(&e), 0);
}
#[test]
fn add_struct_increments_count() {
let mut e = new_thrift_service_export("oxi");
add_thrift_struct(&mut e, "MeshData");
assert_eq!(thrift_struct_count(&e), 1);
}
#[test]
fn add_service_increments_count() {
let mut e = new_thrift_service_export("oxi");
add_thrift_service(&mut e, "MeshSvc");
assert_eq!(thrift_service_count(&e), 1);
}
#[test]
fn add_function_tracked() {
let mut e = new_thrift_service_export("oxi");
add_thrift_service(&mut e, "Svc");
add_thrift_function(&mut e, "getMesh", "MeshData", false);
assert_eq!(total_thrift_functions(&e), 1);
}
#[test]
fn find_service_by_name() {
let mut e = new_thrift_service_export("oxi");
add_thrift_service(&mut e, "AvatarSvc");
assert!(find_thrift_service(&e, "AvatarSvc").is_some());
}
#[test]
fn find_missing_service_none() {
let e = new_thrift_service_export("oxi");
assert!(find_thrift_service(&e, "Ghost").is_none());
}
#[test]
fn oneway_function_flag_set() {
let mut e = new_thrift_service_export("oxi");
add_thrift_service(&mut e, "Svc");
add_thrift_function(&mut e, "notify", "void", true);
assert!(e.services[0].functions[0].is_oneway);
}
#[test]
fn render_idl_contains_service_name() {
let svc = ThriftService {
name: "MySvc".into(),
functions: vec![],
};
assert!(render_thrift_service_idl(&svc).contains("MySvc"));
}
#[test]
fn json_contains_namespace() {
let e = new_thrift_service_export("com.oxihuman");
assert!(thrift_service_export_to_json(&e).contains("com.oxihuman"));
}
}