272 lines
9.1 KiB
Rust
272 lines
9.1 KiB
Rust
mod extend;
|
|
|
|
use crate::extend::AsStrType;
|
|
use prost::Message;
|
|
use prost_types::field_descriptor_proto::Label;
|
|
use prost_types::{
|
|
DescriptorProto, EnumDescriptorProto, FieldDescriptorProto, FileDescriptorProto, FileOptions,
|
|
ServiceDescriptorProto, SourceCodeInfo,
|
|
};
|
|
use std::collections::HashMap;
|
|
use thiserror::Error;
|
|
|
|
#[derive(Error, Debug)]
|
|
pub enum ConverterError {
|
|
#[error("Proto decoding error")]
|
|
DecodeError(#[from] prost::DecodeError),
|
|
#[error("Internal extend error")]
|
|
ExtendError(#[from] extend::ExtendError),
|
|
#[error("{0}")]
|
|
GenericError(String),
|
|
}
|
|
|
|
enum Syntax {
|
|
Proto2,
|
|
Proto3,
|
|
}
|
|
|
|
pub fn process_file_descriptor_set(
|
|
file_descriptor_set_data: &[u8],
|
|
) -> Result<HashMap<String, String>, ConverterError> {
|
|
let mut descriptors = HashMap::new();
|
|
let file_descriptor_set = prost_types::FileDescriptorSet::decode(file_descriptor_set_data)?;
|
|
for descriptor_proto in &file_descriptor_set.file {
|
|
let (file_name, content) = process_file_descriptor(descriptor_proto)?;
|
|
descriptors.insert(file_name, content);
|
|
}
|
|
Ok(descriptors)
|
|
}
|
|
|
|
fn process_file_descriptor(
|
|
descriptor: &FileDescriptorProto,
|
|
) -> Result<(String, String), ConverterError> {
|
|
let mut buffer = String::with_capacity(1024 * 1024); // 1MB
|
|
let syntax = process_version(&mut buffer, descriptor.syntax.as_ref());
|
|
let name = descriptor.name().to_string();
|
|
process_package(&mut buffer, descriptor.package.as_ref());
|
|
|
|
if let Some(options) = &descriptor.options {
|
|
process_options(&mut buffer, options)?;
|
|
}
|
|
|
|
for dependency in &descriptor.dependency {
|
|
buffer.push_str(format!("import \"{dependency}\";\n").as_str());
|
|
}
|
|
buffer.push('\n');
|
|
|
|
// TODO: Hande public_dependency and weak_dependency
|
|
|
|
process_enum(&mut buffer, &descriptor.enum_type)?;
|
|
process_message(
|
|
&mut buffer,
|
|
&syntax,
|
|
&descriptor.message_type,
|
|
descriptor.package.as_ref(),
|
|
)?;
|
|
process_service(&mut buffer, &descriptor.service)?;
|
|
process_extension(&mut buffer, &descriptor.extension)?;
|
|
|
|
if let Some(source_code_info) = &descriptor.source_code_info {
|
|
process_source_code_info(&mut buffer, source_code_info)?;
|
|
}
|
|
|
|
Ok((name, buffer))
|
|
}
|
|
|
|
fn process_version(buffer: &mut String, syntax: Option<&String>) -> Syntax {
|
|
// According to google, if no edition or syntax is specified, one shall default to proto2
|
|
let syntax = syntax.cloned().unwrap_or("proto2".to_string());
|
|
buffer.push_str(format!("syntax = \"{syntax}\";\n\n").as_str());
|
|
match syntax.as_str() {
|
|
"proto3" => Syntax::Proto3,
|
|
_ => Syntax::Proto2,
|
|
}
|
|
}
|
|
|
|
fn process_package(buffer: &mut String, package: Option<&String>) {
|
|
if let Some(package) = package {
|
|
buffer.push_str(format!("package {package};\n\n").as_str());
|
|
}
|
|
}
|
|
|
|
fn process_message(
|
|
buffer: &mut String,
|
|
syntax: &Syntax,
|
|
messages: &[DescriptorProto],
|
|
package: Option<&String>,
|
|
) -> Result<(), ConverterError> {
|
|
for message in messages {
|
|
buffer.push_str(format!("message {} {{\n", message.name()).as_str());
|
|
for field in &message.field {
|
|
buffer.push('\t');
|
|
// TODO: use label to know if optional shall be used
|
|
match field.label() {
|
|
Label::Optional => buffer.push_str("optional "),
|
|
Label::Required => match syntax {
|
|
Syntax::Proto2 => buffer.push_str("required "),
|
|
Syntax::Proto3 => {}
|
|
},
|
|
Label::Repeated => buffer.push_str("repeated "),
|
|
}
|
|
buffer.push_str(field.r#type().as_str_type(field.type_name.as_ref())?);
|
|
buffer.push_str(format!(" {} = {}", field.name(), field.number()).as_str());
|
|
|
|
if let Some(extendee) = &field.extendee {
|
|
// TODO: Handle extendee
|
|
return Err(ConverterError::GenericError(format!(
|
|
"Descriptor extendee is not supported {extendee:?}"
|
|
)));
|
|
}
|
|
|
|
if let Some(default_value) = &field.default_value {
|
|
// TODO: Handle default_value
|
|
return Err(ConverterError::GenericError(format!(
|
|
"Descriptor default_value is not supported {default_value:?}"
|
|
)));
|
|
}
|
|
|
|
if let Some(oneof_index) = &field.oneof_index {
|
|
// TODO: Handle oneof_index
|
|
return Err(ConverterError::GenericError(format!(
|
|
"Descriptor oneof_index is not supported {oneof_index:?}"
|
|
)));
|
|
}
|
|
|
|
if let Some(json_name) = &field.json_name {
|
|
buffer.push_str(format!(" [json_name=\"{json_name}\"]").as_str());
|
|
}
|
|
buffer.push_str(";\n");
|
|
}
|
|
process_extension(buffer, &message.extension)?;
|
|
// TODO: We might require indentation without external tool
|
|
process_message(buffer, syntax, &message.nested_type, package)?;
|
|
// TODO: We might require indentation without external tool
|
|
process_enum(buffer, &message.enum_type)?;
|
|
|
|
if !message.extension_range.is_empty() {
|
|
// TODO: Handle extension_range
|
|
return Err(ConverterError::GenericError(format!(
|
|
"Descriptor extension_range is not supported {:?}",
|
|
message.extension_range
|
|
)));
|
|
}
|
|
|
|
if !message.oneof_decl.is_empty() {
|
|
// TODO: Handle oneof_decl
|
|
return Err(ConverterError::GenericError(format!(
|
|
"Descriptor oneof_decl is not supported {:?}",
|
|
message.oneof_decl
|
|
)));
|
|
}
|
|
|
|
if let Some(options) = &message.options {
|
|
// TODO: Handle options
|
|
return Err(ConverterError::GenericError(format!(
|
|
"Descriptor options is not supported {options:?}"
|
|
)));
|
|
}
|
|
|
|
if !message.reserved_range.is_empty() {
|
|
// TODO: Handle reserved_range
|
|
return Err(ConverterError::GenericError(format!(
|
|
"Descriptor reserved_range is not supported {:?}",
|
|
message.reserved_range
|
|
)));
|
|
}
|
|
|
|
if !message.reserved_name.is_empty() {
|
|
// TODO: Handle reserved_name
|
|
return Err(ConverterError::GenericError(format!(
|
|
"Descriptor reserved_name is not supported {:?}",
|
|
message.reserved_name
|
|
)));
|
|
}
|
|
|
|
buffer.push_str("}\n\n");
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn process_enum(buffer: &mut String, enums: &[EnumDescriptorProto]) -> Result<(), ConverterError> {
|
|
for enum_descriptor in enums {
|
|
buffer.push_str(format!("enum {} {{\n", enum_descriptor.name()).as_str());
|
|
for variant in &enum_descriptor.value {
|
|
buffer.push_str(format!("\t{} = {};\n", variant.name(), variant.number()).as_str());
|
|
if let Some(options) = &variant.options {
|
|
// TODO: Handle options
|
|
return Err(ConverterError::GenericError(format!(
|
|
"Descriptor options is not supported {options:?}"
|
|
)));
|
|
}
|
|
}
|
|
|
|
if let Some(options) = &enum_descriptor.options {
|
|
// TODO: Handle options
|
|
return Err(ConverterError::GenericError(format!(
|
|
"Descriptor options is not supported {options:?}"
|
|
)));
|
|
}
|
|
|
|
if !enum_descriptor.reserved_range.is_empty() {
|
|
// TODO: Handle reserved_range
|
|
return Err(ConverterError::GenericError(format!(
|
|
"Descriptor reserved_range is not supported {:?}",
|
|
enum_descriptor.reserved_range
|
|
)));
|
|
}
|
|
|
|
if !enum_descriptor.reserved_name.is_empty() {
|
|
// TODO: Handle reserved_name
|
|
return Err(ConverterError::GenericError(format!(
|
|
"Descriptor reserved_name is not supported {:?}",
|
|
enum_descriptor.reserved_name
|
|
)));
|
|
}
|
|
|
|
buffer.push_str("}\n\n");
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn process_service(
|
|
_buffer: &mut String,
|
|
services: &[ServiceDescriptorProto],
|
|
) -> Result<(), ConverterError> {
|
|
if !services.is_empty() {
|
|
// TODO: Handle service
|
|
return Err(ConverterError::GenericError(format!(
|
|
"Descriptor service is not supported {services:?}"
|
|
)));
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn process_options(_buffer: &mut String, options: &FileOptions) -> Result<(), ConverterError> {
|
|
// TODO: Handle options
|
|
Err(ConverterError::GenericError(format!(
|
|
"Descriptor options is not supported {options:?}"
|
|
)))
|
|
}
|
|
|
|
fn process_extension(
|
|
_buffer: &mut String,
|
|
extension: &[FieldDescriptorProto],
|
|
) -> Result<(), ConverterError> {
|
|
if !extension.is_empty() {
|
|
// TODO: Handle extension
|
|
return Err(ConverterError::GenericError(format!(
|
|
"Descriptor extension is not supported {extension:?}"
|
|
)));
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn process_source_code_info(
|
|
_buffer: &mut String,
|
|
source_code_info: &SourceCodeInfo,
|
|
) -> Result<(), ConverterError> {
|
|
// TODO: Handle source_code_info
|
|
Err(ConverterError::GenericError(format!(
|
|
"Descriptor source_code_info is not supported {source_code_info:?}"
|
|
)))
|
|
}
|