| use protobuf::descriptor::*; |
| use protobuf::rt; |
| use protobuf::rust; |
| use protobuf::text_format; |
| use protobuf::wire_format; |
| |
| use super::code_writer::CodeWriter; |
| use super::enums::*; |
| use super::rust_types_values::*; |
| |
| use super::customize::customize_from_rustproto_for_field; |
| use super::customize::Customize; |
| use oneof::OneofField; |
| |
| use float; |
| use inside::protobuf_crate_path; |
| use message::RustTypeMessage; |
| use protobuf_name::ProtobufAbsolutePath; |
| use rust_name::RustIdent; |
| use rust_name::RustIdentWithPath; |
| use scope::FieldWithContext; |
| use scope::MessageOrEnumWithScope; |
| use scope::RootScope; |
| use scope::WithScope; |
| use std::marker; |
| use syntax::Syntax; |
| |
| fn type_is_copy(field_type: FieldDescriptorProto_Type) -> bool { |
| match field_type { |
| FieldDescriptorProto_Type::TYPE_MESSAGE |
| | FieldDescriptorProto_Type::TYPE_STRING |
| | FieldDescriptorProto_Type::TYPE_BYTES => false, |
| _ => true, |
| } |
| } |
| |
| trait FieldDescriptorProtoTypeExt { |
| fn read(&self, is: &str, primitive_type_variant: PrimitiveTypeVariant) -> String; |
| fn is_s_varint(&self) -> bool; |
| } |
| |
| impl FieldDescriptorProtoTypeExt for FieldDescriptorProto_Type { |
| fn read(&self, is: &str, primitive_type_variant: PrimitiveTypeVariant) -> String { |
| match primitive_type_variant { |
| PrimitiveTypeVariant::Default => format!("{}.read_{}()", is, protobuf_name(*self)), |
| PrimitiveTypeVariant::Carllerche => { |
| let protobuf_name = match self { |
| &FieldDescriptorProto_Type::TYPE_STRING => "chars", |
| _ => protobuf_name(*self), |
| }; |
| format!("{}.read_carllerche_{}()", is, protobuf_name) |
| } |
| } |
| } |
| |
| /// True if self is signed integer with zigzag encoding |
| fn is_s_varint(&self) -> bool { |
| match *self { |
| FieldDescriptorProto_Type::TYPE_SINT32 | FieldDescriptorProto_Type::TYPE_SINT64 => true, |
| _ => false, |
| } |
| } |
| } |
| |
| fn field_type_wire_type(field_type: FieldDescriptorProto_Type) -> wire_format::WireType { |
| use protobuf::stream::wire_format::*; |
| match field_type { |
| FieldDescriptorProto_Type::TYPE_INT32 => WireTypeVarint, |
| FieldDescriptorProto_Type::TYPE_INT64 => WireTypeVarint, |
| FieldDescriptorProto_Type::TYPE_UINT32 => WireTypeVarint, |
| FieldDescriptorProto_Type::TYPE_UINT64 => WireTypeVarint, |
| FieldDescriptorProto_Type::TYPE_SINT32 => WireTypeVarint, |
| FieldDescriptorProto_Type::TYPE_SINT64 => WireTypeVarint, |
| FieldDescriptorProto_Type::TYPE_BOOL => WireTypeVarint, |
| FieldDescriptorProto_Type::TYPE_ENUM => WireTypeVarint, |
| FieldDescriptorProto_Type::TYPE_FIXED32 => WireTypeFixed32, |
| FieldDescriptorProto_Type::TYPE_FIXED64 => WireTypeFixed64, |
| FieldDescriptorProto_Type::TYPE_SFIXED32 => WireTypeFixed32, |
| FieldDescriptorProto_Type::TYPE_SFIXED64 => WireTypeFixed64, |
| FieldDescriptorProto_Type::TYPE_FLOAT => WireTypeFixed32, |
| FieldDescriptorProto_Type::TYPE_DOUBLE => WireTypeFixed64, |
| FieldDescriptorProto_Type::TYPE_STRING => WireTypeLengthDelimited, |
| FieldDescriptorProto_Type::TYPE_BYTES => WireTypeLengthDelimited, |
| FieldDescriptorProto_Type::TYPE_MESSAGE => WireTypeLengthDelimited, |
| FieldDescriptorProto_Type::TYPE_GROUP => WireTypeLengthDelimited, // not true |
| } |
| } |
| |
| fn type_protobuf_name(field_type: FieldDescriptorProto_Type) -> &'static str { |
| match field_type { |
| FieldDescriptorProto_Type::TYPE_INT32 => "int32", |
| FieldDescriptorProto_Type::TYPE_INT64 => "int64", |
| FieldDescriptorProto_Type::TYPE_UINT32 => "uint32", |
| FieldDescriptorProto_Type::TYPE_UINT64 => "uint64", |
| FieldDescriptorProto_Type::TYPE_SINT32 => "sint32", |
| FieldDescriptorProto_Type::TYPE_SINT64 => "sint64", |
| FieldDescriptorProto_Type::TYPE_BOOL => "bool", |
| FieldDescriptorProto_Type::TYPE_FIXED32 => "fixed32", |
| FieldDescriptorProto_Type::TYPE_FIXED64 => "fixed64", |
| FieldDescriptorProto_Type::TYPE_SFIXED32 => "sfixed32", |
| FieldDescriptorProto_Type::TYPE_SFIXED64 => "sfixed64", |
| FieldDescriptorProto_Type::TYPE_FLOAT => "float", |
| FieldDescriptorProto_Type::TYPE_DOUBLE => "double", |
| FieldDescriptorProto_Type::TYPE_STRING => "string", |
| FieldDescriptorProto_Type::TYPE_BYTES => "bytes", |
| FieldDescriptorProto_Type::TYPE_ENUM |
| | FieldDescriptorProto_Type::TYPE_MESSAGE |
| | FieldDescriptorProto_Type::TYPE_GROUP => panic!(), |
| } |
| } |
| |
| fn field_type_protobuf_name<'a>(field: &'a FieldDescriptorProto) -> &'a str { |
| if field.has_type_name() { |
| field.get_type_name() |
| } else { |
| type_protobuf_name(field.get_field_type()) |
| } |
| } |
| |
| // size of value for type, None if variable |
| fn field_type_size(field_type: FieldDescriptorProto_Type) -> Option<u32> { |
| match field_type { |
| FieldDescriptorProto_Type::TYPE_BOOL => Some(1), |
| t if field_type_wire_type(t) == wire_format::WireTypeFixed32 => Some(4), |
| t if field_type_wire_type(t) == wire_format::WireTypeFixed64 => Some(8), |
| _ => None, |
| } |
| } |
| |
| #[derive(Clone, PartialEq, Eq)] |
| pub enum SingularFieldFlag { |
| // proto2 or proto3 message |
| WithFlag { required: bool }, |
| // proto3 |
| WithoutFlag, |
| } |
| |
| impl SingularFieldFlag { |
| pub fn is_required(&self) -> bool { |
| match *self { |
| SingularFieldFlag::WithFlag { required, .. } => required, |
| SingularFieldFlag::WithoutFlag => false, |
| } |
| } |
| } |
| |
| #[derive(Clone)] |
| pub(crate) struct SingularField<'a> { |
| pub flag: SingularFieldFlag, |
| pub elem: FieldElem<'a>, |
| } |
| |
| impl<'a> SingularField<'a> { |
| fn rust_storage_type(&self) -> RustType { |
| match self.flag { |
| SingularFieldFlag::WithFlag { .. } => match self.elem.proto_type() { |
| FieldDescriptorProto_Type::TYPE_MESSAGE => { |
| RustType::SingularPtrField(Box::new(self.elem.rust_storage_type())) |
| } |
| FieldDescriptorProto_Type::TYPE_STRING | FieldDescriptorProto_Type::TYPE_BYTES |
| if self.elem.primitive_type_variant() == PrimitiveTypeVariant::Default => |
| { |
| RustType::SingularField(Box::new(self.elem.rust_storage_type())) |
| } |
| _ => RustType::Option(Box::new(self.elem.rust_storage_type())), |
| }, |
| SingularFieldFlag::WithoutFlag => self.elem.rust_storage_type(), |
| } |
| } |
| } |
| |
| #[derive(Clone)] |
| pub(crate) struct RepeatedField<'a> { |
| pub elem: FieldElem<'a>, |
| pub packed: bool, |
| } |
| |
| impl<'a> RepeatedField<'a> { |
| fn rust_type(&self) -> RustType { |
| if !self.elem.is_copy() |
| && self.elem.primitive_type_variant() != PrimitiveTypeVariant::Carllerche |
| { |
| RustType::RepeatedField(Box::new(self.elem.rust_storage_type())) |
| } else { |
| RustType::Vec(Box::new(self.elem.rust_storage_type())) |
| } |
| } |
| } |
| |
| #[derive(Clone)] |
| pub struct MapField<'a> { |
| name: String, |
| key: FieldElem<'a>, |
| value: FieldElem<'a>, |
| } |
| |
| #[derive(Clone)] |
| pub(crate) enum FieldKind<'a> { |
| // optional or required |
| Singular(SingularField<'a>), |
| // repeated except map |
| Repeated(RepeatedField<'a>), |
| // map |
| Map(MapField<'a>), |
| // part of oneof |
| Oneof(OneofField<'a>), |
| } |
| |
| impl<'a> FieldKind<'a> { |
| fn elem(&self) -> &FieldElem { |
| match self { |
| &FieldKind::Singular(ref s) => &s.elem, |
| &FieldKind::Repeated(ref r) => &r.elem, |
| &FieldKind::Oneof(ref o) => &o.elem, |
| &FieldKind::Map(..) => { |
| panic!("no single elem type for map field"); |
| } |
| } |
| } |
| |
| fn primitive_type_variant(&self) -> PrimitiveTypeVariant { |
| self.elem().primitive_type_variant() |
| } |
| } |
| |
| // Representation of map entry: key type and value type |
| #[derive(Clone, Debug)] |
| pub struct EntryKeyValue<'a>(FieldElem<'a>, FieldElem<'a>); |
| |
| #[derive(Clone, Debug)] |
| pub(crate) enum FieldElem<'a> { |
| Primitive(FieldDescriptorProto_Type, PrimitiveTypeVariant), |
| // name, file name, entry |
| Message( |
| String, |
| String, |
| Option<Box<EntryKeyValue<'a>>>, |
| marker::PhantomData<&'a ()>, |
| ), |
| // name, file name, default value |
| Enum(String, String, RustIdent), |
| Group, |
| } |
| |
| impl<'a> FieldElem<'a> { |
| fn proto_type(&self) -> FieldDescriptorProto_Type { |
| match *self { |
| FieldElem::Primitive(t, ..) => t, |
| FieldElem::Group => FieldDescriptorProto_Type::TYPE_GROUP, |
| FieldElem::Message(..) => FieldDescriptorProto_Type::TYPE_MESSAGE, |
| FieldElem::Enum(..) => FieldDescriptorProto_Type::TYPE_ENUM, |
| } |
| } |
| |
| fn is_copy(&self) -> bool { |
| type_is_copy(self.proto_type()) |
| } |
| |
| pub fn rust_storage_type(&self) -> RustType { |
| match *self { |
| FieldElem::Primitive(t, PrimitiveTypeVariant::Default) => rust_name(t), |
| FieldElem::Primitive( |
| FieldDescriptorProto_Type::TYPE_STRING, |
| PrimitiveTypeVariant::Carllerche, |
| ) => RustType::Chars, |
| FieldElem::Primitive( |
| FieldDescriptorProto_Type::TYPE_BYTES, |
| PrimitiveTypeVariant::Carllerche, |
| ) => RustType::Bytes, |
| FieldElem::Primitive(.., PrimitiveTypeVariant::Carllerche) => unreachable!(), |
| FieldElem::Group => RustType::Group, |
| FieldElem::Message(ref name, ..) => { |
| RustType::Message(RustTypeMessage(RustIdentWithPath::new(name.clone()))) |
| } |
| FieldElem::Enum(ref name, _, ref default_value) => { |
| RustType::Enum(name.clone(), default_value.clone()) |
| } |
| } |
| } |
| |
| fn protobuf_type_gen(&self) -> ProtobufTypeGen { |
| match *self { |
| FieldElem::Primitive(t, v) => ProtobufTypeGen::Primitive(t, v), |
| FieldElem::Message(ref name, ..) => ProtobufTypeGen::Message(name.clone()), |
| FieldElem::Enum(ref name, ..) => ProtobufTypeGen::Enum(name.clone()), |
| FieldElem::Group => unreachable!(), |
| } |
| } |
| |
| /// implementation of ProtobufType trait |
| fn lib_protobuf_type(&self, customize: &Customize) -> String { |
| self.protobuf_type_gen().rust_type(customize) |
| } |
| |
| fn primitive_type_variant(&self) -> PrimitiveTypeVariant { |
| match self { |
| &FieldElem::Primitive(_, v) => v, |
| _ => PrimitiveTypeVariant::Default, |
| } |
| } |
| } |
| |
| fn field_elem<'a>( |
| field: &FieldWithContext, |
| root_scope: &'a RootScope<'a>, |
| parse_map: bool, |
| customize: &Customize, |
| ) -> (FieldElem<'a>, Option<EnumValueGen>) { |
| if field.field.get_field_type() == FieldDescriptorProto_Type::TYPE_GROUP { |
| (FieldElem::Group, None) |
| } else if field.field.has_type_name() { |
| let message_or_enum = root_scope |
| .find_message_or_enum(&ProtobufAbsolutePath::from(field.field.get_type_name())); |
| let file_name = message_or_enum |
| .get_scope() |
| .file_scope |
| .file_descriptor |
| .get_name() |
| .to_owned(); |
| let rust_relative_name = type_name_to_rust_relative( |
| &ProtobufAbsolutePath::from(field.field.get_type_name()), |
| field.message.get_scope().file_scope.file_descriptor, |
| false, |
| root_scope, |
| ); |
| match (field.field.get_field_type(), message_or_enum) { |
| ( |
| FieldDescriptorProto_Type::TYPE_MESSAGE, |
| MessageOrEnumWithScope::Message(message_with_scope), |
| ) => { |
| let entry_key_value = if let (true, Some((key, value))) = |
| (parse_map, message_with_scope.map_entry()) |
| { |
| Some(Box::new(EntryKeyValue( |
| field_elem(&key, root_scope, false, customize).0, |
| field_elem(&value, root_scope, false, customize).0, |
| ))) |
| } else { |
| None |
| }; |
| ( |
| FieldElem::Message( |
| rust_relative_name, |
| file_name, |
| entry_key_value, |
| marker::PhantomData, |
| ), |
| None, |
| ) |
| } |
| ( |
| FieldDescriptorProto_Type::TYPE_ENUM, |
| MessageOrEnumWithScope::Enum(enum_with_scope), |
| ) => { |
| let e = EnumGen::new( |
| &enum_with_scope, |
| field.message.get_scope().get_file_descriptor(), |
| customize, |
| root_scope, |
| ); |
| let ev = if field.field.has_default_value() { |
| e.value_by_name(field.field.get_default_value()).clone() |
| } else { |
| e.values_unique().into_iter().next().unwrap() |
| }; |
| ( |
| FieldElem::Enum( |
| rust_relative_name, |
| file_name, |
| RustIdent::from(enum_with_scope.values()[0].rust_name().to_owned()), |
| ), |
| Some(ev), |
| ) |
| } |
| _ => panic!("unknown named type: {:?}", field.field.get_field_type()), |
| } |
| } else if field.field.has_field_type() { |
| let carllerche_for_bytes = customize.carllerche_bytes_for_bytes.unwrap_or(false); |
| let carllerche_for_string = customize.carllerche_bytes_for_string.unwrap_or(false); |
| |
| let elem = match field.field.get_field_type() { |
| FieldDescriptorProto_Type::TYPE_STRING if carllerche_for_string => { |
| FieldElem::Primitive( |
| FieldDescriptorProto_Type::TYPE_STRING, |
| PrimitiveTypeVariant::Carllerche, |
| ) |
| } |
| FieldDescriptorProto_Type::TYPE_BYTES if carllerche_for_bytes => FieldElem::Primitive( |
| FieldDescriptorProto_Type::TYPE_BYTES, |
| PrimitiveTypeVariant::Carllerche, |
| ), |
| t => FieldElem::Primitive(t, PrimitiveTypeVariant::Default), |
| }; |
| |
| (elem, None) |
| } else { |
| panic!( |
| "neither type_name, nor field_type specified for field: {}", |
| field.field.get_name() |
| ); |
| } |
| } |
| |
| pub enum AccessorStyle { |
| Lambda, |
| HasGet, |
| } |
| |
| pub struct AccessorFn { |
| name: String, |
| type_params: Vec<String>, |
| pub style: AccessorStyle, |
| } |
| |
| impl AccessorFn { |
| pub fn sig(&self) -> String { |
| let mut s = self.name.clone(); |
| s.push_str("::<_"); |
| for p in &self.type_params { |
| s.push_str(", "); |
| s.push_str(&p); |
| } |
| s.push_str(">"); |
| s |
| } |
| } |
| |
| #[derive(Clone)] |
| pub(crate) struct FieldGen<'a> { |
| root_scope: &'a RootScope<'a>, |
| syntax: Syntax, |
| pub proto_field: FieldWithContext<'a>, |
| // field name in generated code |
| pub rust_name: RustIdent, |
| pub proto_type: FieldDescriptorProto_Type, |
| wire_type: wire_format::WireType, |
| enum_default_value: Option<EnumValueGen>, |
| pub kind: FieldKind<'a>, |
| pub expose_field: bool, |
| pub generate_accessors: bool, |
| pub(crate) customize: Customize, |
| } |
| |
| impl<'a> FieldGen<'a> { |
| pub fn parse( |
| field: FieldWithContext<'a>, |
| root_scope: &'a RootScope<'a>, |
| customize: &Customize, |
| ) -> FieldGen<'a> { |
| let mut customize = customize.clone(); |
| customize.update_with(&customize_from_rustproto_for_field( |
| &field.field.get_options(), |
| )); |
| |
| let (elem, enum_default_value) = field_elem(&field, root_scope, true, &customize); |
| |
| let generate_accessors = customize.generate_accessors.unwrap_or(true); |
| |
| let syntax = field.message.scope.file_scope.syntax(); |
| |
| let field_may_have_custom_default_value = syntax == Syntax::PROTO2 |
| && field.field.get_label() != FieldDescriptorProto_Label::LABEL_REPEATED |
| && field.field.get_field_type() != FieldDescriptorProto_Type::TYPE_MESSAGE; |
| |
| let default_expose_field = !field_may_have_custom_default_value; |
| |
| let expose_field = customize.expose_fields.unwrap_or(default_expose_field); |
| |
| let kind = if field.field.get_label() == FieldDescriptorProto_Label::LABEL_REPEATED { |
| match (elem, true) { |
| // map field |
| (FieldElem::Message(name, _, Some(key_value), _), true) => { |
| FieldKind::Map(MapField { |
| name: name, |
| key: key_value.0.clone(), |
| value: key_value.1.clone(), |
| }) |
| } |
| // regular repeated field |
| (elem, _) => FieldKind::Repeated(RepeatedField { |
| elem, |
| packed: field.field.get_options().get_packed(), |
| }), |
| } |
| } else if let Some(oneof) = field.oneof() { |
| FieldKind::Oneof(OneofField::parse(&oneof, &field, elem, root_scope)) |
| } else { |
| let flag = if field.message.scope.file_scope.syntax() == Syntax::PROTO3 |
| && field.field.get_field_type() != FieldDescriptorProto_Type::TYPE_MESSAGE |
| { |
| SingularFieldFlag::WithoutFlag |
| } else { |
| SingularFieldFlag::WithFlag { |
| required: field.field.get_label() == FieldDescriptorProto_Label::LABEL_REQUIRED, |
| } |
| }; |
| FieldKind::Singular(SingularField { elem, flag }) |
| }; |
| |
| FieldGen { |
| root_scope, |
| syntax: field.message.get_scope().file_scope.syntax(), |
| rust_name: field.rust_name(), |
| proto_type: field.field.get_field_type(), |
| wire_type: field_type_wire_type(field.field.get_field_type()), |
| enum_default_value, |
| proto_field: field.clone(), |
| kind, |
| expose_field, |
| generate_accessors, |
| customize, |
| } |
| } |
| |
| fn tag_size(&self) -> u32 { |
| rt::tag_size(self.proto_field.number()) |
| } |
| |
| pub fn is_oneof(&self) -> bool { |
| match self.kind { |
| FieldKind::Oneof(..) => true, |
| _ => false, |
| } |
| } |
| |
| pub fn oneof(&self) -> &OneofField { |
| match self.kind { |
| FieldKind::Oneof(ref oneof) => &oneof, |
| _ => panic!("not a oneof field: {}", self.reconstruct_def()), |
| } |
| } |
| |
| fn is_singular(&self) -> bool { |
| match self.kind { |
| FieldKind::Singular(..) => true, |
| _ => false, |
| } |
| } |
| |
| fn is_repeated_not_map(&self) -> bool { |
| match self.kind { |
| FieldKind::Repeated(..) => true, |
| _ => false, |
| } |
| } |
| |
| fn is_repeated_or_map(&self) -> bool { |
| match self.kind { |
| FieldKind::Repeated(..) | FieldKind::Map(..) => true, |
| _ => false, |
| } |
| } |
| |
| fn is_repeated_packed(&self) -> bool { |
| match self.kind { |
| FieldKind::Repeated(RepeatedField { packed: true, .. }) => true, |
| _ => false, |
| } |
| } |
| |
| #[allow(dead_code)] |
| fn repeated(&self) -> &RepeatedField { |
| match self.kind { |
| FieldKind::Repeated(ref repeated) => &repeated, |
| _ => panic!("not a repeated field: {}", self.reconstruct_def()), |
| } |
| } |
| |
| fn singular(&self) -> &SingularField { |
| match self.kind { |
| FieldKind::Singular(ref singular) => &singular, |
| _ => panic!("not a singular field: {}", self.reconstruct_def()), |
| } |
| } |
| |
| fn map(&self) -> &MapField { |
| match self.kind { |
| FieldKind::Map(ref map) => &map, |
| _ => panic!("not a map field: {}", self.reconstruct_def()), |
| } |
| } |
| |
| fn variant_path(&self) -> String { |
| // TODO: should reuse code from OneofVariantGen |
| format!( |
| "{}::{}", |
| self.oneof().oneof_type_name.to_code(&self.customize), |
| self.rust_name |
| ) |
| } |
| |
| // TODO: drop it |
| pub fn elem(&self) -> &FieldElem { |
| match self.kind { |
| FieldKind::Singular(SingularField { ref elem, .. }) => &elem, |
| FieldKind::Repeated(RepeatedField { ref elem, .. }) => &elem, |
| FieldKind::Oneof(OneofField { ref elem, .. }) => &elem, |
| FieldKind::Map(..) => unreachable!(), |
| } |
| } |
| |
| // type of field in struct |
| pub fn full_storage_type(&self) -> RustType { |
| match self.kind { |
| FieldKind::Repeated(ref repeated) => repeated.rust_type(), |
| FieldKind::Map(MapField { |
| ref key, ref value, .. |
| }) => RustType::HashMap( |
| Box::new(key.rust_storage_type()), |
| Box::new(value.rust_storage_type()), |
| ), |
| FieldKind::Singular(ref singular) => singular.rust_storage_type(), |
| FieldKind::Oneof(..) => unreachable!(), |
| } |
| } |
| |
| // type of `v` in `for v in field` |
| fn full_storage_iter_elem_type(&self) -> RustType { |
| if let FieldKind::Oneof(ref oneof) = self.kind { |
| oneof.elem.rust_storage_type() |
| } else { |
| self.full_storage_type().iter_elem_type() |
| } |
| } |
| |
| // suffix `xxx` as in `os.write_xxx_no_tag(..)` |
| fn os_write_fn_suffix(&self) -> &str { |
| protobuf_name(self.proto_type) |
| } |
| |
| // type of `v` in `os.write_xxx_no_tag(v)` |
| fn os_write_fn_param_type(&self) -> RustType { |
| match self.proto_type { |
| FieldDescriptorProto_Type::TYPE_STRING => RustType::Ref(Box::new(RustType::Str)), |
| FieldDescriptorProto_Type::TYPE_BYTES => { |
| RustType::Ref(Box::new(RustType::Slice(Box::new(RustType::Int(false, 8))))) |
| } |
| FieldDescriptorProto_Type::TYPE_ENUM => RustType::Int(true, 32), |
| t => rust_name(t), |
| } |
| } |
| |
| // for field `foo`, type of param of `fn set_foo(..)` |
| fn set_xxx_param_type(&self) -> RustType { |
| match self.kind { |
| FieldKind::Singular(SingularField { ref elem, .. }) |
| | FieldKind::Oneof(OneofField { ref elem, .. }) => elem.rust_storage_type(), |
| FieldKind::Repeated(..) | FieldKind::Map(..) => self.full_storage_type(), |
| } |
| } |
| |
| // for field `foo`, return type if `fn take_foo(..)` |
| fn take_xxx_return_type(&self) -> RustType { |
| self.set_xxx_param_type() |
| } |
| |
| // for field `foo`, return type of `fn mut_foo(..)` |
| fn mut_xxx_return_type(&self) -> RustType { |
| RustType::Ref(Box::new(match self.kind { |
| FieldKind::Singular(SingularField { ref elem, .. }) |
| | FieldKind::Oneof(OneofField { ref elem, .. }) => elem.rust_storage_type(), |
| FieldKind::Repeated(..) | FieldKind::Map(..) => self.full_storage_type(), |
| })) |
| } |
| |
| // for field `foo`, return type of `fn get_foo(..)` |
| fn get_xxx_return_type(&self) -> RustType { |
| match self.kind { |
| FieldKind::Singular(SingularField { ref elem, .. }) |
| | FieldKind::Oneof(OneofField { ref elem, .. }) => match elem.is_copy() { |
| true => elem.rust_storage_type(), |
| false => elem.rust_storage_type().ref_type(), |
| }, |
| FieldKind::Repeated(RepeatedField { ref elem, .. }) => RustType::Ref(Box::new( |
| RustType::Slice(Box::new(elem.rust_storage_type())), |
| )), |
| FieldKind::Map(..) => RustType::Ref(Box::new(self.full_storage_type())), |
| } |
| } |
| |
| // fixed size type? |
| fn is_fixed(&self) -> bool { |
| field_type_size(self.proto_type).is_some() |
| } |
| |
| // must use zigzag encoding? |
| fn is_zigzag(&self) -> bool { |
| match self.proto_type { |
| FieldDescriptorProto_Type::TYPE_SINT32 | FieldDescriptorProto_Type::TYPE_SINT64 => true, |
| _ => false, |
| } |
| } |
| |
| // data is enum |
| fn is_enum(&self) -> bool { |
| match self.proto_type { |
| FieldDescriptorProto_Type::TYPE_ENUM => true, |
| _ => false, |
| } |
| } |
| |
| // elem data is not stored in heap |
| pub fn elem_type_is_copy(&self) -> bool { |
| type_is_copy(self.proto_type) |
| } |
| |
| fn defaut_value_from_proto_float(&self) -> String { |
| assert!(self.proto_field.field.has_default_value()); |
| |
| let type_name = match self.proto_type { |
| FieldDescriptorProto_Type::TYPE_FLOAT => "f32", |
| FieldDescriptorProto_Type::TYPE_DOUBLE => "f64", |
| _ => unreachable!(), |
| }; |
| let proto_default = self.proto_field.field.get_default_value(); |
| |
| let f = float::parse_protobuf_float(proto_default) |
| .expect(&format!("failed to parse float: {:?}", proto_default)); |
| |
| if f.is_nan() { |
| format!("::std::{}::NAN", type_name) |
| } else if f.is_infinite() { |
| if f > 0.0 { |
| format!("::std::{}::INFINITY", type_name) |
| } else { |
| format!("::std::{}::NEG_INFINITY", type_name) |
| } |
| } else { |
| format!("{:?}{}", f, type_name) |
| } |
| } |
| |
| fn default_value_from_proto(&self) -> Option<String> { |
| assert!(self.is_singular() || self.is_oneof()); |
| if self.enum_default_value.is_some() { |
| Some(self.enum_default_value.as_ref().unwrap().rust_name_outer()) |
| } else if self.proto_field.field.has_default_value() { |
| let proto_default = self.proto_field.field.get_default_value(); |
| Some(match self.proto_type { |
| // For numeric types, contains the original text representation of the value |
| FieldDescriptorProto_Type::TYPE_DOUBLE | FieldDescriptorProto_Type::TYPE_FLOAT => { |
| self.defaut_value_from_proto_float() |
| } |
| FieldDescriptorProto_Type::TYPE_INT32 |
| | FieldDescriptorProto_Type::TYPE_SINT32 |
| | FieldDescriptorProto_Type::TYPE_SFIXED32 => format!("{}i32", proto_default), |
| FieldDescriptorProto_Type::TYPE_UINT32 |
| | FieldDescriptorProto_Type::TYPE_FIXED32 => format!("{}u32", proto_default), |
| FieldDescriptorProto_Type::TYPE_INT64 |
| | FieldDescriptorProto_Type::TYPE_SINT64 |
| | FieldDescriptorProto_Type::TYPE_SFIXED64 => format!("{}i64", proto_default), |
| FieldDescriptorProto_Type::TYPE_UINT64 |
| | FieldDescriptorProto_Type::TYPE_FIXED64 => format!("{}u64", proto_default), |
| |
| // For booleans, "true" or "false" |
| FieldDescriptorProto_Type::TYPE_BOOL => format!("{}", proto_default), |
| // For strings, contains the default text contents (not escaped in any way) |
| FieldDescriptorProto_Type::TYPE_STRING => rust::quote_escape_str(proto_default), |
| // For bytes, contains the C escaped value. All bytes >= 128 are escaped |
| FieldDescriptorProto_Type::TYPE_BYTES => { |
| rust::quote_escape_bytes(&text_format::unescape_string(proto_default)) |
| } |
| // TODO: resolve outer message prefix |
| FieldDescriptorProto_Type::TYPE_GROUP | FieldDescriptorProto_Type::TYPE_ENUM => { |
| unreachable!() |
| } |
| FieldDescriptorProto_Type::TYPE_MESSAGE => panic!( |
| "default value is not implemented for type: {:?}", |
| self.proto_type |
| ), |
| }) |
| } else { |
| None |
| } |
| } |
| |
| fn default_value_from_proto_typed(&self) -> Option<RustValueTyped> { |
| self.default_value_from_proto().map(|v| { |
| let default_value_type = match self.proto_type { |
| FieldDescriptorProto_Type::TYPE_STRING => RustType::Ref(Box::new(RustType::Str)), |
| FieldDescriptorProto_Type::TYPE_BYTES => { |
| RustType::Ref(Box::new(RustType::Slice(Box::new(RustType::u8())))) |
| } |
| _ => self.full_storage_iter_elem_type(), |
| }; |
| |
| RustValueTyped { |
| value: v, |
| rust_type: default_value_type, |
| } |
| }) |
| } |
| |
| // default value to be returned from fn get_xxx |
| fn get_xxx_default_value_rust(&self) -> String { |
| assert!(self.is_singular() || self.is_oneof()); |
| self.default_value_from_proto() |
| .unwrap_or_else(|| self.get_xxx_return_type().default_value(&self.customize)) |
| } |
| |
| // default to be assigned to field |
| fn element_default_value_rust(&self) -> RustValueTyped { |
| assert!( |
| self.is_singular() || self.is_oneof(), |
| "field is not singular: {}", |
| self.reconstruct_def() |
| ); |
| self.default_value_from_proto_typed().unwrap_or_else(|| { |
| self.elem() |
| .rust_storage_type() |
| .default_value_typed(&self.customize) |
| }) |
| } |
| |
| pub fn reconstruct_def(&self) -> String { |
| let prefix = match (self.proto_field.field.get_label(), self.syntax) { |
| (FieldDescriptorProto_Label::LABEL_REPEATED, _) => "repeated ", |
| (_, Syntax::PROTO3) => "", |
| (FieldDescriptorProto_Label::LABEL_OPTIONAL, _) => "optional ", |
| (FieldDescriptorProto_Label::LABEL_REQUIRED, _) => "required ", |
| }; |
| format!( |
| "{}{} {} = {}", |
| prefix, |
| field_type_protobuf_name(&self.proto_field.field), |
| self.proto_field.name(), |
| self.proto_field.number() |
| ) |
| } |
| |
| pub fn accessor_fn(&self) -> AccessorFn { |
| match self.kind { |
| FieldKind::Repeated(RepeatedField { ref elem, .. }) => { |
| let coll = match self.full_storage_type() { |
| RustType::Vec(..) => "vec", |
| RustType::RepeatedField(..) => "repeated_field", |
| _ => unreachable!(), |
| }; |
| let name = format!("make_{}_accessor", coll); |
| AccessorFn { |
| name: name, |
| type_params: vec![elem.lib_protobuf_type(&self.customize)], |
| style: AccessorStyle::Lambda, |
| } |
| } |
| FieldKind::Map(MapField { |
| ref key, ref value, .. |
| }) => AccessorFn { |
| name: "make_map_accessor".to_owned(), |
| type_params: vec![ |
| key.lib_protobuf_type(&self.customize), |
| value.lib_protobuf_type(&self.customize), |
| ], |
| style: AccessorStyle::Lambda, |
| }, |
| FieldKind::Singular(SingularField { |
| ref elem, |
| flag: SingularFieldFlag::WithoutFlag, |
| }) => { |
| if let &FieldElem::Message(ref name, ..) = elem { |
| // TODO: old style, needed because of default instance |
| |
| AccessorFn { |
| name: "make_singular_message_accessor".to_owned(), |
| type_params: vec![name.clone()], |
| style: AccessorStyle::HasGet, |
| } |
| } else { |
| AccessorFn { |
| name: "make_simple_field_accessor".to_owned(), |
| type_params: vec![elem.lib_protobuf_type(&self.customize)], |
| style: AccessorStyle::Lambda, |
| } |
| } |
| } |
| FieldKind::Singular(SingularField { |
| ref elem, |
| flag: SingularFieldFlag::WithFlag { .. }, |
| }) => { |
| let coll = match self.full_storage_type() { |
| RustType::Option(..) => "option", |
| RustType::SingularField(..) => "singular_field", |
| RustType::SingularPtrField(..) => "singular_ptr_field", |
| _ => unreachable!(), |
| }; |
| let name = format!("make_{}_accessor", coll); |
| AccessorFn { |
| name: name, |
| type_params: vec![elem.lib_protobuf_type(&self.customize)], |
| style: AccessorStyle::Lambda, |
| } |
| } |
| FieldKind::Oneof(OneofField { ref elem, .. }) => { |
| // TODO: uses old style |
| |
| let suffix = match &self.elem().rust_storage_type() { |
| t if t.is_primitive() => t.to_code(&self.customize), |
| &RustType::String | &RustType::Chars => "string".to_string(), |
| &RustType::Vec(ref t) if t.is_u8() => "bytes".to_string(), |
| &RustType::Bytes => "bytes".to_string(), |
| &RustType::Enum(..) => "enum".to_string(), |
| &RustType::Message(..) => "message".to_string(), |
| t => panic!("unexpected field type: {:?}", t), |
| }; |
| |
| let name = format!("make_singular_{}_accessor", suffix); |
| |
| let mut type_params = Vec::new(); |
| match elem { |
| &FieldElem::Message(ref name, ..) | &FieldElem::Enum(ref name, ..) => { |
| type_params.push(name.to_owned()); |
| } |
| _ => (), |
| } |
| |
| AccessorFn { |
| name: name, |
| type_params: type_params, |
| style: AccessorStyle::HasGet, |
| } |
| } |
| } |
| } |
| |
| pub fn write_clear(&self, w: &mut CodeWriter) { |
| if self.is_oneof() { |
| w.write_line(&format!( |
| "self.{} = ::std::option::Option::None;", |
| self.oneof().oneof_rust_field_name |
| )); |
| } else { |
| let clear_expr = self |
| .full_storage_type() |
| .clear(&self.self_field(), &self.customize); |
| w.write_line(&format!("{};", clear_expr)); |
| } |
| } |
| |
| // expression that returns size of data is variable |
| fn element_size(&self, var: &str, var_type: &RustType) -> String { |
| assert!(!self.is_repeated_packed()); |
| |
| match field_type_size(self.proto_type) { |
| Some(data_size) => format!("{}", data_size + self.tag_size()), |
| None => match self.proto_type { |
| FieldDescriptorProto_Type::TYPE_MESSAGE => panic!("not a single-liner"), |
| FieldDescriptorProto_Type::TYPE_BYTES => format!( |
| "::protobuf::rt::bytes_size({}, &{})", |
| self.proto_field.number(), |
| var |
| ), |
| FieldDescriptorProto_Type::TYPE_STRING => format!( |
| "::protobuf::rt::string_size({}, &{})", |
| self.proto_field.number(), |
| var |
| ), |
| FieldDescriptorProto_Type::TYPE_ENUM => { |
| let param_type = match var_type { |
| &RustType::Ref(ref t) => (**t).clone(), |
| t => t.clone(), |
| }; |
| format!( |
| "::protobuf::rt::enum_size({}, {})", |
| self.proto_field.number(), |
| var_type.into_target(¶m_type, var, &self.customize) |
| ) |
| } |
| _ => { |
| let param_type = match var_type { |
| &RustType::Ref(ref t) => (**t).clone(), |
| t => t.clone(), |
| }; |
| if self.proto_type.is_s_varint() { |
| format!( |
| "::protobuf::rt::value_varint_zigzag_size({}, {})", |
| self.proto_field.number(), |
| var_type.into_target(¶m_type, var, &self.customize) |
| ) |
| } else { |
| format!( |
| "::protobuf::rt::value_size({}, {}, ::protobuf::wire_format::{:?})", |
| self.proto_field.number(), |
| var_type.into_target(¶m_type, var, &self.customize), |
| self.wire_type |
| ) |
| } |
| } |
| }, |
| } |
| } |
| |
| // output code that writes single element to stream |
| pub fn write_write_element(&self, w: &mut CodeWriter, os: &str, var: &str, ty: &RustType) { |
| if let FieldKind::Repeated(RepeatedField { packed: true, .. }) = self.kind { |
| unreachable!(); |
| }; |
| |
| match self.proto_type { |
| FieldDescriptorProto_Type::TYPE_MESSAGE => { |
| w.write_line(&format!( |
| "{}.write_tag({}, ::protobuf::wire_format::{:?})?;", |
| os, |
| self.proto_field.number(), |
| wire_format::WireTypeLengthDelimited |
| )); |
| w.write_line(&format!( |
| "{}.write_raw_varint32({}.get_cached_size())?;", |
| os, var |
| )); |
| w.write_line(&format!("{}.write_to_with_cached_sizes({})?;", var, os)); |
| } |
| _ => { |
| let param_type = self.os_write_fn_param_type(); |
| let os_write_fn_suffix = self.os_write_fn_suffix(); |
| let number = self.proto_field.number(); |
| w.write_line(&format!( |
| "{}.write_{}({}, {})?;", |
| os, |
| os_write_fn_suffix, |
| number, |
| ty.into_target(¶m_type, var, &self.customize) |
| )); |
| } |
| } |
| } |
| |
| fn self_field(&self) -> String { |
| format!("self.{}", self.rust_name) |
| } |
| |
| fn self_field_is_some(&self) -> String { |
| assert!(self.is_singular()); |
| format!("{}.is_some()", self.self_field()) |
| } |
| |
| fn self_field_is_not_empty(&self) -> String { |
| assert!(self.is_repeated_or_map()); |
| format!("!{}.is_empty()", self.self_field()) |
| } |
| |
| fn self_field_is_none(&self) -> String { |
| assert!(self.is_singular()); |
| format!("{}.is_none()", self.self_field()) |
| } |
| |
| // type of expression returned by `as_option()` |
| fn as_option_type(&self) -> RustType { |
| assert!(self.is_singular()); |
| match self.full_storage_type() { |
| RustType::Option(ref e) if e.is_copy() => RustType::Option(e.clone()), |
| RustType::Option(e) => RustType::Option(Box::new(e.ref_type())), |
| RustType::SingularField(ty) | RustType::SingularPtrField(ty) => { |
| RustType::Option(Box::new(RustType::Ref(ty))) |
| } |
| x => panic!("cannot convert {:?} to option", x), |
| } |
| } |
| |
| // field data viewed as Option |
| fn self_field_as_option(&self) -> RustValueTyped { |
| assert!(self.is_singular()); |
| |
| let suffix = match self.full_storage_type() { |
| RustType::Option(ref e) if e.is_copy() => "", |
| _ => ".as_ref()", |
| }; |
| |
| self.as_option_type() |
| .value(format!("{}{}", self.self_field(), suffix)) |
| } |
| |
| fn write_if_let_self_field_is_some<F>(&self, w: &mut CodeWriter, cb: F) |
| where |
| F: Fn(&str, &RustType, &mut CodeWriter), |
| { |
| match self.kind { |
| FieldKind::Repeated(..) | FieldKind::Map(..) => panic!("field is not singular"), |
| FieldKind::Singular(SingularField { |
| flag: SingularFieldFlag::WithFlag { .. }, |
| ref elem, |
| }) => { |
| let var = "v"; |
| let ref_prefix = match elem.rust_storage_type().is_copy() { |
| true => "", |
| false => "ref ", |
| }; |
| let as_option = self.self_field_as_option(); |
| w.if_let_stmt( |
| &format!("Some({}{})", ref_prefix, var), |
| &as_option.value, |
| |w| { |
| let v_type = as_option.rust_type.elem_type(); |
| cb(var, &v_type, w); |
| }, |
| ); |
| } |
| FieldKind::Singular(SingularField { |
| flag: SingularFieldFlag::WithoutFlag, |
| ref elem, |
| }) => match *elem { |
| FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_STRING, ..) |
| | FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_BYTES, ..) => { |
| w.if_stmt(format!("!{}.is_empty()", self.self_field()), |w| { |
| cb(&self.self_field(), &self.full_storage_type(), w); |
| }); |
| } |
| _ => { |
| w.if_stmt( |
| format!( |
| "{} != {}", |
| self.self_field(), |
| self.full_storage_type().default_value(&self.customize) |
| ), |
| |w| { |
| cb(&self.self_field(), &self.full_storage_type(), w); |
| }, |
| ); |
| } |
| }, |
| FieldKind::Oneof(..) => unreachable!(), |
| } |
| } |
| |
| fn write_if_self_field_is_not_empty<F>(&self, w: &mut CodeWriter, cb: F) |
| where |
| F: Fn(&mut CodeWriter), |
| { |
| assert!(self.is_repeated_or_map()); |
| let self_field_is_not_empty = self.self_field_is_not_empty(); |
| w.if_stmt(self_field_is_not_empty, cb); |
| } |
| |
| pub fn write_if_self_field_is_none<F>(&self, w: &mut CodeWriter, cb: F) |
| where |
| F: Fn(&mut CodeWriter), |
| { |
| let self_field_is_none = self.self_field_is_none(); |
| w.if_stmt(self_field_is_none, cb) |
| } |
| |
| // repeated or singular |
| pub fn write_for_self_field<F>(&self, w: &mut CodeWriter, varn: &str, cb: F) |
| where |
| F: Fn(&mut CodeWriter, &RustType), |
| { |
| match self.kind { |
| FieldKind::Oneof(OneofField { |
| ref elem, |
| ref oneof_type_name, |
| .. |
| }) => { |
| let cond = format!( |
| "Some({}::{}(ref {}))", |
| oneof_type_name.to_code(&self.customize), |
| self.rust_name, |
| varn |
| ); |
| w.if_let_stmt(&cond, &self.self_field_oneof(), |w| { |
| cb(w, &elem.rust_storage_type()) |
| }) |
| } |
| _ => { |
| let v_type = self.full_storage_iter_elem_type(); |
| let self_field = self.self_field(); |
| w.for_stmt(&format!("&{}", self_field), varn, |w| cb(w, &v_type)); |
| } |
| } |
| } |
| |
| fn write_self_field_assign(&self, w: &mut CodeWriter, value: &str) { |
| let self_field = self.self_field(); |
| w.write_line(&format!("{} = {};", self_field, value)); |
| } |
| |
| fn write_self_field_assign_some(&self, w: &mut CodeWriter, value: &str) { |
| let full_storage_type = self.full_storage_type(); |
| match self.singular() { |
| &SingularField { |
| flag: SingularFieldFlag::WithFlag { .. }, |
| .. |
| } => { |
| self.write_self_field_assign(w, &full_storage_type.wrap_value(value)); |
| } |
| &SingularField { |
| flag: SingularFieldFlag::WithoutFlag, |
| .. |
| } => { |
| self.write_self_field_assign(w, value); |
| } |
| } |
| } |
| |
| fn write_self_field_assign_value(&self, w: &mut CodeWriter, value: &str, ty: &RustType) { |
| match self.kind { |
| FieldKind::Repeated(..) | FieldKind::Map(..) => { |
| let converted = ty.into_target(&self.full_storage_type(), value, &self.customize); |
| self.write_self_field_assign(w, &converted); |
| } |
| FieldKind::Singular(SingularField { ref elem, ref flag }) => { |
| let converted = ty.into_target(&elem.rust_storage_type(), value, &self.customize); |
| let wrapped = if *flag == SingularFieldFlag::WithoutFlag { |
| converted |
| } else { |
| self.full_storage_type().wrap_value(&converted) |
| }; |
| self.write_self_field_assign(w, &wrapped); |
| } |
| FieldKind::Oneof(..) => unreachable!(), |
| } |
| } |
| |
| fn write_self_field_assign_default(&self, w: &mut CodeWriter) { |
| assert!(self.is_singular()); |
| if self.is_oneof() { |
| let self_field_oneof = self.self_field_oneof(); |
| w.write_line(format!( |
| "{} = ::std::option::Option::Some({}({}))", |
| self_field_oneof, |
| self.variant_path(), |
| // TODO: default from .proto is not needed here (?) |
| self.element_default_value_rust() |
| .into_type(self.full_storage_iter_elem_type(), &self.customize) |
| .value |
| )); |
| } else { |
| // Note it is different from C++ protobuf, where field is initialized |
| // with default value |
| match self.full_storage_type() { |
| RustType::SingularField(..) | RustType::SingularPtrField(..) => { |
| let self_field = self.self_field(); |
| w.write_line(&format!("{}.set_default();", self_field)); |
| } |
| _ => { |
| self.write_self_field_assign_some( |
| w, |
| &self |
| .elem() |
| .rust_storage_type() |
| .default_value_typed(&self.customize) |
| .into_type(self.elem().rust_storage_type(), &self.customize) |
| .value, |
| ); |
| } |
| } |
| } |
| } |
| |
| fn self_field_vec_packed_fixed_data_size(&self) -> String { |
| assert!(self.is_fixed()); |
| format!( |
| "({}.len() * {}) as u32", |
| self.self_field(), |
| field_type_size(self.proto_type).unwrap() |
| ) |
| } |
| |
| fn self_field_vec_packed_varint_data_size(&self) -> String { |
| assert!(!self.is_fixed()); |
| let fn_name = if self.is_enum() { |
| "vec_packed_enum_data_size".to_string() |
| } else { |
| let zigzag_suffix = if self.is_zigzag() { "_zigzag" } else { "" }; |
| format!("vec_packed_varint{}_data_size", zigzag_suffix) |
| }; |
| format!( |
| "{}::rt::{}(&{})", |
| protobuf_crate_path(&self.customize), |
| fn_name, |
| self.self_field() |
| ) |
| } |
| |
| fn self_field_vec_packed_data_size(&self) -> String { |
| assert!(self.is_repeated_not_map()); |
| if self.is_fixed() { |
| self.self_field_vec_packed_fixed_data_size() |
| } else { |
| self.self_field_vec_packed_varint_data_size() |
| } |
| } |
| |
| fn self_field_vec_packed_fixed_size(&self) -> String { |
| // zero is filtered outside |
| format!( |
| "{} + {}::rt::compute_raw_varint32_size({}) + {}", |
| self.tag_size(), |
| protobuf_crate_path(&self.customize), |
| self.self_field_vec_packed_fixed_data_size(), |
| self.self_field_vec_packed_fixed_data_size() |
| ) |
| } |
| |
| fn self_field_vec_packed_varint_size(&self) -> String { |
| // zero is filtered outside |
| assert!(!self.is_fixed()); |
| let fn_name = if self.is_enum() { |
| "vec_packed_enum_size".to_string() |
| } else { |
| let zigzag_suffix = if self.is_zigzag() { "_zigzag" } else { "" }; |
| format!("vec_packed_varint{}_size", zigzag_suffix) |
| }; |
| format!( |
| "{}::rt::{}({}, &{})", |
| protobuf_crate_path(&self.customize), |
| fn_name, |
| self.proto_field.number(), |
| self.self_field() |
| ) |
| } |
| |
| fn self_field_oneof(&self) -> String { |
| format!("self.{}", self.oneof().oneof_rust_field_name) |
| } |
| |
| pub fn clear_field_func(&self) -> String { |
| format!("clear_{}", self.rust_name) |
| } |
| |
| // Write `merge_from` part for this singular or repeated field |
| // of type message, string or bytes |
| fn write_merge_from_field_message_string_bytes(&self, w: &mut CodeWriter) { |
| let singular_or_repeated = match self.kind { |
| FieldKind::Repeated(..) => "repeated", |
| FieldKind::Singular(SingularField { |
| flag: SingularFieldFlag::WithFlag { .. }, |
| .. |
| }) => "singular", |
| FieldKind::Singular(SingularField { |
| flag: SingularFieldFlag::WithoutFlag, |
| .. |
| }) => "singular_proto3", |
| FieldKind::Map(..) | FieldKind::Oneof(..) => unreachable!(), |
| }; |
| let carllerche = match self.kind.primitive_type_variant() { |
| PrimitiveTypeVariant::Carllerche => "carllerche_", |
| PrimitiveTypeVariant::Default => "", |
| }; |
| let type_name_for_fn = protobuf_name(self.proto_type); |
| w.write_line(&format!( |
| "::protobuf::rt::read_{}_{}{}_into(wire_type, is, &mut self.{})?;", |
| singular_or_repeated, carllerche, type_name_for_fn, self.rust_name |
| )); |
| } |
| |
| fn write_error_unexpected_wire_type(&self, wire_type_var: &str, w: &mut CodeWriter) { |
| w.write_line(&format!( |
| "return ::std::result::Result::Err({}::rt::unexpected_wire_type({}));", |
| protobuf_crate_path(&self.customize), |
| wire_type_var |
| )); |
| } |
| |
| fn write_assert_wire_type(&self, wire_type_var: &str, w: &mut CodeWriter) { |
| w.if_stmt( |
| &format!( |
| "{} != ::protobuf::wire_format::{:?}", |
| wire_type_var, self.wire_type |
| ), |
| |w| { |
| self.write_error_unexpected_wire_type(wire_type_var, w); |
| }, |
| ); |
| } |
| |
| // Write `merge_from` part for this oneof field |
| fn write_merge_from_oneof(&self, f: &OneofField, wire_type_var: &str, w: &mut CodeWriter) { |
| self.write_assert_wire_type(wire_type_var, w); |
| |
| let typed = RustValueTyped { |
| value: format!( |
| "{}?", |
| self.proto_type.read("is", f.elem.primitive_type_variant()) |
| ), |
| rust_type: self.full_storage_iter_elem_type(), |
| }; |
| |
| let maybe_boxed = if f.boxed { |
| typed.boxed(&self.customize) |
| } else { |
| typed |
| }; |
| |
| w.write_line(&format!( |
| "self.{} = ::std::option::Option::Some({}({}));", |
| self.oneof().oneof_rust_field_name, |
| self.variant_path(), |
| maybe_boxed.value |
| )); // TODO: into_type |
| } |
| |
| // Write `merge_from` part for this map field |
| fn write_merge_from_map(&self, w: &mut CodeWriter) { |
| let &MapField { |
| ref key, ref value, .. |
| } = self.map(); |
| w.write_line(&format!( |
| "::protobuf::rt::read_map_into::<{}, {}>(wire_type, is, &mut {})?;", |
| key.lib_protobuf_type(&self.customize), |
| value.lib_protobuf_type(&self.customize), |
| self.self_field() |
| )); |
| } |
| |
| // Write `merge_from` part for this singular field |
| fn write_merge_from_singular(&self, wire_type_var: &str, w: &mut CodeWriter) { |
| let field = match self.kind { |
| FieldKind::Singular(ref field) => field, |
| _ => panic!(), |
| }; |
| |
| match field.elem { |
| FieldElem::Message(..) |
| | FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_STRING, ..) |
| | FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_BYTES, ..) => { |
| self.write_merge_from_field_message_string_bytes(w); |
| } |
| FieldElem::Enum(..) => { |
| let version = match field.flag { |
| SingularFieldFlag::WithFlag { .. } => "proto2", |
| SingularFieldFlag::WithoutFlag => "proto3", |
| }; |
| w.write_line(&format!( |
| "::protobuf::rt::read_{}_enum_with_unknown_fields_into({}, is, &mut self.{}, {}, &mut self.unknown_fields)?", |
| version, |
| wire_type_var, |
| self.rust_name, |
| self.proto_field.number() |
| )); |
| } |
| _ => { |
| let read_proc = format!( |
| "{}?", |
| self.proto_type.read("is", PrimitiveTypeVariant::Default) |
| ); |
| |
| self.write_assert_wire_type(wire_type_var, w); |
| w.write_line(&format!("let tmp = {};", read_proc)); |
| self.write_self_field_assign_some(w, "tmp"); |
| } |
| } |
| } |
| |
| // Write `merge_from` part for this repeated field |
| fn write_merge_from_repeated(&self, wire_type_var: &str, w: &mut CodeWriter) { |
| let field = match self.kind { |
| FieldKind::Repeated(ref field) => field, |
| _ => panic!(), |
| }; |
| |
| match field.elem { |
| FieldElem::Message(..) |
| | FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_STRING, ..) |
| | FieldElem::Primitive(FieldDescriptorProto_Type::TYPE_BYTES, ..) => { |
| self.write_merge_from_field_message_string_bytes(w); |
| } |
| FieldElem::Enum(..) => { |
| w.write_line(&format!( |
| "::protobuf::rt::read_repeated_enum_with_unknown_fields_into({}, is, &mut self.{}, {}, &mut self.unknown_fields)?", |
| wire_type_var, |
| self.rust_name, |
| self.proto_field.number() |
| )); |
| } |
| _ => { |
| w.write_line(&format!( |
| "{}::rt::read_repeated_{}_into({}, is, &mut self.{})?;", |
| protobuf_crate_path(&self.customize), |
| protobuf_name(self.proto_type), |
| wire_type_var, |
| self.rust_name |
| )); |
| } |
| } |
| } |
| |
| // Write `merge_from` part for this field |
| pub fn write_merge_from_field(&self, wire_type_var: &str, w: &mut CodeWriter) { |
| match self.kind { |
| FieldKind::Oneof(ref f) => self.write_merge_from_oneof(&f, wire_type_var, w), |
| FieldKind::Map(..) => self.write_merge_from_map(w), |
| FieldKind::Singular(..) => self.write_merge_from_singular(wire_type_var, w), |
| FieldKind::Repeated(..) => self.write_merge_from_repeated(wire_type_var, w), |
| } |
| } |
| |
| fn self_field_vec_packed_size(&self) -> String { |
| match self.kind { |
| FieldKind::Repeated(RepeatedField { packed: true, .. }) => { |
| // zero is filtered outside |
| if self.is_fixed() { |
| self.self_field_vec_packed_fixed_size() |
| } else { |
| self.self_field_vec_packed_varint_size() |
| } |
| } |
| _ => { |
| panic!("not packed"); |
| } |
| } |
| } |
| |
| pub fn write_element_size( |
| &self, |
| w: &mut CodeWriter, |
| item_var: &str, |
| item_var_type: &RustType, |
| sum_var: &str, |
| ) { |
| assert!(!self.is_repeated_packed()); |
| |
| match self.proto_type { |
| FieldDescriptorProto_Type::TYPE_MESSAGE => { |
| w.write_line(&format!("let len = {}.compute_size();", item_var)); |
| let tag_size = self.tag_size(); |
| w.write_line(&format!( |
| "{} += {} + ::protobuf::rt::compute_raw_varint32_size(len) + len;", |
| sum_var, tag_size |
| )); |
| } |
| _ => { |
| w.write_line(&format!( |
| "{} += {};", |
| sum_var, |
| self.element_size(item_var, item_var_type) |
| )); |
| } |
| } |
| } |
| |
| pub fn write_message_write_field(&self, w: &mut CodeWriter) { |
| match self.kind { |
| FieldKind::Singular(..) => { |
| self.write_if_let_self_field_is_some(w, |v, v_type, w| { |
| self.write_write_element(w, "os", v, v_type); |
| }); |
| } |
| FieldKind::Repeated(RepeatedField { packed: false, .. }) => { |
| self.write_for_self_field(w, "v", |w, v_type| { |
| self.write_write_element(w, "os", "v", v_type); |
| }); |
| } |
| FieldKind::Repeated(RepeatedField { packed: true, .. }) => { |
| self.write_if_self_field_is_not_empty(w, |w| { |
| let number = self.proto_field.number(); |
| w.write_line(&format!( |
| "os.write_tag({}, {}::wire_format::{:?})?;", |
| number, |
| protobuf_crate_path(&self.customize), |
| wire_format::WireTypeLengthDelimited |
| )); |
| w.comment("TODO: Data size is computed again, it should be cached"); |
| let data_size_expr = self.self_field_vec_packed_data_size(); |
| w.write_line(&format!("os.write_raw_varint32({})?;", data_size_expr)); |
| self.write_for_self_field(w, "v", |w, v_type| { |
| let param_type = self.os_write_fn_param_type(); |
| let os_write_fn_suffix = self.os_write_fn_suffix(); |
| w.write_line(&format!( |
| "os.write_{}_no_tag({})?;", |
| os_write_fn_suffix, |
| v_type.into_target(¶m_type, "v", &self.customize) |
| )); |
| }); |
| }); |
| } |
| FieldKind::Map(MapField { |
| ref key, ref value, .. |
| }) => { |
| w.write_line(&format!( |
| "::protobuf::rt::write_map_with_cached_sizes::<{}, {}>({}, &{}, os)?;", |
| key.lib_protobuf_type(&self.customize), |
| value.lib_protobuf_type(&self.customize), |
| self.proto_field.number(), |
| self.self_field() |
| )); |
| } |
| FieldKind::Oneof(..) => unreachable!(), |
| }; |
| } |
| |
| pub fn write_message_compute_field_size(&self, sum_var: &str, w: &mut CodeWriter) { |
| match self.kind { |
| FieldKind::Singular(..) => { |
| self.write_if_let_self_field_is_some(w, |v, v_type, w| { |
| match field_type_size(self.proto_type) { |
| Some(s) => { |
| let tag_size = self.tag_size(); |
| w.write_line(&format!("{} += {};", sum_var, (s + tag_size) as isize)); |
| } |
| None => { |
| self.write_element_size(w, v, v_type, sum_var); |
| } |
| }; |
| }); |
| } |
| FieldKind::Repeated(RepeatedField { packed: false, .. }) => { |
| match field_type_size(self.proto_type) { |
| Some(s) => { |
| let tag_size = self.tag_size(); |
| let self_field = self.self_field(); |
| w.write_line(&format!( |
| "{} += {} * {}.len() as u32;", |
| sum_var, |
| (s + tag_size) as isize, |
| self_field |
| )); |
| } |
| None => { |
| self.write_for_self_field(w, "value", |w, value_type| { |
| self.write_element_size(w, "value", value_type, sum_var); |
| }); |
| } |
| }; |
| } |
| FieldKind::Map(MapField { |
| ref key, ref value, .. |
| }) => { |
| w.write_line(&format!( |
| "{} += {}::rt::compute_map_size::<{}, {}>({}, &{});", |
| sum_var, |
| protobuf_crate_path(&self.customize), |
| key.lib_protobuf_type(&self.customize), |
| value.lib_protobuf_type(&self.customize), |
| self.proto_field.number(), |
| self.self_field() |
| )); |
| } |
| FieldKind::Repeated(RepeatedField { packed: true, .. }) => { |
| self.write_if_self_field_is_not_empty(w, |w| { |
| let size_expr = self.self_field_vec_packed_size(); |
| w.write_line(&format!("{} += {};", sum_var, size_expr)); |
| }); |
| } |
| FieldKind::Oneof(..) => unreachable!(), |
| } |
| } |
| |
| fn write_message_field_get_singular(&self, w: &mut CodeWriter) { |
| let get_xxx_return_type = self.get_xxx_return_type(); |
| |
| if self.proto_type == FieldDescriptorProto_Type::TYPE_MESSAGE { |
| let self_field = self.self_field(); |
| let ref rust_type_message = match self.elem().rust_storage_type() { |
| RustType::Message(m) => m, |
| _ => unreachable!(), |
| }; |
| w.write_line(&format!( |
| "{}.as_ref().unwrap_or_else(|| {})", |
| self_field, |
| rust_type_message.default_instance(&self.customize) |
| )); |
| } else { |
| let get_xxx_default_value_rust = self.get_xxx_default_value_rust(); |
| let self_field = self.self_field(); |
| match self.singular() { |
| &SingularField { |
| flag: SingularFieldFlag::WithFlag { .. }, |
| .. |
| } => { |
| if get_xxx_return_type.is_ref() { |
| let as_option = self.self_field_as_option(); |
| w.match_expr(&as_option.value, |w| { |
| let v_type = as_option.rust_type.elem_type(); |
| let r_type = self.get_xxx_return_type(); |
| w.case_expr( |
| "Some(v)", |
| v_type.into_target(&r_type, "v", &self.customize), |
| ); |
| let get_xxx_default_value_rust = self.get_xxx_default_value_rust(); |
| w.case_expr("None", get_xxx_default_value_rust); |
| }); |
| } else { |
| w.write_line(&format!( |
| "{}.unwrap_or({})", |
| self_field, get_xxx_default_value_rust |
| )); |
| } |
| } |
| &SingularField { |
| flag: SingularFieldFlag::WithoutFlag, |
| .. |
| } => { |
| w.write_line(self.full_storage_type().into_target( |
| &get_xxx_return_type, |
| &self_field, |
| &self.customize, |
| )); |
| } |
| } |
| } |
| } |
| |
| fn write_message_field_get(&self, w: &mut CodeWriter) { |
| let get_xxx_return_type = self.get_xxx_return_type(); |
| let fn_def = format!( |
| "get_{}(&self) -> {}", |
| self.rust_name, |
| get_xxx_return_type.to_code(&self.customize) |
| ); |
| |
| w.pub_fn(&fn_def, |w| match self.kind { |
| FieldKind::Oneof(OneofField { ref elem, .. }) => { |
| let self_field_oneof = self.self_field_oneof(); |
| w.match_expr(self_field_oneof, |w| { |
| let (refv, vtype) = if !self.elem_type_is_copy() { |
| ("ref v", elem.rust_storage_type().ref_type()) |
| } else { |
| ("v", elem.rust_storage_type()) |
| }; |
| w.case_expr( |
| format!( |
| "::std::option::Option::Some({}({}))", |
| self.variant_path(), |
| refv |
| ), |
| vtype.into_target(&get_xxx_return_type, "v", &self.customize), |
| ); |
| w.case_expr("_", self.get_xxx_default_value_rust()); |
| }) |
| } |
| FieldKind::Singular(..) => { |
| self.write_message_field_get_singular(w); |
| } |
| FieldKind::Repeated(..) | FieldKind::Map(..) => { |
| let self_field = self.self_field(); |
| w.write_line(&format!("&{}", self_field)); |
| } |
| }); |
| } |
| |
| fn has_has(&self) -> bool { |
| match self.kind { |
| FieldKind::Repeated(..) | FieldKind::Map(..) => false, |
| FieldKind::Singular(SingularField { |
| flag: SingularFieldFlag::WithFlag { .. }, |
| .. |
| }) => true, |
| FieldKind::Singular(SingularField { |
| flag: SingularFieldFlag::WithoutFlag, |
| .. |
| }) => false, |
| FieldKind::Oneof(..) => true, |
| } |
| } |
| |
| fn has_mut(&self) -> bool { |
| match self.kind { |
| FieldKind::Repeated(..) | FieldKind::Map(..) => true, |
| // TODO: string should be public, and mut is not needed |
| FieldKind::Singular(..) | FieldKind::Oneof(..) => !self.elem_type_is_copy(), |
| } |
| } |
| |
| fn has_take(&self) -> bool { |
| match self.kind { |
| FieldKind::Repeated(..) | FieldKind::Map(..) => true, |
| // TODO: string should be public, and mut is not needed |
| FieldKind::Singular(..) | FieldKind::Oneof(..) => !self.elem_type_is_copy(), |
| } |
| } |
| |
| fn has_name(&self) -> String { |
| format!("has_{}", self.rust_name) |
| } |
| |
| fn write_message_field_has(&self, w: &mut CodeWriter) { |
| w.pub_fn(&format!("{}(&self) -> bool", self.has_name()), |w| { |
| if !self.is_oneof() { |
| let self_field_is_some = self.self_field_is_some(); |
| w.write_line(self_field_is_some); |
| } else { |
| let self_field_oneof = self.self_field_oneof(); |
| w.match_expr(self_field_oneof, |w| { |
| w.case_expr( |
| format!("::std::option::Option::Some({}(..))", self.variant_path()), |
| "true", |
| ); |
| w.case_expr("_", "false"); |
| }); |
| } |
| }); |
| } |
| |
| fn write_message_field_set(&self, w: &mut CodeWriter) { |
| let set_xxx_param_type = self.set_xxx_param_type(); |
| w.comment("Param is passed by value, moved"); |
| let ref name = self.rust_name; |
| w.pub_fn( |
| &format!( |
| "set_{}(&mut self, v: {})", |
| name, |
| set_xxx_param_type.to_code(&self.customize) |
| ), |
| |w| { |
| if !self.is_oneof() { |
| self.write_self_field_assign_value(w, "v", &set_xxx_param_type); |
| } else { |
| let self_field_oneof = self.self_field_oneof(); |
| let v = set_xxx_param_type.into_target( |
| &self.oneof().rust_type(), |
| "v", |
| &self.customize, |
| ); |
| w.write_line(&format!( |
| "{} = ::std::option::Option::Some({}({}))", |
| self_field_oneof, |
| self.variant_path(), |
| v |
| )); |
| } |
| }, |
| ); |
| } |
| |
| fn write_message_field_mut(&self, w: &mut CodeWriter) { |
| let mut_xxx_return_type = self.mut_xxx_return_type(); |
| w.comment("Mutable pointer to the field."); |
| if self.is_singular() { |
| w.comment("If field is not initialized, it is initialized with default value first."); |
| } |
| let fn_def = match mut_xxx_return_type { |
| RustType::Ref(ref param) => format!( |
| "mut_{}(&mut self) -> &mut {}", |
| self.rust_name, |
| param.to_code(&self.customize) |
| ), |
| _ => panic!( |
| "not a ref: {}", |
| mut_xxx_return_type.to_code(&self.customize) |
| ), |
| }; |
| w.pub_fn(&fn_def, |w| { |
| match self.kind { |
| FieldKind::Repeated(..) | FieldKind::Map(..) => { |
| let self_field = self.self_field(); |
| w.write_line(&format!("&mut {}", self_field)); |
| } |
| FieldKind::Singular(SingularField { |
| flag: SingularFieldFlag::WithFlag { .. }, |
| .. |
| }) => { |
| self.write_if_self_field_is_none(w, |w| { |
| self.write_self_field_assign_default(w); |
| }); |
| let self_field = self.self_field(); |
| w.write_line(&format!("{}.as_mut().unwrap()", self_field)); |
| } |
| FieldKind::Singular(SingularField { |
| flag: SingularFieldFlag::WithoutFlag, |
| .. |
| }) => w.write_line(&format!("&mut {}", self.self_field())), |
| FieldKind::Oneof(..) => { |
| let self_field_oneof = self.self_field_oneof(); |
| |
| // if oneof does not contain current field |
| w.if_let_else_stmt( |
| &format!("::std::option::Option::Some({}(_))", self.variant_path())[..], |
| &self_field_oneof[..], |
| |w| { |
| // initialize it with default value |
| w.write_line(&format!( |
| "{} = ::std::option::Option::Some({}({}));", |
| self_field_oneof, |
| self.variant_path(), |
| self.element_default_value_rust() |
| .into_type(self.oneof().rust_type(), &self.customize) |
| .value |
| )); |
| }, |
| ); |
| |
| // extract field |
| w.match_expr(self_field_oneof, |w| { |
| w.case_expr( |
| format!( |
| "::std::option::Option::Some({}(ref mut v))", |
| self.variant_path() |
| ), |
| "v", |
| ); |
| w.case_expr("_", "panic!()"); |
| }); |
| } |
| } |
| }); |
| } |
| |
| fn write_message_field_take_oneof(&self, w: &mut CodeWriter) { |
| let take_xxx_return_type = self.take_xxx_return_type(); |
| |
| // TODO: replace with if let |
| w.write_line(&format!("if self.{}() {{", self.has_name())); |
| w.indented(|w| { |
| let self_field_oneof = self.self_field_oneof(); |
| w.match_expr(format!("{}.take()", self_field_oneof), |w| { |
| let value_in_some = self.oneof().rust_type().value("v".to_owned()); |
| let converted = |
| value_in_some.into_type(self.take_xxx_return_type(), &self.customize); |
| w.case_expr( |
| format!("::std::option::Option::Some({}(v))", self.variant_path()), |
| &converted.value, |
| ); |
| w.case_expr("_", "panic!()"); |
| }); |
| }); |
| w.write_line("} else {"); |
| w.indented(|w| { |
| w.write_line( |
| self.elem() |
| .rust_storage_type() |
| .default_value_typed(&self.customize) |
| .into_type(take_xxx_return_type.clone(), &self.customize) |
| .value, |
| ); |
| }); |
| w.write_line("}"); |
| } |
| |
| fn write_message_field_take(&self, w: &mut CodeWriter) { |
| let take_xxx_return_type = self.take_xxx_return_type(); |
| w.comment("Take field"); |
| w.pub_fn( |
| &format!( |
| "take_{}(&mut self) -> {}", |
| self.rust_name, |
| take_xxx_return_type.to_code(&self.customize) |
| ), |
| |w| match self.kind { |
| FieldKind::Oneof(..) => { |
| self.write_message_field_take_oneof(w); |
| } |
| FieldKind::Repeated(..) | FieldKind::Map(..) => { |
| w.write_line(&format!( |
| "::std::mem::replace(&mut self.{}, {})", |
| self.rust_name, |
| take_xxx_return_type.default_value(&self.customize) |
| )); |
| } |
| FieldKind::Singular(SingularField { |
| ref elem, |
| flag: SingularFieldFlag::WithFlag { .. }, |
| }) => { |
| if !elem.is_copy() { |
| w.write_line(&format!( |
| "{}.take().unwrap_or_else(|| {})", |
| self.self_field(), |
| elem.rust_storage_type().default_value(&self.customize) |
| )); |
| } else { |
| w.write_line(&format!( |
| "{}.take().unwrap_or({})", |
| self.self_field(), |
| self.element_default_value_rust().value |
| )); |
| } |
| } |
| FieldKind::Singular(SingularField { |
| flag: SingularFieldFlag::WithoutFlag, |
| .. |
| }) => w.write_line(&format!( |
| "::std::mem::replace(&mut {}, {})", |
| self.self_field(), |
| self.full_storage_type().default_value(&self.customize) |
| )), |
| }, |
| ); |
| } |
| |
| pub fn write_message_single_field_accessors(&self, w: &mut CodeWriter) { |
| // TODO: do not generate `get` when !proto2 and !generate_accessors` |
| w.write_line(""); |
| self.write_message_field_get(w); |
| |
| if !self.generate_accessors { |
| return; |
| } |
| |
| let clear_field_func = self.clear_field_func(); |
| w.pub_fn(&format!("{}(&mut self)", clear_field_func), |w| { |
| self.write_clear(w); |
| }); |
| |
| if self.has_has() { |
| w.write_line(""); |
| self.write_message_field_has(w); |
| } |
| |
| w.write_line(""); |
| self.write_message_field_set(w); |
| |
| if self.has_mut() { |
| w.write_line(""); |
| self.write_message_field_mut(w); |
| } |
| |
| if self.has_take() { |
| w.write_line(""); |
| self.write_message_field_take(w); |
| } |
| } |
| } |
| |
| pub(crate) fn rust_field_name_for_protobuf_field_name(name: &str) -> RustIdent { |
| if rust::is_rust_keyword(name) { |
| RustIdent::new(&format!("field_{}", name)) |
| } else { |
| RustIdent::new(name) |
| } |
| } |