use protobuf::descriptor::DescriptorProto;
use protobuf::descriptor::EnumDescriptorProto;
use protobuf::descriptor::EnumValueDescriptorProto;
use protobuf::descriptor::FieldDescriptorProto;
use protobuf::descriptor::FileDescriptorProto;
use protobuf::descriptor::MethodDescriptorProto;
use protobuf::descriptor::OneofDescriptorProto;
use protobuf::descriptor::ServiceDescriptorProto;
use protobuf::reflect::FieldDescriptor;
use protobuf::reflect::FileDescriptor;
use protobuf::reflect::MessageDescriptor;
use protobuf::MessageFull;
use protobuf::UnknownFields;
use protobuf::UnknownValue;
use protobuf_support::lexer::str_lit::StrLitDecodeError;
use crate::model;
use crate::model::ProtobufConstant;
use crate::model::ProtobufConstantMessage;
use crate::model::ProtobufConstantMessageFieldName;
use crate::model::ProtobufOptionName;
use crate::model::ProtobufOptionNameExt;
use crate::model::ProtobufOptionNamePart;
use crate::model::WithLoc;
use crate::protobuf_path::ProtobufPath;
use crate::pure::convert::Resolver;
use crate::pure::convert::TypeResolved;
use crate::ProtobufAbsPath;
use crate::ProtobufAbsPathRef;
use crate::ProtobufIdent;
use crate::ProtobufIdentRef;
use crate::ProtobufRelPath;
use crate::ProtobufRelPathRef;
#[derive(Debug, thiserror::Error)]
enum OptionResolverError {
#[error(transparent)]
OtherError(anyhow::Error),
#[error("extension is not a message: {0}")]
ExtensionIsNotMessage(String),
#[error("unknown field name: {0}")]
UnknownFieldName(String),
#[error("wrong extension type: option {0} extendee {1} expected extendee {2}")]
WrongExtensionType(String, String, String),
#[error("extension not found: {0}")]
ExtensionNotFound(String),
#[error("unknown enum value: {0}")]
UnknownEnumValue(String),
#[error("unsupported extension type: {0} {1} {2}")]
UnsupportedExtensionType(String, String, model::ProtobufConstant),
#[error("builtin option {0} not found for options {1}")]
BuiltinOptionNotFound(String, String),
#[error("builtin option {0} points to a non-singular field of {1}")]
BuiltinOptionPointsToNonSingularField(String, String),
#[error("incorrect string literal: {0}")]
StrLitDecodeError(#[source] StrLitDecodeError),
#[error("wrong option type, expecting {0}, got `{1}`")]
WrongOptionType(&'static str, String),
#[error("Message field requires a message constant")]
MessageFieldRequiresMessageConstant,
#[error("message not found by name {0}")]
MessageNotFound(ProtobufAbsPath),
#[error("message not found by name {0}")]
MessageFoundMoreThanOnce(ProtobufAbsPath),
}
#[derive(Clone)]
enum LookupScope2 {
File(FileDescriptor),
Message(MessageDescriptor, ProtobufAbsPath),
}
impl LookupScope2 {
fn current_path(&self) -> ProtobufAbsPath {
match self {
LookupScope2::File(f) => ProtobufAbsPath::package_from_file_descriptor(f),
LookupScope2::Message(_, p) => p.clone(),
}
}
fn messages(&self) -> Vec<MessageDescriptor> {
match self {
LookupScope2::File(file) => file.messages().collect(),
LookupScope2::Message(message, _) => message.nested_messages().collect(),
}
}
fn down(&self, name: &ProtobufIdentRef) -> Option<LookupScope2> {
match self.messages().iter().find(|m| m.name() == name.as_str()) {
Some(m) => {
let mut path = self.current_path();
path.push_simple(name);
Some(LookupScope2::Message(m.clone(), path))
}
None => None,
}
}
fn extensions(&self) -> Vec<FieldDescriptor> {
match self {
LookupScope2::File(f) => f.extensions().collect(),
LookupScope2::Message(m, _) => m.extensions().collect(),
}
}
}
#[derive(Clone)]
pub(crate) struct LookupScopeUnion2 {
path: ProtobufAbsPath,
scopes: Vec<LookupScope2>,
partial_scopes: Vec<FileDescriptor>,
}
impl LookupScopeUnion2 {
fn down(&self, name: &ProtobufIdentRef) -> LookupScopeUnion2 {
let mut path: ProtobufAbsPath = self.path.clone();
path.push_simple(name);
let mut scopes: Vec<_> = self.scopes.iter().flat_map(|f| f.down(name)).collect();
let mut partial_scopes = Vec::new();
for partial_scope in &self.partial_scopes {
let package = ProtobufAbsPath::package_from_file_descriptor(partial_scope);
if package.as_ref() == path.as_ref() {
scopes.push(LookupScope2::File(partial_scope.clone()));
} else if package.starts_with(&path) {
partial_scopes.push(partial_scope.clone());
}
}
LookupScopeUnion2 {
path,
scopes,
partial_scopes,
}
}
fn lookup(&self, path: &ProtobufRelPath) -> LookupScopeUnion2 {
let mut scope = self.clone();
for c in path.components() {
scope = scope.down(c);
}
scope
}
fn extensions(&self) -> Vec<FieldDescriptor> {
self.scopes.iter().flat_map(|s| s.extensions()).collect()
}
fn as_message(&self) -> anyhow::Result<MessageDescriptor> {
let mut messages: Vec<MessageDescriptor> = self
.scopes
.iter()
.filter_map(|s| match s {
LookupScope2::Message(m, _) => Some(m.clone()),
_ => None,
})
.collect();
let message = match messages.pop() {
Some(m) => m,
None => return Err(OptionResolverError::MessageNotFound(self.path.clone()).into()),
};
if !messages.is_empty() {
return Err(OptionResolverError::MessageFoundMoreThanOnce(self.path.clone()).into());
}
Ok(message)
}
}
pub(crate) trait ProtobufOptions {
fn by_name(&self, name: &str) -> Option<&model::ProtobufConstant>;
fn _by_name_bool(&self, name: &str) -> anyhow::Result<Option<bool>> {
match self.by_name(name) {
Some(model::ProtobufConstant::Bool(b)) => Ok(Some(*b)),
Some(c) => Err(OptionResolverError::WrongOptionType("bool", c.to_string()).into()),
None => Ok(None),
}
}
fn by_name_string(&self, name: &str) -> anyhow::Result<Option<String>> {
match self.by_name(name) {
Some(model::ProtobufConstant::String(s)) => s
.decode_utf8()
.map(Some)
.map_err(|e| OptionResolverError::StrLitDecodeError(e).into()),
Some(c) => Err(OptionResolverError::WrongOptionType("string", c.to_string()).into()),
None => Ok(None),
}
}
}
impl<'a> ProtobufOptions for &'a [model::ProtobufOption] {
fn by_name(&self, name: &str) -> Option<&model::ProtobufConstant> {
let option_name = ProtobufOptionName::simple(name);
for model::ProtobufOption { name, value } in *self {
if name == &option_name {
return Some(&value);
}
}
None
}
}
pub(crate) struct OptionResoler<'a> {
pub(crate) resolver: &'a Resolver<'a>,
pub(crate) descriptor_without_options: FileDescriptor,
}
impl<'a> OptionResoler<'a> {
fn all_files(&self) -> Vec<FileDescriptor> {
let mut files = Vec::new();
files.push(self.descriptor_without_options.clone());
files.extend(
self.resolver
.type_resolver
.deps
.iter()
.map(|p| p.descriptor.clone()),
);
files
}
fn root_scope(&self) -> LookupScopeUnion2 {
let (scopes, partial_scopes) = self
.all_files()
.into_iter()
.partition::<Vec<_>, _>(|f| ProtobufAbsPath::package_from_file_descriptor(f).is_root());
LookupScopeUnion2 {
path: ProtobufAbsPath::root(),
scopes: scopes.into_iter().map(LookupScope2::File).collect(),
partial_scopes,
}
}
fn lookup(&self, path: &ProtobufAbsPath) -> LookupScopeUnion2 {
self.root_scope().lookup(&path.to_root_rel())
}
fn find_message_by_abs_name(
&self,
path: &ProtobufAbsPath,
) -> anyhow::Result<MessageDescriptor> {
let scope = self.lookup(path);
scope.as_message()
}
fn scope_resolved_candidates_rel(
scope: &ProtobufAbsPathRef,
rel: &ProtobufRelPathRef,
) -> Vec<ProtobufAbsPath> {
scope
.self_and_parents()
.into_iter()
.map(|a| {
let mut a = a.to_owned();
a.push_relative(rel);
a
})
.collect()
}
fn scope_resolved_candidates(
scope: &ProtobufAbsPathRef,
path: &ProtobufPath,
) -> Vec<ProtobufAbsPath> {
match path {
ProtobufPath::Abs(p) => vec![p.clone()],
ProtobufPath::Rel(p) => Self::scope_resolved_candidates_rel(scope, p),
}
}
fn find_extension_by_abs_path(
&self,
path: &ProtobufAbsPathRef,
) -> anyhow::Result<Option<FieldDescriptor>> {
let mut path = path.to_owned();
let extension = path.pop().unwrap();
let scope = self.lookup(&path);
for ext in scope.extensions() {
if ext.name() == extension.get() {
return Ok(Some(ext.clone()));
}
}
Ok(None)
}
fn find_extension_by_path(
&self,
scope: &ProtobufAbsPathRef,
path: &ProtobufPath,
) -> anyhow::Result<FieldDescriptor> {
for candidate in Self::scope_resolved_candidates(scope, path) {
if let Some(e) = self.find_extension_by_abs_path(&candidate)? {
return Ok(e);
}
}
Err(OptionResolverError::ExtensionNotFound(path.to_string()).into())
}
fn ext_resolve_field_ext(
&self,
scope: &ProtobufAbsPathRef,
message: &MessageDescriptor,
field_name: &ProtobufPath,
) -> anyhow::Result<FieldDescriptor> {
let expected_extendee = ProtobufAbsPath::from_message(message);
let field = self.find_extension_by_path(scope, field_name)?;
if ProtobufAbsPath::new(field.proto().extendee()) != expected_extendee {
return Err(OptionResolverError::WrongExtensionType(
format!("{}", field_name),
format!("{}", field.proto().extendee()),
format!("{}", expected_extendee),
)
.into());
}
Ok(field)
}
fn ext_resolve_field(
&self,
scope: &ProtobufAbsPathRef,
message: &MessageDescriptor,
field: &ProtobufOptionNamePart,
) -> anyhow::Result<FieldDescriptor> {
match field {
ProtobufOptionNamePart::Direct(field) => match message.field_by_name(field.get()) {
Some(field) => Ok(field),
None => Err(OptionResolverError::UnknownFieldName(field.to_string()).into()),
},
ProtobufOptionNamePart::Ext(field) => {
Ok(self.ext_resolve_field_ext(scope, message, field)?)
}
}
}
fn custom_option_ext_step(
&self,
scope: &ProtobufAbsPathRef,
options_type: &MessageDescriptor,
unknown_fields: &mut UnknownFields,
option_name: &ProtobufOptionNamePart,
option_name_rem: &[ProtobufOptionNamePart],
option_value: &ProtobufConstant,
) -> anyhow::Result<()> {
let field = self.ext_resolve_field(scope, options_type, option_name)?;
let field_type = TypeResolved::from_field(field.proto());
match option_name_rem.split_first() {
Some((first, rem)) => {
match field_type {
TypeResolved::Message(message_name) => {
let m = self.find_message_by_abs_name(&message_name)?;
let mut message_unknown_fields = UnknownFields::new();
self.custom_option_ext_step(
scope,
&m,
&mut message_unknown_fields,
first,
rem,
option_value,
)?;
unknown_fields.add_length_delimited(
field.proto().number() as u32,
message_unknown_fields.write_to_bytes(),
);
Ok(())
}
TypeResolved::Group(..) => {
Ok(())
}
_ => Err(OptionResolverError::ExtensionIsNotMessage(format!(
"scope: {}, option name: {}",
scope, option_name
))
.into()),
}
}
None => self
.add_option_value_to_unknown_fields(
&field_type,
field.number() as u32,
unknown_fields,
option_value,
&format!("{}", option_name),
)
.map_err(|err| {
err.context(format!(
"parsing custom option `{}` value `{}` at `{}`",
option_name, option_value, scope
))
}),
}
}
fn add_option_value_to_unknown_fields(
&self,
field_type: &TypeResolved,
field_num: u32,
unknown_fields: &mut UnknownFields,
option_value: &ProtobufConstant,
option_name_for_diag: &str,
) -> anyhow::Result<()> {
let error = || {
OptionResolverError::UnsupportedExtensionType(
option_name_for_diag.to_owned(),
format!("{:?}", field_type),
option_value.clone(),
)
};
match option_value {
ProtobufConstant::U64(v) => match field_type {
TypeResolved::Fixed64 => unknown_fields.add_value(field_num, Self::fixed64(*v)?),
TypeResolved::Sfixed64 => unknown_fields.add_value(field_num, Self::sfixed64(*v)?),
TypeResolved::Fixed32 => unknown_fields.add_value(field_num, Self::fixed32(*v)?),
TypeResolved::Sfixed32 => unknown_fields.add_value(field_num, Self::sfixed32(*v)?),
TypeResolved::Int32 => unknown_fields.add_value(field_num, Self::int32(*v)?),
TypeResolved::Int64 => unknown_fields.add_value(field_num, Self::int64(*v)?),
TypeResolved::Uint64 => unknown_fields.add_value(field_num, Self::uint64(*v)?),
TypeResolved::Uint32 => unknown_fields.add_value(field_num, Self::uint32(*v)?),
TypeResolved::Sint64 => unknown_fields.add_value(field_num, Self::sint64(*v)?),
TypeResolved::Sint32 => unknown_fields.add_value(field_num, Self::sint32(*v)?),
TypeResolved::Float => {
unknown_fields.add_value(field_num, UnknownValue::float(*v as f32))
}
TypeResolved::Double => {
unknown_fields.add_value(field_num, UnknownValue::double(*v as f64))
}
_ => return Err(error().into()),
},
ProtobufConstant::I64(v) => match field_type {
TypeResolved::Fixed64 => unknown_fields.add_value(field_num, Self::fixed64(*v)?),
TypeResolved::Sfixed64 => unknown_fields.add_value(field_num, Self::sfixed64(*v)?),
TypeResolved::Fixed32 => unknown_fields.add_value(field_num, Self::fixed32(*v)?),
TypeResolved::Sfixed32 => unknown_fields.add_value(field_num, Self::sfixed32(*v)?),
TypeResolved::Int32 => unknown_fields.add_value(field_num, Self::int32(*v)?),
TypeResolved::Int64 => unknown_fields.add_value(field_num, Self::int64(*v)?),
TypeResolved::Uint64 => unknown_fields.add_value(field_num, Self::uint64(*v)?),
TypeResolved::Uint32 => unknown_fields.add_value(field_num, Self::uint32(*v)?),
TypeResolved::Sint64 => unknown_fields.add_value(field_num, Self::sint64(*v)?),
TypeResolved::Sint32 => unknown_fields.add_value(field_num, Self::sint32(*v)?),
TypeResolved::Float => {
unknown_fields.add_value(field_num, UnknownValue::float(*v as f32))
}
TypeResolved::Double => {
unknown_fields.add_value(field_num, UnknownValue::double(*v as f64))
}
_ => return Err(error().into()),
},
ProtobufConstant::F64(f) => match field_type {
TypeResolved::Float => {
unknown_fields.add_value(field_num, UnknownValue::float(*f as f32))
}
TypeResolved::Double => {
unknown_fields.add_value(field_num, UnknownValue::double(*f))
}
TypeResolved::Fixed32 => {
unknown_fields.add_value(field_num, UnknownValue::Fixed32(*f as u32))
}
TypeResolved::Fixed64 => {
unknown_fields.add_value(field_num, UnknownValue::Fixed64(*f as u64))
}
TypeResolved::Sfixed32 => {
unknown_fields.add_value(field_num, UnknownValue::sfixed32(*f as i32))
}
TypeResolved::Sfixed64 => {
unknown_fields.add_value(field_num, UnknownValue::sfixed64(*f as i64))
}
TypeResolved::Sint64 => {
unknown_fields.add_value(field_num, UnknownValue::sint64(*f as i64))
}
TypeResolved::Sint32 => {
unknown_fields.add_value(field_num, UnknownValue::sint32(*f as i32))
}
TypeResolved::Int32 | TypeResolved::Int64 => {
unknown_fields.add_value(field_num, UnknownValue::int64(*f as i64))
}
TypeResolved::Uint32 | TypeResolved::Uint64 => {
unknown_fields.add_value(field_num, UnknownValue::Varint(*f as u64))
}
_ => return Err(error().into()),
},
ProtobufConstant::Bool(b) => match field_type {
TypeResolved::Bool => unknown_fields
.add_value(field_num, UnknownValue::Varint(if *b { 1 } else { 0 })),
_ => return Err(error().into()),
},
ProtobufConstant::Ident(ident) => match field_type {
TypeResolved::Enum(abs_path) => {
let n = self
.resolver
.find_enum_by_abs_name(abs_path)
.map_err(OptionResolverError::OtherError)?
.values
.iter()
.find(|v| v.name == ident.to_string())
.map(|v| v.number)
.ok_or_else(|| OptionResolverError::UnknownEnumValue(ident.to_string()))?;
unknown_fields.add_value(field_num, UnknownValue::int32(n));
}
_ => return Err(error().into()),
},
ProtobufConstant::String(s) => match field_type {
TypeResolved::String => unknown_fields.add_value(
field_num,
UnknownValue::LengthDelimited(s.decode_utf8()?.into_bytes()),
),
TypeResolved::Bytes => unknown_fields
.add_value(field_num, UnknownValue::LengthDelimited(s.decode_bytes()?)),
_ => return Err(error().into()),
},
ProtobufConstant::Message(message) => self.add_option_value_message_to_unknown_fields(
field_type,
field_num,
unknown_fields,
message,
&option_name_for_diag,
)?,
ProtobufConstant::Repeated(list) => {
for v in list {
self.add_option_value_to_unknown_fields(
field_type,
field_num,
unknown_fields,
v,
option_name_for_diag,
)?
}
}
}
Ok(())
}
fn custom_option_ext<M>(
&self,
scope: &ProtobufAbsPathRef,
options: &mut M,
option_name: &ProtobufOptionNameExt,
option_value: &ProtobufConstant,
) -> anyhow::Result<()>
where
M: MessageFull,
{
self.custom_option_ext_step(
scope,
&M::descriptor(),
options.mut_unknown_fields(),
&option_name.0[0],
&option_name.0[1..],
option_value,
)
}
fn fixed32(
v: impl TryInto<u32, Error = impl std::error::Error + Send + Sync + 'static>,
) -> anyhow::Result<UnknownValue> {
Ok(UnknownValue::Fixed32(v.try_into()?))
}
fn sfixed32(
v: impl TryInto<i32, Error = impl std::error::Error + Send + Sync + 'static>,
) -> anyhow::Result<UnknownValue> {
Ok(UnknownValue::sfixed32(v.try_into()?))
}
fn fixed64(
v: impl TryInto<u64, Error = impl std::error::Error + Send + Sync + 'static>,
) -> anyhow::Result<UnknownValue> {
Ok(UnknownValue::Fixed64(v.try_into()?))
}
fn sfixed64(
v: impl TryInto<i64, Error = impl std::error::Error + Send + Sync + 'static>,
) -> anyhow::Result<UnknownValue> {
Ok(UnknownValue::sfixed64(v.try_into()?))
}
fn int32(
v: impl TryInto<i32, Error = impl std::error::Error + Send + Sync + 'static>,
) -> anyhow::Result<UnknownValue> {
Ok(UnknownValue::int32(v.try_into()?))
}
fn int64(
v: impl TryInto<i64, Error = impl std::error::Error + Send + Sync + 'static>,
) -> anyhow::Result<UnknownValue> {
Ok(UnknownValue::int64(v.try_into()?))
}
fn uint32(
v: impl TryInto<u32, Error = impl std::error::Error + Send + Sync + 'static>,
) -> anyhow::Result<UnknownValue> {
Ok(UnknownValue::Varint(v.try_into()? as u64))
}
fn uint64(
v: impl TryInto<u64, Error = impl std::error::Error + Send + Sync + 'static>,
) -> anyhow::Result<UnknownValue> {
Ok(UnknownValue::Varint(v.try_into()?))
}
fn sint32(
v: impl TryInto<i32, Error = impl std::error::Error + Send + Sync + 'static>,
) -> anyhow::Result<UnknownValue> {
Ok(UnknownValue::sint32(v.try_into()?))
}
fn sint64(
v: impl TryInto<i64, Error = impl std::error::Error + Send + Sync + 'static>,
) -> anyhow::Result<UnknownValue> {
Ok(UnknownValue::sint64(v.try_into()?))
}
fn add_option_value_message_to_unknown_fields(
&self,
field_type: &TypeResolved,
field_num: u32,
options: &mut UnknownFields,
option_value: &ProtobufConstantMessage,
option_name_for_diag: &str,
) -> anyhow::Result<()> {
match &field_type {
TypeResolved::Message(ma) => {
let m = self
.resolver
.find_message_by_abs_name(ma)
.map_err(OptionResolverError::OtherError)?
.t;
let mut unknown_fields = UnknownFields::new();
for (n, v) in &option_value.fields {
match n {
ProtobufConstantMessageFieldName::Regular(n) => {
let field = m
.field_by_name(n.as_str())
.ok_or_else(|| OptionResolverError::UnknownFieldName(n.clone()))?;
let field_type = self.resolver.field_type(&ma, n, &field.typ)?;
self.add_option_value_to_unknown_fields(
&field_type,
field.number as u32,
&mut unknown_fields,
v,
option_name_for_diag,
)
.map_err(OptionResolverError::OtherError)?;
}
ProtobufConstantMessageFieldName::Extension(..) => {
}
ProtobufConstantMessageFieldName::AnyTypeUrl(..) => {
}
}
}
options.add_value(
field_num,
UnknownValue::LengthDelimited(unknown_fields.write_to_bytes()),
);
Ok(())
}
_ => Err(OptionResolverError::MessageFieldRequiresMessageConstant.into()),
}
}
fn custom_option_builtin<M>(
&self,
_scope: &ProtobufAbsPathRef,
options: &mut M,
option: &ProtobufIdent,
option_value: &ProtobufConstant,
) -> anyhow::Result<()>
where
M: MessageFull,
{
if M::descriptor().full_name() == "google.protobuf.FieldOptions" {
if option.get() == "default" || option.get() == "json_name" {
return Ok(());
}
}
match M::descriptor().field_by_name(option.get()) {
Some(field) => {
if field.is_repeated_or_map() {
return Err(OptionResolverError::BuiltinOptionPointsToNonSingularField(
M::descriptor().full_name().to_owned(),
option.get().to_owned(),
)
.into());
}
field.set_singular_field(
options,
option_value.as_type(field.singular_runtime_type())?,
);
return Ok(());
}
None => {
return Err(OptionResolverError::BuiltinOptionNotFound(
M::descriptor().full_name().to_owned(),
option.get().to_owned(),
)
.into())
}
}
}
fn custom_option<M>(
&self,
scope: &ProtobufAbsPathRef,
options: &mut M,
option: &model::ProtobufOption,
) -> anyhow::Result<()>
where
M: MessageFull,
{
match &option.name {
ProtobufOptionName::Builtin(simple) => {
self.custom_option_builtin(scope, options, simple, &option.value)
}
ProtobufOptionName::Ext(e) => self.custom_option_ext(scope, options, e, &option.value),
}
}
fn custom_options<M>(
&self,
scope: &ProtobufAbsPathRef,
input: &[model::ProtobufOption],
) -> anyhow::Result<Option<M>>
where
M: MessageFull,
{
if input.is_empty() {
return Ok(None);
}
let mut options = M::new();
for option in input {
self.custom_option(scope, &mut options, option)?;
}
Ok(Some(options))
}
fn file_options(
&self,
scope: &ProtobufAbsPath,
input: &[model::ProtobufOption],
) -> anyhow::Result<Option<protobuf::descriptor::FileOptions>> {
self.custom_options(scope, input)
}
fn enum_options(
&self,
scope: &ProtobufAbsPathRef,
input: &[model::ProtobufOption],
) -> anyhow::Result<Option<protobuf::descriptor::EnumOptions>> {
self.custom_options(scope, input)
}
fn enum_value_options(
&self,
scope: &ProtobufAbsPathRef,
input: &[model::ProtobufOption],
) -> anyhow::Result<Option<protobuf::descriptor::EnumValueOptions>> {
self.custom_options(scope, input)
}
fn field_options(
&self,
scope: &ProtobufAbsPathRef,
input: &[model::ProtobufOption],
) -> anyhow::Result<Option<protobuf::descriptor::FieldOptions>> {
self.custom_options(scope, input)
}
fn message_options(
&self,
scope: &ProtobufAbsPathRef,
input: &[model::ProtobufOption],
) -> anyhow::Result<Option<protobuf::descriptor::MessageOptions>> {
self.custom_options(scope, input)
}
fn oneof_options(
&self,
scope: &ProtobufAbsPathRef,
input: &[model::ProtobufOption],
) -> anyhow::Result<Option<protobuf::descriptor::OneofOptions>> {
self.custom_options(scope, input)
}
fn method(
&self,
method_proto: &mut MethodDescriptorProto,
method_model: &model::Method,
) -> anyhow::Result<()> {
method_proto.options = self.service_method_options(&method_model.options)?.into();
Ok(())
}
fn service_options(
&self,
input: &[model::ProtobufOption],
) -> anyhow::Result<Option<protobuf::descriptor::ServiceOptions>> {
self.custom_options(&self.resolver.current_file.package, input)
}
fn service_method_options(
&self,
input: &[model::ProtobufOption],
) -> anyhow::Result<Option<protobuf::descriptor::MethodOptions>> {
self.custom_options(&self.resolver.current_file.package, input)
}
fn service(
&self,
service_proto: &mut ServiceDescriptorProto,
service_model: &WithLoc<model::Service>,
) -> anyhow::Result<()> {
service_proto.options = self.service_options(&service_model.options)?.into();
for service_method_model in &service_model.methods {
let mut method_proto = service_proto
.method
.iter_mut()
.find(|method| method.name() == service_method_model.name)
.unwrap();
self.method(&mut method_proto, service_method_model)?;
}
Ok(())
}
fn enum_value(
&self,
scope: &ProtobufAbsPathRef,
enum_value_proto: &mut EnumValueDescriptorProto,
enum_value_model: &model::EnumValue,
) -> anyhow::Result<()> {
enum_value_proto.options = self
.enum_value_options(scope, &enum_value_model.options)?
.into();
Ok(())
}
fn enumeration(
&self,
scope: &ProtobufAbsPathRef,
enum_proto: &mut EnumDescriptorProto,
enum_model: &WithLoc<model::Enumeration>,
) -> anyhow::Result<()> {
enum_proto.options = self.enum_options(scope, &enum_model.options)?.into();
for enum_value_model in &enum_model.values {
let mut enum_value_proto = enum_proto
.value
.iter_mut()
.find(|v| v.name() == enum_value_model.name)
.unwrap();
self.enum_value(scope, &mut enum_value_proto, enum_value_model)?;
}
Ok(())
}
fn oneof(
&self,
scope: &ProtobufAbsPathRef,
oneof_proto: &mut OneofDescriptorProto,
oneof_model: &model::OneOf,
) -> anyhow::Result<()> {
oneof_proto.options = self.oneof_options(scope, &oneof_model.options)?.into();
Ok(())
}
fn field(
&self,
scope: &ProtobufAbsPathRef,
field_proto: &mut FieldDescriptorProto,
field_model: &model::Field,
) -> anyhow::Result<()> {
field_proto.options = self.field_options(scope, &field_model.options)?.into();
Ok(())
}
fn message(
&self,
scope: &ProtobufAbsPathRef,
message_proto: &mut DescriptorProto,
message_model: &WithLoc<model::Message>,
) -> anyhow::Result<()> {
message_proto.options = self.message_options(scope, &message_model.options)?.into();
let mut nested_scope = scope.to_owned();
nested_scope.push_simple(ProtobufIdentRef::new(&message_proto.name()));
for field_model in &message_model.regular_fields_including_in_oneofs() {
let mut field_proto = message_proto
.field
.iter_mut()
.find(|field| field.name() == field_model.name)
.unwrap();
self.field(&nested_scope, &mut field_proto, field_model)?;
}
for field_model in &message_model.extensions {
let field_proto = message_proto
.extension
.iter_mut()
.find(|field| field.name() == field_model.field.name)
.unwrap();
self.field(&nested_scope, field_proto, &field_model.field)?;
}
for nested_message_model in &message_model.messages {
let nested_message_proto = message_proto
.nested_type
.iter_mut()
.find(|nested_message_proto| {
nested_message_proto.name() == nested_message_model.name
})
.unwrap();
self.message(&nested_scope, nested_message_proto, nested_message_model)?;
}
for nested_enum_model in &message_model.enums {
let nested_enum_proto = message_proto
.enum_type
.iter_mut()
.find(|nested_enum_proto| nested_enum_proto.name() == nested_enum_model.name)
.unwrap();
self.enumeration(&nested_scope, nested_enum_proto, nested_enum_model)?;
}
for oneof_model in &message_model.oneofs() {
let oneof_proto = message_proto
.oneof_decl
.iter_mut()
.find(|oneof_proto| oneof_proto.name() == oneof_model.name)
.unwrap();
self.oneof(&nested_scope, oneof_proto, oneof_model)?;
}
Ok(())
}
pub(crate) fn file(&self, output: &mut FileDescriptorProto) -> anyhow::Result<()> {
let _ = &self.descriptor_without_options;
for message_model in &self.resolver.current_file.messages {
let message_proto = output
.message_type
.iter_mut()
.find(|m| m.name() == message_model.name)
.unwrap();
self.message(
&self.resolver.current_file.package,
message_proto,
message_model,
)?;
}
for enum_model in &self.resolver.current_file.enums {
let enum_proto = output
.enum_type
.iter_mut()
.find(|e| e.name() == enum_model.name)
.unwrap();
self.enumeration(&self.resolver.current_file.package, enum_proto, enum_model)?;
}
for service_proto in &mut output.service {
let service_model = self
.resolver
.current_file
.services
.iter()
.find(|s| s.name == service_proto.name())
.unwrap();
self.service(service_proto, service_model)?;
}
for extension_model in &self.resolver.current_file.extensions {
let extension_proto = output
.extension
.iter_mut()
.find(|e| e.name() == extension_model.field.name)
.unwrap();
self.field(
&self.resolver.current_file.package,
extension_proto,
&extension_model.field,
)?;
}
output.options = self
.file_options(
&self.resolver.current_file.package,
&self.resolver.current_file.options,
)?
.into();
Ok(())
}
}