diff options
author | Casper <casperneo@uchicago.edu> | 2020-12-07 18:37:51 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-07 18:37:51 -0500 |
commit | 442949bc11c4e08a04516390dd78794cd4dec746 (patch) | |
tree | 292275b264f5e50a31255a979e5a0c6cd7ee0ca0 /src | |
parent | 9064072e8cd42be6710b293ad567acd44845f7fc (diff) | |
download | flatbuffers-442949bc11c4e08a04516390dd78794cd4dec746.tar.gz flatbuffers-442949bc11c4e08a04516390dd78794cd4dec746.tar.bz2 flatbuffers-442949bc11c4e08a04516390dd78794cd4dec746.zip |
Rust Flatbuffers Verifier (#6269)
* Updated comments and fixed a fundemental type error.
* bump rust flatbuffers semver
* Initial commit with verifier, need to clean up
* Verifier tested. Needs clean up and refactoring.
* Display for InvalidFlatbuffer and better errors for strings
* SimpleToVerify, some refactoring
* Combined VerifierType TableAccessorFuncBody into FollowType
* scrub todos
* Update Rust get_root functions.
There are 6 variants, with verifier options, default verifier options
and no verification "fast".
* Rename root fns
* inline
* Update to use thiserror
* fix for bad compiler
* improve error formatting
* Replace multiply with saturating_multiply
* saturating adds too
* Add docs disclaiming experimental verification system
Co-authored-by: Casper Neo <cneo@google.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/idl_gen_rust.cpp | 469 |
1 files changed, 284 insertions, 185 deletions
diff --git a/src/idl_gen_rust.cpp b/src/idl_gen_rust.cpp index 3995a7f2..3c17b5cc 100644 --- a/src/idl_gen_rust.cpp +++ b/src/idl_gen_rust.cpp @@ -555,111 +555,93 @@ class RustGenerator : public BaseGenerator { code_ += "pub use self::bitflags_{{ENUM_NAME_SNAKE}}::{{ENUM_NAME}};"; code_ += ""; - // Generate Follow and Push so we can serialize and stuff. - code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {"; - code_ += " type Inner = Self;"; - code_ += " #[inline]"; - code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {"; - code_ += " let bits = flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc);"; - code_ += " unsafe { Self::from_bits_unchecked(bits) }"; - code_ += " }"; - code_ += "}"; + code_.SetValue("FROM_BASE", "unsafe { Self::from_bits_unchecked(b) }"); + code_.SetValue("INTO_BASE", "self.bits()"); + } else { + // Normal, c-modelled enums. + // Deprecated associated constants; + const std::string deprecation_warning = + "#[deprecated(since = \"1.13\", note = \"Use associated constants" + " instead. This will no longer be generated in 2021.\")]"; + code_ += deprecation_warning; + code_ += "pub const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}" + " = {{ENUM_MIN_BASE_VALUE}};"; + code_ += deprecation_warning; + code_ += "pub const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}" + " = {{ENUM_MAX_BASE_VALUE}};"; + auto num_fields = NumToString(enum_def.size()); + code_ += deprecation_warning; + code_ += "#[allow(non_camel_case_types)]"; + code_ += "pub const ENUM_VALUES_{{ENUM_NAME_CAPS}}: [{{ENUM_NAME}}; " + + num_fields + "] = ["; + ForAllEnumValues1(enum_def, [&](const EnumVal &ev){ + code_ += " " + GetEnumValue(enum_def, ev) + ","; + }); + code_ += "];"; code_ += ""; - code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {"; - code_ += " type Output = {{ENUM_NAME}};"; - code_ += " #[inline]"; - code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {"; - code_ += " flatbuffers::emplace_scalar::<{{BASE_TYPE}}>" - "(dst, self.bits());"; - code_ += " }"; - code_ += "}"; + + GenComment(enum_def.doc_comment); + code_ += + "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]"; + code_ += "#[repr(transparent)]"; + code_ += "pub struct {{ENUM_NAME}}(pub {{BASE_TYPE}});"; + code_ += "#[allow(non_upper_case_globals)]"; + code_ += "impl {{ENUM_NAME}} {"; + ForAllEnumValues1(enum_def, [&](const EnumVal &ev){ + this->GenComment(ev.doc_comment, " "); + code_ += " pub const {{VARIANT}}: Self = Self({{VALUE}});"; + }); code_ += ""; - code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {"; - code_ += " #[inline]"; - code_ += " fn to_little_endian(self) -> Self {"; - code_ += " let bits = {{BASE_TYPE}}::to_le(self.bits());"; - code_ += " unsafe { Self::from_bits_unchecked(bits) }"; - code_ += " }"; - code_ += " #[inline]"; - code_ += " fn from_little_endian(self) -> Self {"; - code_ += " let bits = {{BASE_TYPE}}::from_le(self.bits());"; - code_ += " unsafe { Self::from_bits_unchecked(bits) }"; + // Generate Associated constants + code_ += " pub const ENUM_MIN: {{BASE_TYPE}} = {{ENUM_MIN_BASE_VALUE}};"; + code_ += " pub const ENUM_MAX: {{BASE_TYPE}} = {{ENUM_MAX_BASE_VALUE}};"; + code_ += " pub const ENUM_VALUES: &'static [Self] = &["; + ForAllEnumValues(enum_def, [&](){ + code_ += " Self::{{VARIANT}},"; + }); + code_ += " ];"; + code_ += " /// Returns the variant's name or \"\" if unknown."; + code_ += " pub fn variant_name(self) -> Option<&'static str> {"; + code_ += " match self {"; + ForAllEnumValues(enum_def, [&](){ + code_ += " Self::{{VARIANT}} => Some(\"{{VARIANT}}\"),"; + }); + code_ += " _ => None,"; + code_ += " }"; code_ += " }"; code_ += "}"; - code_ += ""; - return; - } - // Deprecated associated constants; - code_ += "#[deprecated(since = \"1.13\", note = \"Use associated constants" - " instead. This will no longer be generated in 2021.\")]"; - code_ += "pub const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}" - " = {{ENUM_MIN_BASE_VALUE}};"; - code_ += "#[deprecated(since = \"1.13\", note = \"Use associated constants" - " instead. This will no longer be generated in 2021.\")]"; - code_ += "pub const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}" - " = {{ENUM_MAX_BASE_VALUE}};"; - auto num_fields = NumToString(enum_def.size()); - code_ += "#[deprecated(since = \"1.13\", note = \"Use associated constants" - " instead. This will no longer be generated in 2021.\")]"; - code_ += "#[allow(non_camel_case_types)]"; - code_ += "pub const ENUM_VALUES_{{ENUM_NAME_CAPS}}: [{{ENUM_NAME}}; " + - num_fields + "] = ["; - ForAllEnumValues1(enum_def, [&](const EnumVal &ev){ - code_ += " " + GetEnumValue(enum_def, ev) + ","; - }); - code_ += "];"; - code_ += ""; + // Generate Debug. Unknown variants are printed like "<UNKNOWN 42>". + code_ += "impl std::fmt::Debug for {{ENUM_NAME}} {"; + code_ += " fn fmt(&self, f: &mut std::fmt::Formatter) ->" + " std::fmt::Result {"; + code_ += " if let Some(name) = self.variant_name() {"; + code_ += " f.write_str(name)"; + code_ += " } else {"; + code_ += " f.write_fmt(format_args!(\"<UNKNOWN {:?}>\", self.0))"; + code_ += " }"; + code_ += " }"; + code_ += "}"; - GenComment(enum_def.doc_comment); - code_ += - "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]"; - code_ += "#[repr(transparent)]"; - code_ += "pub struct {{ENUM_NAME}}(pub {{BASE_TYPE}});"; - code_ += "#[allow(non_upper_case_globals)]"; - code_ += "impl {{ENUM_NAME}} {"; - ForAllEnumValues1(enum_def, [&](const EnumVal &ev){ - this->GenComment(ev.doc_comment, " "); - code_ += " pub const {{VARIANT}}: Self = Self({{VALUE}});"; - }); - code_ += ""; - // Generate Associated constants - code_ += " pub const ENUM_MIN: {{BASE_TYPE}} = {{ENUM_MIN_BASE_VALUE}};"; - code_ += " pub const ENUM_MAX: {{BASE_TYPE}} = {{ENUM_MAX_BASE_VALUE}};"; - code_ += " pub const ENUM_VALUES: &'static [Self] = &["; - ForAllEnumValues(enum_def, [&](){ - code_ += " Self::{{VARIANT}},"; - }); - code_ += " ];"; - code_ += " /// Returns the variant's name or \"\" if unknown."; - code_ += " pub fn variant_name(self) -> Option<&'static str> {"; - code_ += " match self {"; - ForAllEnumValues(enum_def, [&](){ - code_ += " Self::{{VARIANT}} => Some(\"{{VARIANT}}\"),"; - }); - code_ += " _ => None,"; - code_ += " }"; - code_ += " }"; - code_ += "}"; + if (enum_def.is_union) { + // Generate tyoesafe offset(s) for unions + code_.SetValue("NAME", Name(enum_def)); + code_.SetValue("UNION_OFFSET_NAME", Name(enum_def) + "UnionTableOffset"); + code_ += "pub struct {{UNION_OFFSET_NAME}} {}"; + } - // Generate Debug. Unknown variants are printed like "<UNKNOWN 42>". - code_ += "impl std::fmt::Debug for {{ENUM_NAME}} {"; - code_ += " fn fmt(&self, f: &mut std::fmt::Formatter) ->" - " std::fmt::Result {"; - code_ += " if let Some(name) = self.variant_name() {"; - code_ += " f.write_str(name)"; - code_ += " } else {"; - code_ += " f.write_fmt(format_args!(\"<UNKNOWN {:?}>\", self.0))"; - code_ += " }"; - code_ += " }"; - code_ += "}"; + code_.SetValue("FROM_BASE", "Self(b)"); + code_.SetValue("INTO_BASE", "self.0"); + } // Generate Follow and Push so we can serialize and stuff. code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {"; code_ += " type Inner = Self;"; code_ += " #[inline]"; code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {"; - code_ += " Self(flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc))"; + code_ += " let b = flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf," + " loc);"; + code_ += " {{FROM_BASE}}"; code_ += " }"; code_ += "}"; code_ += ""; @@ -668,28 +650,36 @@ class RustGenerator : public BaseGenerator { code_ += " #[inline]"; code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {"; code_ += " flatbuffers::emplace_scalar::<{{BASE_TYPE}}>" - "(dst, self.0);"; + "(dst, {{INTO_BASE}});"; code_ += " }"; code_ += "}"; code_ += ""; code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {"; code_ += " #[inline]"; code_ += " fn to_little_endian(self) -> Self {"; - code_ += " Self({{BASE_TYPE}}::to_le(self.0))"; + code_ += " let b = {{BASE_TYPE}}::to_le({{INTO_BASE}});"; + code_ += " {{FROM_BASE}}"; code_ += " }"; code_ += " #[inline]"; code_ += " fn from_little_endian(self) -> Self {"; - code_ += " Self({{BASE_TYPE}}::from_le(self.0))"; + code_ += " let b = {{BASE_TYPE}}::from_le({{INTO_BASE}});"; + code_ += " {{FROM_BASE}}"; code_ += " }"; code_ += "}"; code_ += ""; - - if (enum_def.is_union) { - // Generate tyoesafe offset(s) for unions - code_.SetValue("NAME", Name(enum_def)); - code_.SetValue("UNION_OFFSET_NAME", Name(enum_def) + "UnionTableOffset"); - code_ += "pub struct {{UNION_OFFSET_NAME}} {}"; - } + // Generate verifier - deferring to the base type. + code_ += "impl<'a> flatbuffers::Verifiable for {{ENUM_NAME}} {"; + code_ += " #[inline]"; + code_ += " fn run_verifier<'o, 'b>("; + code_ += " v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize"; + code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {"; + code_ += " use self::flatbuffers::Verifiable;"; + code_ += " {{BASE_TYPE}}::run_verifier(v, pos)"; + code_ += " }"; + code_ += "}"; + code_ += ""; + // Enums are basically integers. + code_ += "impl flatbuffers::SimpleToVerifyInSlice for {{ENUM_NAME}} {}"; } std::string GetFieldOffsetName(const FieldDef &field) { @@ -1003,109 +993,60 @@ class RustGenerator : public BaseGenerator { return "INVALID_CODE_GENERATION"; // for return analysis } - std::string GenTableAccessorFuncBody(const FieldDef &field, - const std::string &lifetime, - const std::string &offset_prefix) { - const std::string offset_name = - offset_prefix + "::" + GetFieldOffsetName(field); - const Type &type = field.value.type; + std::string FollowType(const Type &type, const std::string &lifetime) { + // IsVector... This can be made iterative? - switch (GetFullType(field.value.type)) { + const auto WrapForwardsUOffset = [](std::string ty) -> std::string { + return "flatbuffers::ForwardsUOffset<" + ty + ">"; + }; + const auto WrapVector = [&](std::string ty) -> std::string { + return "flatbuffers::Vector<" + lifetime + ", " + ty + ">"; + }; + switch (GetFullType(type)) { case ftInteger: case ftFloat: case ftBool: { - const auto typname = GetTypeBasic(type); - if (field.optional) { - return "self._tab.get::<" + typname + ">(" + offset_name + ", None)"; - } else { - const auto default_value = GetDefaultScalarValue(field); - return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" + - default_value + ")).unwrap()"; - } + return GetTypeBasic(type); } case ftStruct: { - const auto typname = WrapInNameSpace(*type.struct_def); - return AddUnwrapIfRequired( - "self._tab.get::<" + typname + ">(" + offset_name + ", None)", - field.required); + return WrapInNameSpace(*type.struct_def); + } + case ftUnionKey: + case ftEnumKey: { + return WrapInNameSpace(*type.enum_def); } case ftTable: { const auto typname = WrapInNameSpace(*type.struct_def); - return AddUnwrapIfRequired( - "self._tab.get::<flatbuffers::ForwardsUOffset<" + typname + "<" + - lifetime + ">>>(" + offset_name + ", None)", - field.required); + return WrapForwardsUOffset(typname); } case ftUnionValue: { - return AddUnwrapIfRequired( - "self._tab.get::<flatbuffers::ForwardsUOffset<" - "flatbuffers::Table<" + - lifetime + ">>>(" + offset_name + ", None)", - field.required); - } - case ftUnionKey: - case ftEnumKey: { - const std::string typname = WrapInNameSpace(*type.enum_def); - const std::string default_value = GetDefaultScalarValue(field); - if (field.optional) { - return "self._tab.get::<" + typname + ">(" + offset_name + ", None)"; - } else { - return "self._tab.get::<" + typname + ">(" + offset_name + ", Some(" + - default_value + ")).unwrap()"; - } + return WrapForwardsUOffset("flatbuffers::Table<" + lifetime + ">"); } case ftString: { - return AddUnwrapIfRequired( - "self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(" + - offset_name + ", None)", - field.required); + return WrapForwardsUOffset("&str"); } - case ftVectorOfInteger: case ftVectorOfBool: case ftVectorOfFloat: { const auto typname = GetTypeBasic(type.VectorType()); - std::string s = - "self._tab.get::<flatbuffers::ForwardsUOffset<" - "flatbuffers::Vector<" + - lifetime + ", " + typname + ">>>(" + offset_name + ", None)"; - // single-byte values are safe to slice - if (IsOneByte(type.VectorType().base_type)) { - s += ".map(|v| v.safe_slice())"; - } - return AddUnwrapIfRequired(s, field.required); + return WrapForwardsUOffset(WrapVector(typname)); } case ftVectorOfEnumKey: { - const auto typname = WrapInNameSpace(*type.enum_def); - return AddUnwrapIfRequired( - "self._tab.get::<flatbuffers::ForwardsUOffset<" - "flatbuffers::Vector<" + - lifetime + ", " + typname + ">>>(" + offset_name + ", None)", - field.required); + const auto typname = WrapInNameSpace(*type.VectorType().enum_def); + return WrapForwardsUOffset(WrapVector(typname)); + } case ftVectorOfStruct: { const auto typname = WrapInNameSpace(*type.struct_def); - return AddUnwrapIfRequired( - "self._tab.get::<flatbuffers::ForwardsUOffset<" - "flatbuffers::Vector<" + - typname + ">>>(" + offset_name + - ", None).map(|v| v.safe_slice() )", - field.required); + return WrapForwardsUOffset(WrapVector(typname)); } case ftVectorOfTable: { const auto typname = WrapInNameSpace(*type.struct_def); - return AddUnwrapIfRequired( - "self._tab.get::<flatbuffers::ForwardsUOffset<" - "flatbuffers::Vector<flatbuffers::ForwardsUOffset<" + - typname + "<" + lifetime + ">>>>>(" + offset_name + ", None)", - field.required); + return WrapForwardsUOffset(WrapVector(WrapForwardsUOffset(typname))); } case ftVectorOfString: { - return AddUnwrapIfRequired( - "self._tab.get::<flatbuffers::ForwardsUOffset<" - "flatbuffers::Vector<flatbuffers::ForwardsUOffset<&" + - lifetime + " str>>>>(" + offset_name + ", None)", - field.required); + return WrapForwardsUOffset(WrapVector(WrapForwardsUOffset( + "&" + lifetime + " str"))); } case ftVectorOfUnionValue: { FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported"); @@ -1115,6 +1056,28 @@ class RustGenerator : public BaseGenerator { return "INVALID_CODE_GENERATION"; // for return analysis } + std::string GenTableAccessorFuncBody(const FieldDef &field, + const std::string &lifetime) { + const std::string vt_offset = GetFieldOffsetName(field); + const std::string typname = FollowType(field.value.type, lifetime); + // Default-y fields (scalars so far) are neither optional nor required. + const std::string default_value = !(field.optional || field.required) ? + "Some(" + GetDefaultScalarValue(field) + ")" : "None"; + const std::string unwrap = field.optional ? "" : ".unwrap()"; + + const auto t = GetFullType(field.value.type); + + // TODO(caspern): Shouldn't 1byte VectorOfEnumKey be slice too? + const std::string safe_slice = ( + t == ftVectorOfStruct || + ((t == ftVectorOfBool || t == ftVectorOfFloat || t == ftVectorOfInteger) + && IsOneByte(field.value.type.VectorType().base_type)) + ) ? ".map(|v| v.safe_slice())" : ""; + + return "self._tab.get::<" + typname + ">({{STRUCT_NAME}}::" + + vt_offset + ", " + default_value + ")" + safe_slice + unwrap; + } + bool TableFieldReturnsOption(const FieldDef &field) { if (field.optional) return true; switch (GetFullType(field.value.type)) { @@ -1272,17 +1235,14 @@ class RustGenerator : public BaseGenerator { // pub fn name(&'a self) -> user_facing_type { // self._tab.get::<internal_type>(offset, defaultval).unwrap() // } - const auto offset_prefix = Name(struct_def); ForAllTableFields(struct_def, [&](const FieldDef &field) { code_.SetValue("RETURN_TYPE", GenTableAccessorFuncReturnType(field, "'a")); - code_.SetValue("FUNC_BODY", - GenTableAccessorFuncBody(field, "'a", offset_prefix)); this->GenComment(field.doc_comment, " "); code_ += " #[inline]"; code_ += " pub fn {{FIELD_NAME}}(&self) -> {{RETURN_TYPE}} {"; - code_ += " {{FUNC_BODY}}"; + code_ += " " + GenTableAccessorFuncBody(field, "'a"); code_ += " }"; // Generate a comparison function for this field if it is a key. @@ -1369,6 +1329,50 @@ class RustGenerator : public BaseGenerator { code_ += "}"; // End of table impl. code_ += ""; + // Generate Verifier; + code_ += "impl flatbuffers::Verifiable for {{STRUCT_NAME}}<'_> {"; + code_ += " #[inline]"; + code_ += " fn run_verifier<'o, 'b>("; + code_ += " v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize"; + code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {"; + code_ += " use self::flatbuffers::Verifiable;"; + code_ += " v.visit_table(pos)?\\"; + // Escape newline and insert it onthe next line so we can end the builder + // with a nice semicolon. + ForAllTableFields(struct_def, [&](const FieldDef &field) { + if (GetFullType(field.value.type) == ftUnionKey) return; + + code_.SetValue("IS_REQ", field.required ? "true" : "false"); + if (GetFullType(field.value.type) != ftUnionValue) { + // All types besides unions. + code_.SetValue("TY", FollowType(field.value.type, "'_")); + code_ += "\n .visit_field::<{{TY}}>(&\"{{FIELD_NAME}}\", " + "Self::{{OFFSET_NAME}}, {{IS_REQ}})?\\"; + return; + } + // Unions. + EnumDef &union_def = *field.value.type.enum_def; + code_.SetValue("UNION_TYPE", Name(union_def)); + code_ += "\n .visit_union::<{{UNION_TYPE}}, _>(" + "&\"{{FIELD_NAME}}_type\", Self::{{OFFSET_NAME}}_TYPE, " + "&\"{{FIELD_NAME}}\", Self::{{OFFSET_NAME}}, {{IS_REQ}}, " + "|key, v, pos| {"; + code_ += " match key {"; + ForAllUnionVariantsBesidesNone(union_def, [&](const EnumVal &unused) { + (void) unused; + code_ += " {{U_ELEMENT_ENUM_TYPE}} => v.verify_union_variant::" + "<flatbuffers::ForwardsUOffset<{{U_ELEMENT_TABLE_TYPE}}>>(" + "\"{{U_ELEMENT_ENUM_TYPE}}\", pos),"; + }); + code_ += " _ => Ok(()),"; + code_ += " }"; + code_ += " })?\\"; + }); + code_ += "\n .finish();"; + code_ += " Ok(())"; + code_ += " }"; + code_ += "}"; + // Generate an args struct: code_.SetValue("MAYBE_LT", TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : ""); @@ -1538,22 +1542,105 @@ class RustGenerator : public BaseGenerator { // The root datatype accessors: code_ += "#[inline]"; + code_ += "#[deprecated(since=\"1.13\", " + "note=\"Deprecated in favor of `root_as...` methods.\")]"; code_ += "pub fn get_root_as_{{STRUCT_NAME_SNAKECASE}}<'a>(buf: &'a [u8])" " -> {{STRUCT_NAME}}<'a> {"; - code_ += " flatbuffers::get_root::<{{STRUCT_NAME}}<'a>>(buf)"; + code_ += " unsafe { flatbuffers::root_unchecked::<{{STRUCT_NAME}}" + "<'a>>(buf) }"; code_ += "}"; code_ += ""; code_ += "#[inline]"; + code_ += "#[deprecated(since=\"1.13\", " + "note=\"Deprecated in favor of `root_as...` methods.\")]"; code_ += "pub fn get_size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}" "<'a>(buf: &'a [u8]) -> {{STRUCT_NAME}}<'a> {"; code_ += - " flatbuffers::get_size_prefixed_root::<{{STRUCT_NAME}}<'a>>" - "(buf)"; + " unsafe { flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_NAME}}" + "<'a>>(buf) }"; code_ += "}"; code_ += ""; + // Default verifier root fns. + code_ += "#[inline]"; + code_ += "/// Verifies that a buffer of bytes contains a `{{STRUCT_NAME}}`"; + code_ += "/// and returns it."; + code_ += "/// Note that verification is still experimental and may not"; + code_ += "/// catch every error, or be maximally performant. For the"; + code_ += "/// previous, unchecked, behavior use"; + code_ += "/// `root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`."; + code_ += "pub fn root_as_{{STRUCT_NAME_SNAKECASE}}(buf: &[u8]) " + "-> Result<{{STRUCT_NAME}}, flatbuffers::InvalidFlatbuffer> {"; + code_ += " flatbuffers::root::<{{STRUCT_NAME}}>(buf)"; + code_ += "}"; + code_ += "#[inline]"; + code_ += "/// Verifies that a buffer of bytes contains a size prefixed"; + code_ += "/// `{{STRUCT_NAME}}` and returns it."; + code_ += "/// Note that verification is still experimental and may not"; + code_ += "/// catch every error, or be maximally performant. For the"; + code_ += "/// previous, unchecked, behavior use"; + code_ += "/// `size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`."; + code_ += "pub fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}" + "(buf: &[u8]) -> Result<{{STRUCT_NAME}}, " + "flatbuffers::InvalidFlatbuffer> {"; + code_ += " flatbuffers::size_prefixed_root::<{{STRUCT_NAME}}>(buf)"; + code_ += "}"; + // Verifier with options root fns. + code_ += "#[inline]"; + code_ += "/// Verifies, with the given options, that a buffer of bytes"; + code_ += "/// contains a `{{STRUCT_NAME}}` and returns it."; + code_ += "/// Note that verification is still experimental and may not"; + code_ += "/// catch every error, or be maximally performant. For the"; + code_ += "/// previous, unchecked, behavior use"; + code_ += "/// `root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`."; + code_ += "pub fn root_as_{{STRUCT_NAME_SNAKECASE}}_with_opts<'b, 'o>("; + code_ += " opts: &'o flatbuffers::VerifierOptions,"; + code_ += " buf: &'b [u8],"; + code_ += ") -> Result<{{STRUCT_NAME}}<'b>, flatbuffers::InvalidFlatbuffer>" + " {"; + code_ += " flatbuffers::root_with_opts::<{{STRUCT_NAME}}<'b>>(opts, buf)"; + code_ += "}"; + code_ += "#[inline]"; + code_ += "/// Verifies, with the given verifier options, that a buffer of"; + code_ += "/// bytes contains a size prefixed `{{STRUCT_NAME}}` and returns"; + code_ += "/// it. Note that verification is still experimental and may not"; + code_ += "/// catch every error, or be maximally performant. For the"; + code_ += "/// previous, unchecked, behavior use"; + code_ += "/// `root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`."; + code_ += "pub fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}_with_opts" + "<'b, 'o>("; + code_ += " opts: &'o flatbuffers::VerifierOptions,"; + code_ += " buf: &'b [u8],"; + code_ += ") -> Result<{{STRUCT_NAME}}<'b>, flatbuffers::InvalidFlatbuffer>" + " {"; + code_ += " flatbuffers::size_prefixed_root_with_opts::<{{STRUCT_NAME}}" + "<'b>>(opts, buf)"; + code_ += "}"; + // Unchecked root fns. + code_ += "#[inline]"; + code_ += "/// Assumes, without verification, that a buffer of bytes " + "contains a {{STRUCT_NAME}} and returns it."; + code_ += "/// # Safety"; + code_ += "/// Callers must trust the given bytes do indeed contain a valid" + " `{{STRUCT_NAME}}`."; + code_ += "pub unsafe fn root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked" + "(buf: &[u8]) -> {{STRUCT_NAME}} {"; + code_ += " flatbuffers::root_unchecked::<{{STRUCT_NAME}}>(buf)"; + code_ += "}"; + code_ += "#[inline]"; + code_ += "/// Assumes, without verification, that a buffer of bytes " + "contains a size prefixed {{STRUCT_NAME}} and returns it."; + code_ += "/// # Safety"; + code_ += "/// Callers must trust the given bytes do indeed contain a valid" + " size prefixed `{{STRUCT_NAME}}`."; + code_ += "pub unsafe fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}" + "_unchecked(buf: &[u8]) -> {{STRUCT_NAME}} {"; + code_ += " flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_NAME}}>" + "(buf)"; + code_ += "}"; + if (parser_.file_identifier_.length()) { // Declare the identifier @@ -1697,6 +1784,7 @@ class RustGenerator : public BaseGenerator { // Generate impls for SafeSliceAccess (because all structs are endian-safe), // Follow for the value type, Follow for the reference type, Push for the // value type, and Push for the reference type. + code_ += "impl flatbuffers::SimpleToVerifyInSlice for {{STRUCT_NAME}} {}"; code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_NAME}} {}"; code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}} {"; code_ += " type Inner = &'a {{STRUCT_NAME}};"; @@ -1738,7 +1826,18 @@ class RustGenerator : public BaseGenerator { code_ += " }"; code_ += "}"; code_ += ""; - code_ += ""; + + // Generate verifier: Structs are simple so presence and alignment are + // all that need to be checked. + code_ += "impl<'a> flatbuffers::Verifiable for {{STRUCT_NAME}} {"; + code_ += " #[inline]"; + code_ += " fn run_verifier<'o, 'b>("; + code_ += " v: &mut flatbuffers::Verifier<'o, 'b>, pos: usize"; + code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {"; + code_ += " use self::flatbuffers::Verifiable;"; + code_ += " v.in_buffer::<Self>(pos)"; + code_ += " }"; + code_ += "}"; // Generate a constructor that takes all fields as arguments. code_ += "impl {{STRUCT_NAME}} {"; |