aboutsummaryrefslogtreecommitdiff
path: root/src/gen/field/accessor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/gen/field/accessor.rs')
-rw-r--r--src/gen/field/accessor.rs241
1 files changed, 241 insertions, 0 deletions
diff --git a/src/gen/field/accessor.rs b/src/gen/field/accessor.rs
new file mode 100644
index 0000000..26f0ef4
--- /dev/null
+++ b/src/gen/field/accessor.rs
@@ -0,0 +1,241 @@
+use crate::gen::code_writer::CodeWriter;
+use crate::gen::field::elem::FieldElem;
+use crate::gen::field::elem::FieldElemEnum;
+use crate::gen::field::option_kind::OptionKind;
+use crate::gen::field::repeated::RepeatedField;
+use crate::gen::field::repeated::RepeatedFieldKind;
+use crate::gen::field::singular::SingularField;
+use crate::gen::field::singular::SingularFieldFlag;
+use crate::gen::field::FieldGen;
+use crate::gen::field::FieldKind;
+use crate::gen::field::MapField;
+use crate::gen::inside::protobuf_crate_path;
+use crate::gen::oneof::OneofField;
+use crate::gen::rust_types_values::RustType;
+use crate::gen::scope::WithScope;
+
+struct AccessorFn {
+ name: String,
+ // function type params after first underscore
+ type_params: Vec<String>,
+ callback_params: Vec<String>,
+}
+
+impl AccessorFn {
+ 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
+ }
+}
+
+impl FieldGen<'_> {
+ fn make_accessor_fns_lambda(&self) -> Vec<String> {
+ let message = self.proto_field.message.rust_name();
+ vec![
+ format!("|m: &{}| {{ &m.{} }}", message, self.rust_name),
+ format!("|m: &mut {}| {{ &mut m.{} }}", message, self.rust_name),
+ ]
+ }
+
+ fn make_accessor_fns_has_get_set(&self) -> Vec<String> {
+ let message = self.proto_field.message.rust_name();
+ vec![
+ format!("{}::{}", message, self.has_name()),
+ format!("{}::{}", message, self.rust_name),
+ format!("{}::{}", message, self.set_name()),
+ ]
+ }
+
+ fn make_accessor_fns_has_get_mut_set(&self) -> Vec<String> {
+ let message = self.proto_field.message.rust_name();
+ vec![
+ format!("{}::{}", message, self.has_name()),
+ format!("{}::{}", message, self.rust_name),
+ format!("{}::{}", message, self.mut_name()),
+ format!("{}::{}", message, self.set_name()),
+ ]
+ }
+
+ fn accessor_fn_map(&self, map_field: &MapField) -> AccessorFn {
+ let MapField { .. } = map_field;
+ AccessorFn {
+ name: "make_map_simpler_accessor".to_owned(),
+ type_params: vec![format!("_"), format!("_")],
+ callback_params: self.make_accessor_fns_lambda(),
+ }
+ }
+
+ fn accessor_fn_repeated(&self, repeated_field: &RepeatedField) -> AccessorFn {
+ let RepeatedField { .. } = repeated_field;
+ let name = match repeated_field.kind() {
+ RepeatedFieldKind::Vec => "make_vec_simpler_accessor",
+ };
+ AccessorFn {
+ name: name.to_owned(),
+ type_params: vec![format!("_")],
+ callback_params: self.make_accessor_fns_lambda(),
+ }
+ }
+
+ fn accessor_fn_oneof_enum(&self, oneof: &OneofField, en: &FieldElemEnum) -> AccessorFn {
+ let message = self.proto_field.message.rust_name();
+
+ let variant_path = oneof.variant_path(&self.proto_field.message.scope.rust_path_to_file());
+
+ let getter = CodeWriter::with_no_error(|w| {
+ w.expr_block(
+ &format!(
+ "|message: &{}| match &message.{}",
+ message, oneof.oneof_field_name
+ ),
+ |w| {
+ w.case_expr(
+ &format!("::std::option::Option::Some({}(e))", variant_path),
+ "::std::option::Option::Some(*e)",
+ );
+ w.case_expr("_", "::std::option::Option::None");
+ },
+ );
+ });
+
+ let setter = CodeWriter::with_no_error(|w| {
+ w.expr_block(
+ &format!(
+ "|message: &mut {}, e: {}::EnumOrUnknown<{}>|",
+ message,
+ protobuf_crate_path(&self.customize),
+ en.enum_rust_type(&self.file_and_mod())
+ .to_code(&self.customize)
+ ),
+ |w| {
+ w.write_line(&format!(
+ "message.{} = ::std::option::Option::Some({}(e));",
+ oneof.oneof_field_name, variant_path
+ ));
+ },
+ )
+ });
+
+ let default = self.xxx_default_value_rust();
+
+ AccessorFn {
+ name: "make_oneof_enum_accessors".to_owned(),
+ type_params: vec![format!("_")],
+ callback_params: vec![getter, setter, default],
+ }
+ }
+
+ fn accessor_fn_singular_without_flag(&self, _elem: &FieldElem) -> AccessorFn {
+ AccessorFn {
+ name: "make_simpler_field_accessor".to_owned(),
+ type_params: vec![format!("_")],
+ callback_params: self.make_accessor_fns_lambda(),
+ }
+ }
+
+ fn accessor_fn_singular_with_flag(
+ &self,
+ elem: &FieldElem,
+ _option_kind: OptionKind,
+ ) -> AccessorFn {
+ match elem {
+ FieldElem::Message(m) => AccessorFn {
+ name: "make_message_field_accessor".to_owned(),
+ type_params: vec![format!("{}", m.rust_name_relative(&self.file_and_mod()))],
+ callback_params: self.make_accessor_fns_lambda(),
+ },
+ FieldElem::Primitive(..) | FieldElem::Enum(..) => AccessorFn {
+ name: "make_option_accessor".to_owned(),
+ type_params: vec!["_".to_owned()],
+ callback_params: self.make_accessor_fns_lambda(),
+ },
+ FieldElem::Group => {
+ unreachable!("no accessor for group field");
+ }
+ }
+ }
+
+ fn accessor_fn_oneof(&self, oneof: &OneofField) -> AccessorFn {
+ let OneofField { ref elem, .. } = oneof;
+
+ let reference = self
+ .proto_field
+ .message
+ .scope
+ .file_and_mod(self.customize.clone());
+
+ if let FieldElem::Enum(en) = &oneof.elem {
+ return self.accessor_fn_oneof_enum(oneof, en);
+ }
+
+ if elem.is_copy() {
+ return AccessorFn {
+ name: "make_oneof_copy_has_get_set_simpler_accessors".to_owned(),
+ type_params: vec![format!("_")],
+ callback_params: self.make_accessor_fns_has_get_set(),
+ };
+ }
+
+ if let RustType::Message(name) = elem.rust_storage_elem_type(&reference) {
+ return AccessorFn {
+ name: "make_oneof_message_has_get_mut_set_accessor".to_owned(),
+ type_params: vec![format!("{}", name)],
+ callback_params: self.make_accessor_fns_has_get_mut_set(),
+ };
+ }
+
+ // string or bytes
+ AccessorFn {
+ name: "make_oneof_deref_has_get_set_simpler_accessor".to_owned(),
+ type_params: vec![format!("_")],
+ callback_params: self.make_accessor_fns_has_get_set(),
+ }
+ }
+
+ fn accessor_fn(&self) -> AccessorFn {
+ match self.kind {
+ FieldKind::Repeated(ref repeated_field) => self.accessor_fn_repeated(repeated_field),
+ FieldKind::Map(ref map_field) => self.accessor_fn_map(map_field),
+ FieldKind::Singular(SingularField {
+ ref elem,
+ flag: SingularFieldFlag::WithoutFlag,
+ }) => self.accessor_fn_singular_without_flag(elem),
+ FieldKind::Singular(SingularField {
+ ref elem,
+ flag: SingularFieldFlag::WithFlag { option_kind, .. },
+ }) => self.accessor_fn_singular_with_flag(elem, option_kind),
+ FieldKind::Oneof(ref oneof) => self.accessor_fn_oneof(oneof),
+ }
+ }
+
+ pub fn write_push_accessor(&self, fields_var: &str, w: &mut CodeWriter) {
+ let accessor_fn = self.accessor_fn();
+ w.write_line(&format!(
+ "{}.push({}::reflect::rt::v2::{}(",
+ fields_var,
+ protobuf_crate_path(&self.customize),
+ accessor_fn.sig()
+ ));
+ w.indented(|w| {
+ w.write_line(&format!("\"{}\",", self.proto_field.name()));
+ for callback in &accessor_fn.callback_params {
+ let callback_lines: Vec<&str> = callback.lines().collect();
+ for (i, callback_line) in callback_lines.iter().enumerate() {
+ let comma = if i == callback_lines.len() - 1 {
+ ","
+ } else {
+ ""
+ };
+ w.write_line(&format!("{}{}", callback_line, comma));
+ }
+ }
+ });
+ w.write_line("));");
+ }
+}