Skip to content

Commit

Permalink
Support more extension types in codegen
Browse files Browse the repository at this point in the history
Pure rust codegen doesn't support enum or message extensions
  • Loading branch information
stepancheg committed Feb 21, 2019
1 parent a8c66d6 commit 0837187
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 3 deletions.
58 changes: 55 additions & 3 deletions protobuf-codegen-pure/src/convert.rs
Expand Up @@ -10,13 +10,14 @@ use protobuf::prelude::*;
use protobuf::Message;

use protobuf::text_format::lexer::StrLitDecodeError;
use std::mem;

#[derive(Debug)]
pub enum ConvertError {
UnsupportedOption(String),
ExtensionNotFound(String),
WrongExtensionType(String, &'static str),
UnsupportedExtensionType(String, String),
UnsupportedExtensionType(String, String, String),
StrLitDecodeError(StrLitDecodeError),
DefaultValueIsNotStringLiteral,
WrongOptionType,
Expand Down Expand Up @@ -884,14 +885,48 @@ impl<'a> Resolver<'a> {
Ok(protobuf::UnknownValue::Varint(if b { 1 } else { 0 }))
}
}
// TODO: check overflow
&model::ProtobufConstant::U64(v) => {
match field_type {
&model::FieldType::Fixed64 => Ok(protobuf::UnknownValue::Fixed64(v)),
// TODO: check overflow
&model::FieldType::Fixed64
| model::FieldType::Sfixed64 => Ok(protobuf::UnknownValue::Fixed64(v)),
&model::FieldType::Fixed32
| model::FieldType::Sfixed32 => Ok(protobuf::UnknownValue::Fixed32(v as u32)),
&model::FieldType::Int64
| &model::FieldType::Int32
| &model::FieldType::Uint64
| &model::FieldType::Uint32 => Ok(protobuf::UnknownValue::Varint(v)),
&model::FieldType::Sint64 => Ok(protobuf::UnknownValue::sint64(v as i64)),
&model::FieldType::Sint32 => Ok(protobuf::UnknownValue::sint32(v as i32)),
_ => Err(()),
}
}
&model::ProtobufConstant::I64(v) => {
match field_type {
&model::FieldType::Fixed64
| model::FieldType::Sfixed64 => Ok(protobuf::UnknownValue::Fixed64(v as u64)),
&model::FieldType::Fixed32
| model::FieldType::Sfixed32 => Ok(protobuf::UnknownValue::Fixed32(v as u32)),
&model::FieldType::Int64
| &model::FieldType::Int32
| &model::FieldType::Uint64
| &model::FieldType::Uint32 => Ok(protobuf::UnknownValue::Varint(v as u64)),
&model::FieldType::Sint64 => Ok(protobuf::UnknownValue::sint64(v as i64)),
&model::FieldType::Sint32 => Ok(protobuf::UnknownValue::sint32(v as i32)),
_ => Err(()),
}
}
&model::ProtobufConstant::F64(f) => {
match field_type {
&model::FieldType::Float => Ok(protobuf::UnknownValue::Fixed32(unsafe { mem::transmute::<f32, u32>(f as f32) })),
&model::FieldType::Double => Ok(protobuf::UnknownValue::Fixed64(unsafe { mem::transmute::<f64, u64>(f) })),
_ => Err(()),
}
}
&model::ProtobufConstant::String(ref s) => {
match field_type {
&model::FieldType::String => Ok(protobuf::UnknownValue::LengthDelimited(s.decode_utf8()?.into_bytes())),
&model::FieldType::Bytes => Ok(protobuf::UnknownValue::LengthDelimited(s.decode_bytes()?)),
_ => Err(()),
}
}
Expand All @@ -902,6 +937,7 @@ impl<'a> Resolver<'a> {
ConvertError::UnsupportedExtensionType(
option_name.to_owned(),
format!("{:?}", field_type),
format!("{:?}", value),
)
})
}
Expand All @@ -914,6 +950,16 @@ impl<'a> Resolver<'a> {
self.custom_options(input, "google.protobuf.FileOptions", r.mut_unknown_fields())?;
Ok(r)
}

