use std::marker; use float; use inside::protobuf_crate_path; use message::RustTypeMessage; use oneof::OneofField; use protobuf::descriptor::*; use protobuf::rt; use protobuf::rust; use protobuf::text_format; use protobuf::wire_format; 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 syntax::Syntax; use super::code_writer::CodeWriter; use super::customize::customize_from_rustproto_for_field; use super::customize::Customize; use super::enums::*; use super::rust_types_values::*; 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::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 { 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>>, 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) { 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, customize, ); 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, 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, 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: 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 { 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 { 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!( "{}::rt::bytes_size({}, &{})", protobuf_crate_path(&self.customize), self.proto_field.number(), var ), FieldDescriptorProto_Type::TYPE_STRING => format!( "{}::rt::string_size({}, &{})", protobuf_crate_path(&self.customize), 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!( "{}::rt::enum_size({}, {})", protobuf_crate_path(&self.customize), 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!( "{}::rt::value_varint_zigzag_size({}, {})", protobuf_crate_path(&self.customize), self.proto_field.number(), var_type.into_target(¶m_type, var, &self.customize) ) } else { format!( "{}::rt::value_size({}, {}, {}::wire_format::{:?})", protobuf_crate_path(&self.customize), self.proto_field.number(), var_type.into_target(¶m_type, var, &self.customize), protobuf_crate_path(&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({}, {}::wire_format::{:?})?;", os, self.proto_field.number(), protobuf_crate_path(&self.customize), 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(&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(&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(&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(&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, &self.customize), ); } &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.customize) }; 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!( "{}::rt::read_{}_{}{}_into(wire_type, is, &mut self.{})?;", protobuf_crate_path(&self.customize), 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!( "{} != {}::wire_format::{:?}", wire_type_var, protobuf_crate_path(&self.customize), 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!( "{}::rt::read_map_into::<{}, {}>(wire_type, is, &mut {})?;", protobuf_crate_path(&self.customize), 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!( "{}::rt::read_{}_enum_with_unknown_fields_into({}, is, &mut self.{}, {}, &mut self.unknown_fields)?", protobuf_crate_path(&self.customize), 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!( "{}::rt::read_repeated_enum_with_unknown_fields_into({}, is, &mut self.{}, {}, &mut self.unknown_fields)?", protobuf_crate_path(&self.customize), 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!( "{} += {} + {}::rt::compute_raw_varint32_size(len) + len;", sum_var, tag_size, protobuf_crate_path(&self.customize) )); } _ => { 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!( "{}::rt::write_map_with_cached_sizes::<{}, {}>({}, &{}, os)?;", 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::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) } }