use crate::RpcService;
use core::fmt;
const TAB: &str = " ";
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct RpcMethodDefines<'a> {
pub service: &'a RpcService,
}
impl<'a> fmt::Display for RpcMethodDefines<'a> {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str("#[rustfmt::skip]\n")?;
for method in self.service.methods.iter() {
let method = method.name.as_str();
let name = method.to_uppercase();
fmt.write_fmt(format_args!("\npub const {name}: &str = \"{method}\";"))?;
}
Ok(())
}
}
#[derive(Copy, Clone)]
pub struct RpcServiceImplDefines<'a> {
pub service: &'a RpcService,
pub extra_args: &'a [(&'a str, &'a str)],
pub on_invalid_request_cb: &'a str,
pub is_size_prefixed: bool,
pub default_message_limit: &'a str,
}
impl<'a> fmt::Display for RpcServiceImplDefines<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let (parse_method, finish_method) = if self.is_size_prefixed {
("size_prefixed_root_with_opts", "finish_size_prefixed")
} else {
("root_with_opts", "finish")
};
let default_message_limit = self.default_message_limit;
let on_invalid_request_cb = self.on_invalid_request_cb;
fmt.write_str("//Generated by flatbuffers-tools\n")?;
for method in self.service.methods.iter() {
let method = method.name.as_str();
fmt.write_fmt(format_args!("mod {method};\n"))?;
fmt.write_fmt(format_args!("pub use {method}::{method};\n"))?;
}
fmt.write_str("\n#[rustfmt::skip]\n")?;
fmt.write_str("pub async fn dispatch(")?;
for arg in self.extra_args.iter() {
let name = arg.0;
let typ = arg.1;
fmt.write_fmt(format_args!("{name}: {typ},"))?;
}
fmt.write_str("method: &str, input: &[u8], builder: &mut flatbuffers::FlatBufferBuilder<'_>) -> Option<Result<(), ()>> {\n")?;
for method in self.service.methods.iter() {
let define_name = method.name.to_uppercase();
let method = method.name.as_str();
fmt.write_fmt(format_args!(
"{TAB}const {define_name}: u128 = xxhash_rust::const_xxh3::xxh3_128(b\"{method}\");\n"
))?;
}
fmt.write_fmt(format_args!(
r#"
const OPTIONS: flatbuffers::VerifierOptions = flatbuffers::VerifierOptions {{
max_depth: 64,
max_tables: 100,
max_apparent_size: {default_message_limit},
ignore_missing_null_terminator: false,
}};
"#
))?;
fmt.write_fmt(format_args!(
"match xxhash_rust::xxh3::xxh3_128(method.as_bytes()) {{\n"
))?;
for method in self.service.methods.iter() {
assert_eq!(
method.arguments.len(),
1,
"We require all RPC methods to have 1 argument"
);
let argument = &method.arguments[0];
let method = method.name.as_str();
let define_name = method.to_uppercase();
fmt.write_fmt(format_args!("{TAB}{TAB}{define_name} => match flatbuffers::{parse_method}::<crate::interface::{argument}>(&OPTIONS, input) {{\n"))?;
fmt.write_fmt(format_args!("{TAB}{TAB}{TAB}Ok(req) => match {method}(req, builder"))?;
for arg in self.extra_args.iter() {
let name = arg.0;
fmt.write_str(",")?;
fmt.write_str(name)?;
}
fmt.write_str(").await {\n")?;
fmt.write_fmt(format_args!("{TAB}{TAB}{TAB}{TAB}Ok(response) => {{\n"))?;
fmt.write_fmt(format_args!(
"{TAB}{TAB}{TAB}{TAB}{TAB}let result = response.finish();\n"
))?;
fmt.write_fmt(format_args!(
"{TAB}{TAB}{TAB}{TAB}{TAB}builder.{finish_method}(result, None);\n"
))?;
fmt.write_fmt(format_args!("{TAB}{TAB}{TAB}{TAB}{TAB}Some(Ok(()))\n"))?;
fmt.write_fmt(format_args!("{TAB}{TAB}{TAB}{TAB}}}\n"))?;
fmt.write_fmt(format_args!("{TAB}{TAB}{TAB}{TAB}Err(error) => {{\n"))?;
fmt.write_fmt(format_args!(
"{TAB}{TAB}{TAB}{TAB}{TAB}let result = error.to_interface(builder);\n"
))?;
fmt.write_fmt(format_args!(
"{TAB}{TAB}{TAB}{TAB}{TAB}builder.{finish_method}(result, None);\n"
))?;
fmt.write_fmt(format_args!("{TAB}{TAB}{TAB}{TAB}{TAB}Some(Err(()))\n"))?;
fmt.write_fmt(format_args!("{TAB}{TAB}{TAB}{TAB}}}\n"))?;
fmt.write_fmt(format_args!("{TAB}{TAB}{TAB}}}\n"))?;
fmt.write_fmt(format_args!(
"{TAB}{TAB}{TAB}Err(error) => {on_invalid_request_cb}(builder, error),\n"
))?;
fmt.write_fmt(format_args!("{TAB}{TAB}}}\n"))?;
}
fmt.write_fmt(format_args!("{TAB}{TAB}_ => None,\n"))?;
fmt.write_fmt(format_args!("{TAB}}}\n"))?;
fmt.write_str("}")
}
}