mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-09 06:30:54 +00:00
Implement Serialize on generated rust types (#7022)
* fix for rust build * Rust: Implement Serialize on generated types For debugging convenience it is really handy to be able to dump out types as another format (ie: json). For example, if we are logging a type to a structured logging system, or even printing it out in a structured way to the console. Right now we handle this by shelling out to `flatc` which is not ideal; by implementing Serialize on the generated types we can use any of the Serializer-implementing packages for our structured debug output. * clang-format * Make the flatbuffers Rust crate only have an optional dependency on the `serde` packages. * fix warning * fix rust test build * Oh yeah this needs to be initialized * fix toml syntax * code review feedback * rebuild test data
This commit is contained in:
@@ -384,6 +384,11 @@ class RustGenerator : public BaseGenerator {
|
||||
code_ += "extern crate flatbuffers;";
|
||||
code_ += "use std::mem;";
|
||||
code_ += "use std::cmp::Ordering;";
|
||||
if (parser_.opts.rust_serialize) {
|
||||
code_ += "extern crate serde;";
|
||||
code_ +=
|
||||
"use self::serde::ser::{Serialize, Serializer, SerializeStruct};";
|
||||
}
|
||||
code_ += "use self::flatbuffers::{EndianScalar, Follow};";
|
||||
code_ += "use super::*;";
|
||||
cur_name_space_ = symbol.defined_namespace;
|
||||
@@ -842,6 +847,26 @@ class RustGenerator : public BaseGenerator {
|
||||
code_.SetValue("INTO_BASE", "self.0");
|
||||
}
|
||||
|
||||
// Implement serde::Serialize
|
||||
if (parser_.opts.rust_serialize) {
|
||||
code_ += "impl Serialize for {{ENUM_NAME}} {";
|
||||
code_ +=
|
||||
" fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>";
|
||||
code_ += " where";
|
||||
code_ += " S: Serializer,";
|
||||
code_ += " {";
|
||||
if (IsBitFlagsEnum(enum_def)) {
|
||||
code_ += " serializer.serialize_u32(self.bits() as u32)";
|
||||
} else {
|
||||
code_ +=
|
||||
" serializer.serialize_unit_variant(\"{{ENUM_NAME}}\", self.0 as "
|
||||
"u32, self.variant_name().unwrap())";
|
||||
}
|
||||
code_ += " }";
|
||||
code_ += "}";
|
||||
code_ += "";
|
||||
}
|
||||
|
||||
// Generate Follow and Push so we can serialize and stuff.
|
||||
code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {";
|
||||
code_ += " type Inner = Self;";
|
||||
@@ -2005,6 +2030,74 @@ class RustGenerator : public BaseGenerator {
|
||||
code_ += " }";
|
||||
code_ += " }";
|
||||
code_ += "}";
|
||||
code_ += "";
|
||||
|
||||
// Implement serde::Serialize
|
||||
if (parser_.opts.rust_serialize) {
|
||||
const auto numFields = struct_def.fields.vec.size();
|
||||
code_.SetValue("NUM_FIELDS", NumToString(numFields));
|
||||
code_ += "impl Serialize for {{STRUCT_NAME}}<'_> {";
|
||||
code_ +=
|
||||
" fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>";
|
||||
code_ += " where";
|
||||
code_ += " S: Serializer,";
|
||||
code_ += " {";
|
||||
if (numFields == 0) {
|
||||
code_ +=
|
||||
" let s = serializer.serialize_struct(\"{{STRUCT_NAME}}\", 0)?;";
|
||||
} else {
|
||||
code_ +=
|
||||
" let mut s = serializer.serialize_struct(\"{{STRUCT_NAME}}\", "
|
||||
"{{NUM_FIELDS}})?;";
|
||||
}
|
||||
ForAllTableFields(struct_def, [&](const FieldDef &field) {
|
||||
const Type &type = field.value.type;
|
||||
if (IsUnion(type)) {
|
||||
if (type.base_type == BASE_TYPE_UNION) {
|
||||
const auto &enum_def = *type.enum_def;
|
||||
code_.SetValue("ENUM_NAME", WrapInNameSpace(enum_def));
|
||||
code_.SetValue("FIELD_TYPE_FIELD_NAME", field.name);
|
||||
|
||||
code_ += " match self.{{FIELD_TYPE_FIELD_NAME}}_type() {";
|
||||
code_ += " {{ENUM_NAME}}::NONE => (),";
|
||||
ForAllUnionObjectVariantsBesidesNone(enum_def, [&] {
|
||||
code_.SetValue("FIELD_TYPE_FIELD_NAME", field.name);
|
||||
code_ += " {{ENUM_NAME}}::{{VARIANT_NAME}} => {";
|
||||
code_ +=
|
||||
" let f = "
|
||||
"self.{{FIELD_TYPE_FIELD_NAME}}_as_{{U_ELEMENT_NAME}}()";
|
||||
code_ +=
|
||||
" .expect(\"Invalid union table, expected "
|
||||
"`{{ENUM_NAME}}::{{VARIANT_NAME}}`.\");";
|
||||
code_ += " s.serialize_field(\"{{FIELD_NAME}}\", &f)?;";
|
||||
code_ += " }";
|
||||
});
|
||||
code_ += " _ => unimplemented!(),";
|
||||
code_ += " }";
|
||||
} else {
|
||||
code_ +=
|
||||
" s.serialize_field(\"{{FIELD_NAME}}\", "
|
||||
"&self.{{FIELD_NAME}}())?;";
|
||||
}
|
||||
} else {
|
||||
if (field.IsOptional()) {
|
||||
code_ += " if let Some(f) = self.{{FIELD_NAME}}() {";
|
||||
code_ += " s.serialize_field(\"{{FIELD_NAME}}\", &f)?;";
|
||||
code_ += " } else {";
|
||||
code_ += " s.skip_field(\"{{FIELD_NAME}}\")?;";
|
||||
code_ += " }";
|
||||
} else {
|
||||
code_ +=
|
||||
" s.serialize_field(\"{{FIELD_NAME}}\", "
|
||||
"&self.{{FIELD_NAME}}())?;";
|
||||
}
|
||||
}
|
||||
});
|
||||
code_ += " s.end()";
|
||||
code_ += " }";
|
||||
code_ += "}";
|
||||
code_ += "";
|
||||
}
|
||||
|
||||
// Generate a builder struct:
|
||||
code_ += "pub struct {{STRUCT_NAME}}Builder<'a: 'b, 'b> {";
|
||||
@@ -2636,6 +2729,36 @@ class RustGenerator : public BaseGenerator {
|
||||
code_ += " v.in_buffer::<Self>(pos)";
|
||||
code_ += " }";
|
||||
code_ += "}";
|
||||
code_ += "";
|
||||
|
||||
// Implement serde::Serialize
|
||||
if (parser_.opts.rust_serialize) {
|
||||
const auto numFields = struct_def.fields.vec.size();
|
||||
code_.SetValue("NUM_FIELDS", NumToString(numFields));
|
||||
code_ += "impl Serialize for {{STRUCT_NAME}} {";
|
||||
code_ +=
|
||||
" fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>";
|
||||
code_ += " where";
|
||||
code_ += " S: Serializer,";
|
||||
code_ += " {";
|
||||
if (numFields == 0) {
|
||||
code_ +=
|
||||
" let s = serializer.serialize_struct(\"{{STRUCT_NAME}}\", 0)?;";
|
||||
} else {
|
||||
code_ +=
|
||||
" let mut s = serializer.serialize_struct(\"{{STRUCT_NAME}}\", "
|
||||
"{{NUM_FIELDS}})?;";
|
||||
}
|
||||
ForAllStructFields(struct_def, [&](const FieldDef &unused) {
|
||||
(void)unused;
|
||||
code_ +=
|
||||
" s.serialize_field(\"{{FIELD_NAME}}\", &self.{{FIELD_NAME}}())?;";
|
||||
});
|
||||
code_ += " s.end()";
|
||||
code_ += " }";
|
||||
code_ += "}";
|
||||
code_ += "";
|
||||
}
|
||||
|
||||
// Generate a constructor that takes all fields as arguments.
|
||||
code_ += "impl<'a> {{STRUCT_NAME}} {";
|
||||
@@ -2834,6 +2957,12 @@ class RustGenerator : public BaseGenerator {
|
||||
code_ += indent + "use std::mem;";
|
||||
code_ += indent + "use std::cmp::Ordering;";
|
||||
code_ += "";
|
||||
if (parser_.opts.rust_serialize) {
|
||||
code_ += indent + "extern crate serde;";
|
||||
code_ += indent +
|
||||
"use self::serde::ser::{Serialize, Serializer, SerializeStruct};";
|
||||
code_ += "";
|
||||
}
|
||||
code_ += indent + "extern crate flatbuffers;";
|
||||
code_ += indent + "use self::flatbuffers::{EndianScalar, Follow};";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user