fn extension(
&self,
input: &model::Extension,
) -> ConvertResult<protobuf::descriptor::FieldDescriptorProto> {
let relative_path = RelativePath::new("".to_owned());
let mut field = self.field(&input.field, None, &relative_path)?;
field.set_extendee(self.resolve_message_or_enum(&input.extendee, &relative_path).0.path);
Ok(field)
}
}

fn syntax(input: model::Syntax) -> String {
Expand Down Expand Up @@ -962,5 +1008,11 @@ pub fn file_descriptor(
.options
.set_message(resolver.file_options(&input.options)?);

let mut extensions = protobuf::RepeatedField::new();
for e in &input.extensions {
extensions.push(resolver.extension(e)?);
}
output.extension = extensions;

Ok(output)
}
29 changes: 29 additions & 0 deletions protobuf-test/src/common/v2/test_ext.rs
@@ -0,0 +1,29 @@
use protobuf::prelude::*;
use protobuf::Message;

use super::test_ext_pb::*;

#[test]
fn test_get() {
let descriptor = MyMessage::descriptor_static();
let message = descriptor.get_proto().options.get_message();
assert_eq!(10.5, exts::double_field.get(message).unwrap_or_default());
assert_eq!(-8.5, exts::float_field.get(message).unwrap_or_default());
assert_eq!(-3, exts::int32_field.get(message).unwrap_or_default());
assert_eq!(-13, exts::int64_field.get(message).unwrap_or_default());
assert_eq!(-4, exts::sint32_field.get(message).unwrap_or_default());
assert_eq!(-14, exts::sint64_field.get(message).unwrap_or_default());
assert_eq!(5, exts::uint32_field.get(message).unwrap_or_default());
assert_eq!(15, exts::uint64_field.get(message).unwrap_or_default());
assert_eq!(6, exts::fixed32_field.get(message).unwrap_or_default());
assert_eq!(16, exts::fixed64_field.get(message).unwrap_or_default());
assert_eq!(7, exts::sfixed32_field.get(message).unwrap_or_default());
assert_eq!(-17, exts::sfixed64_field.get(message).unwrap_or_default());
assert_eq!(true, exts::bool_field.get(message).unwrap_or_default());
assert_eq!("Hello world!", exts::string_field.get(message).unwrap_or_default());
if false {
// TODO: only implemented in `protoc`-based codegen
assert_eq!(TestEnum::RED, exts::enum_field.get(message).unwrap_or_default());
assert_eq!(22, exts::message_field.get(message).unwrap().get_n());
}
}
60 changes: 60 additions & 0 deletions protobuf-test/src/common/v2/test_ext_pb.proto
@@ -0,0 +1,60 @@
syntax = "proto2";

package test_ext;

import "google/protobuf/descriptor.proto";
import "rustproto.proto";
option (rustproto.generate_accessors_all) = true;


message SubM {
optional int32 n = 1;
}

enum TestEnum {
UNDEFINED = 0;
RED = 1;
BLUE = 2;
GREEN = 3;
}


extend google.protobuf.MessageOptions {
optional double double_field = 50001;
optional float float_field = 50002;
optional int32 int32_field = 50003;
optional int64 int64_field = 50004;
optional uint32 uint32_field = 50005;
optional uint64 uint64_field = 50006;
optional sint32 sint32_field = 50007;
optional sint64 sint64_field = 50008;
optional fixed32 fixed32_field = 50009;
optional fixed64 fixed64_field = 50010;
optional sfixed32 sfixed32_field = 50011;
optional sfixed64 sfixed64_field = 50012;
optional bool bool_field = 50013;
optional string string_field = 50014;
optional bytes bytes_field = 50015;
optional TestEnum enum_field = 50016;
optional SubM message_field = 50017;
}

message MyMessage {
option (double_field) = 10.5;
option (float_field) = -8.5;
option (int32_field) = -3;
option (int64_field) = -13;
option (sint32_field) = -4;
option (sint64_field) = -14;
option (uint32_field) = 5;
option (uint64_field) = 15;
option (fixed32_field) = 6;
option (fixed64_field) = 16;
option (sfixed32_field) = 7;
option (sfixed64_field) = -17;
option (bool_field) = true;
option (string_field) = "Hello world!";
option (bytes_field) = "bytes";
option (enum_field) = RED;
option (message_field) = { n: 22 };
}

0 comments on commit 0837187

Please sign in to comment.