mirror of
https://github.com/google/flatbuffers.git
synced 2026-07-03 06:22:27 +00:00
Default strings and vectors: Parser + Rust support (#6421)
* Fix tests.cpp * Parser support for vector/string defaults * tests and default empty vectors * addressed comments * Default strings and vectors for Rust * Tested Rust more_defaults * git-clang-format * add more_defaults_test * fixed vector default * removed commented out code * more unreachable Co-authored-by: Casper Neo <cneo@google.com>
This commit is contained in:
@@ -337,6 +337,7 @@ struct FieldDef : public Definition {
|
|||||||
kDefault,
|
kDefault,
|
||||||
};
|
};
|
||||||
Presence static MakeFieldPresence(bool optional, bool required) {
|
Presence static MakeFieldPresence(bool optional, bool required) {
|
||||||
|
FLATBUFFERS_ASSERT(!(required && optional));
|
||||||
// clang-format off
|
// clang-format off
|
||||||
return required ? FieldDef::kRequired
|
return required ? FieldDef::kRequired
|
||||||
: optional ? FieldDef::kOptional
|
: optional ? FieldDef::kOptional
|
||||||
@@ -973,6 +974,7 @@ class Parser : public ParserState {
|
|||||||
bool SupportsAdvancedUnionFeatures() const;
|
bool SupportsAdvancedUnionFeatures() const;
|
||||||
bool SupportsAdvancedArrayFeatures() const;
|
bool SupportsAdvancedArrayFeatures() const;
|
||||||
bool SupportsOptionalScalars() const;
|
bool SupportsOptionalScalars() const;
|
||||||
|
bool SupportsDefaultVectorsAndStrings() const;
|
||||||
Namespace *UniqueNamespace(Namespace *ns);
|
Namespace *UniqueNamespace(Namespace *ns);
|
||||||
|
|
||||||
FLATBUFFERS_CHECKED_ERROR RecurseError();
|
FLATBUFFERS_CHECKED_ERROR RecurseError();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "flatbuffers"
|
name = "flatbuffers"
|
||||||
version = "0.8.2"
|
version = "0.8.3"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
authors = ["Robert Winslow <hello@rwinslow.com>", "FlatBuffers Maintainers"]
|
authors = ["Robert Winslow <hello@rwinslow.com>", "FlatBuffers Maintainers"]
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
|||||||
@@ -29,6 +29,14 @@ use crate::primitives::*;
|
|||||||
|
|
||||||
pub struct Vector<'a, T: 'a>(&'a [u8], usize, PhantomData<T>);
|
pub struct Vector<'a, T: 'a>(&'a [u8], usize, PhantomData<T>);
|
||||||
|
|
||||||
|
impl<'a, T:'a> Default for Vector<'a, T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
// Static, length 0 vector.
|
||||||
|
// Note that derived default causes UB due to issues in read_scalar_at /facepalm.
|
||||||
|
Self(&[0; core::mem::size_of::<UOffsetT>()], 0, Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, T> Debug for Vector<'a, T>
|
impl<'a, T> Debug for Vector<'a, T>
|
||||||
where
|
where
|
||||||
T: 'a + Follow<'a>,
|
T: 'a + Follow<'a>,
|
||||||
|
|||||||
@@ -183,6 +183,12 @@ bool IsBitFlagsEnum(const FieldDef &field) {
|
|||||||
return ed && IsBitFlagsEnum(*ed);
|
return ed && IsBitFlagsEnum(*ed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TableArgs make required non-scalars "Option<_>".
|
||||||
|
// TODO(cneo): Rework how we do defaults and stuff.
|
||||||
|
bool IsOptionalToBuilder(const FieldDef &field) {
|
||||||
|
return field.IsOptional() || !IsScalar(field.value.type.base_type);
|
||||||
|
}
|
||||||
|
|
||||||
namespace rust {
|
namespace rust {
|
||||||
|
|
||||||
class RustGenerator : public BaseGenerator {
|
class RustGenerator : public BaseGenerator {
|
||||||
@@ -883,8 +889,10 @@ class RustGenerator : public BaseGenerator {
|
|||||||
return "VT_" + MakeUpper(Name(field));
|
return "VT_" + MakeUpper(Name(field));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetDefaultValue(const FieldDef &field, bool for_builder) {
|
enum DefaultContext { kBuilder, kAccessor, kObject };
|
||||||
if (for_builder) {
|
std::string GetDefaultValue(const FieldDef &field,
|
||||||
|
const DefaultContext context) {
|
||||||
|
if (context == kBuilder) {
|
||||||
// Builders and Args structs model nonscalars "optional" even if they're
|
// Builders and Args structs model nonscalars "optional" even if they're
|
||||||
// required or have defaults according to the schema. I guess its because
|
// required or have defaults according to the schema. I guess its because
|
||||||
// WIPOffset is not nullable.
|
// WIPOffset is not nullable.
|
||||||
@@ -915,9 +923,19 @@ class RustGenerator : public BaseGenerator {
|
|||||||
return ObjectFieldType(field, true) + "::NONE";
|
return ObjectFieldType(field, true) + "::NONE";
|
||||||
}
|
}
|
||||||
case ftString: {
|
case ftString: {
|
||||||
// Required strings.
|
// Required fields do not have defaults defined by the schema, but we
|
||||||
return "String::new()"; // No default strings yet.
|
// need one for Rust's Default trait so we use empty string. The usual
|
||||||
|
// value of field.value.constant is `0`, which is non-sensical except
|
||||||
|
// maybe to c++ (nullptr == 0).
|
||||||
|
// TODO: Escape strings?
|
||||||
|
const std::string defval =
|
||||||
|
field.IsRequired() ? "\"\"" : "\"" + field.value.constant + "\"";
|
||||||
|
if (context == kObject) return defval + ".to_string()";
|
||||||
|
if (context == kAccessor) return "&" + defval;
|
||||||
|
FLATBUFFERS_ASSERT("Unreachable.");
|
||||||
|
return "INVALID_CODE_GENERATION";
|
||||||
}
|
}
|
||||||
|
|
||||||
case ftVectorOfBool:
|
case ftVectorOfBool:
|
||||||
case ftVectorOfFloat:
|
case ftVectorOfFloat:
|
||||||
case ftVectorOfInteger:
|
case ftVectorOfInteger:
|
||||||
@@ -925,14 +943,16 @@ class RustGenerator : public BaseGenerator {
|
|||||||
case ftVectorOfStruct:
|
case ftVectorOfStruct:
|
||||||
case ftVectorOfTable:
|
case ftVectorOfTable:
|
||||||
case ftVectorOfEnumKey:
|
case ftVectorOfEnumKey:
|
||||||
case ftVectorOfUnionValue: {
|
case ftVectorOfUnionValue:
|
||||||
// Required vectors.
|
|
||||||
return "Vec::new()"; // No default strings yet.
|
|
||||||
}
|
|
||||||
case ftStruct:
|
case ftStruct:
|
||||||
case ftTable: {
|
case ftTable: {
|
||||||
// Required struct/tables.
|
// We only support empty vectors which matches the defaults for
|
||||||
return "Default::default()"; // punt.
|
// &[T] and Vec<T> anyway.
|
||||||
|
//
|
||||||
|
// For required structs and tables fields, we defer to their object API
|
||||||
|
// defaults. This works so long as there's nothing recursive happening,
|
||||||
|
// but `table Infinity { i: Infinity (required); }` does compile.
|
||||||
|
return "Default::default()";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FLATBUFFERS_ASSERT("Unreachable.");
|
FLATBUFFERS_ASSERT("Unreachable.");
|
||||||
@@ -953,30 +973,38 @@ class RustGenerator : public BaseGenerator {
|
|||||||
std::string TableBuilderArgsDefnType(const FieldDef &field,
|
std::string TableBuilderArgsDefnType(const FieldDef &field,
|
||||||
const std::string &lifetime) {
|
const std::string &lifetime) {
|
||||||
const Type &type = field.value.type;
|
const Type &type = field.value.type;
|
||||||
|
auto WrapOption = [&](std::string s) {
|
||||||
|
return IsOptionalToBuilder(field) ? "Option<" + s + ">" : s;
|
||||||
|
};
|
||||||
|
auto WrapVector = [&](std::string ty) {
|
||||||
|
return WrapOption("flatbuffers::WIPOffset<flatbuffers::Vector<" +
|
||||||
|
lifetime + ", " + ty + ">>");
|
||||||
|
};
|
||||||
|
auto WrapUOffsetsVector = [&](std::string ty) {
|
||||||
|
return WrapVector("flatbuffers::ForwardsUOffset<" + ty + ">");
|
||||||
|
};
|
||||||
|
|
||||||
switch (GetFullType(type)) {
|
switch (GetFullType(type)) {
|
||||||
case ftInteger:
|
case ftInteger:
|
||||||
case ftFloat:
|
case ftFloat:
|
||||||
case ftBool: {
|
case ftBool: {
|
||||||
const auto typname = GetTypeBasic(type);
|
return WrapOption(GetTypeBasic(type));
|
||||||
return field.IsOptional() ? "Option<" + typname + ">" : typname;
|
|
||||||
}
|
}
|
||||||
case ftStruct: {
|
case ftStruct: {
|
||||||
const auto typname = WrapInNameSpace(*type.struct_def);
|
const auto typname = WrapInNameSpace(*type.struct_def);
|
||||||
return "Option<&" + lifetime + " " + typname + ">";
|
return WrapOption("&" + lifetime + " " + typname);
|
||||||
}
|
}
|
||||||
case ftTable: {
|
case ftTable: {
|
||||||
const auto typname = WrapInNameSpace(*type.struct_def);
|
const auto typname = WrapInNameSpace(*type.struct_def);
|
||||||
return "Option<flatbuffers::WIPOffset<" + typname + "<" + lifetime +
|
return WrapOption("flatbuffers::WIPOffset<" + typname + "<" + lifetime +
|
||||||
">>>";
|
">>");
|
||||||
}
|
}
|
||||||
case ftString: {
|
case ftString: {
|
||||||
return "Option<flatbuffers::WIPOffset<&" + lifetime + " str>>";
|
return WrapOption("flatbuffers::WIPOffset<&" + lifetime + " str>");
|
||||||
}
|
}
|
||||||
case ftEnumKey:
|
case ftEnumKey:
|
||||||
case ftUnionKey: {
|
case ftUnionKey: {
|
||||||
const auto typname = WrapInNameSpace(*type.enum_def);
|
return WrapOption(WrapInNameSpace(*type.enum_def));
|
||||||
return field.IsOptional() ? "Option<" + typname + ">" : typname;
|
|
||||||
}
|
}
|
||||||
case ftUnionValue: {
|
case ftUnionValue: {
|
||||||
return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>";
|
return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>";
|
||||||
@@ -986,36 +1014,25 @@ class RustGenerator : public BaseGenerator {
|
|||||||
case ftVectorOfBool:
|
case ftVectorOfBool:
|
||||||
case ftVectorOfFloat: {
|
case ftVectorOfFloat: {
|
||||||
const auto typname = GetTypeBasic(type.VectorType());
|
const auto typname = GetTypeBasic(type.VectorType());
|
||||||
return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
|
return WrapVector(typname);
|
||||||
", " + typname + ">>>";
|
|
||||||
}
|
}
|
||||||
case ftVectorOfEnumKey: {
|
case ftVectorOfEnumKey: {
|
||||||
const auto typname = WrapInNameSpace(*type.enum_def);
|
const auto typname = WrapInNameSpace(*type.enum_def);
|
||||||
return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
|
return WrapVector(typname);
|
||||||
", " + typname + ">>>";
|
|
||||||
}
|
}
|
||||||
case ftVectorOfStruct: {
|
case ftVectorOfStruct: {
|
||||||
const auto typname = WrapInNameSpace(*type.struct_def);
|
const auto typname = WrapInNameSpace(*type.struct_def);
|
||||||
return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
|
return WrapVector(typname);
|
||||||
", " + typname + ">>>";
|
|
||||||
}
|
}
|
||||||
case ftVectorOfTable: {
|
case ftVectorOfTable: {
|
||||||
const auto typname = WrapInNameSpace(*type.struct_def);
|
const auto typname = WrapInNameSpace(*type.struct_def);
|
||||||
return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
|
return WrapUOffsetsVector(typname + "<" + lifetime + ">");
|
||||||
", flatbuffers::ForwardsUOffset<" + typname + "<" + lifetime +
|
|
||||||
">>>>>";
|
|
||||||
}
|
}
|
||||||
case ftVectorOfString: {
|
case ftVectorOfString: {
|
||||||
return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
|
return WrapUOffsetsVector("&" + lifetime + " str");
|
||||||
", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>>";
|
|
||||||
}
|
}
|
||||||
case ftVectorOfUnionValue: {
|
case ftVectorOfUnionValue: {
|
||||||
const auto typname =
|
return WrapUOffsetsVector("flatbuffers::Table<" + lifetime + ">");
|
||||||
WrapInNameSpace(*type.enum_def) + "UnionTableOffset";
|
|
||||||
return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
|
|
||||||
", flatbuffers::ForwardsUOffset<"
|
|
||||||
"flatbuffers::Table<" +
|
|
||||||
lifetime + ">>>>";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "INVALID_CODE_GENERATION"; // for return analysis
|
return "INVALID_CODE_GENERATION"; // for return analysis
|
||||||
@@ -1084,8 +1101,7 @@ class RustGenerator : public BaseGenerator {
|
|||||||
return "INVALID_CODE_GENERATION"; // OH NO!
|
return "INVALID_CODE_GENERATION"; // OH NO!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (in_a_table && !IsUnion(type) &&
|
if (in_a_table && !IsUnion(type) && field.IsOptional()) {
|
||||||
(IsScalar(type.base_type) ? field.IsOptional() : !field.IsRequired())) {
|
|
||||||
return "Option<" + ty + ">";
|
return "Option<" + ty + ">";
|
||||||
} else {
|
} else {
|
||||||
return ty;
|
return ty;
|
||||||
@@ -1207,73 +1223,64 @@ class RustGenerator : public BaseGenerator {
|
|||||||
std::string GenTableAccessorFuncReturnType(const FieldDef &field,
|
std::string GenTableAccessorFuncReturnType(const FieldDef &field,
|
||||||
const std::string &lifetime) {
|
const std::string &lifetime) {
|
||||||
const Type &type = field.value.type;
|
const Type &type = field.value.type;
|
||||||
|
const auto WrapOption = [&](std::string s) {
|
||||||
|
return field.IsOptional() ? "Option<" + s + ">" : s;
|
||||||
|
};
|
||||||
|
|
||||||
switch (GetFullType(field.value.type)) {
|
switch (GetFullType(field.value.type)) {
|
||||||
case ftInteger:
|
case ftInteger:
|
||||||
case ftFloat:
|
case ftFloat:
|
||||||
case ftBool: {
|
case ftBool: {
|
||||||
const auto typname = GetTypeBasic(type);
|
return WrapOption(GetTypeBasic(type));
|
||||||
return field.IsOptional() ? "Option<" + typname + ">" : typname;
|
|
||||||
}
|
}
|
||||||
case ftStruct: {
|
case ftStruct: {
|
||||||
const auto typname = WrapInNameSpace(*type.struct_def);
|
const auto typname = WrapInNameSpace(*type.struct_def);
|
||||||
return WrapInOptionIfNotRequired("&" + lifetime + " " + typname,
|
return WrapOption("&" + lifetime + " " + typname);
|
||||||
field.IsRequired());
|
|
||||||
}
|
}
|
||||||
case ftTable: {
|
case ftTable: {
|
||||||
const auto typname = WrapInNameSpace(*type.struct_def);
|
const auto typname = WrapInNameSpace(*type.struct_def);
|
||||||
return WrapInOptionIfNotRequired(typname + "<" + lifetime + ">",
|
return WrapOption(typname + "<" + lifetime + ">");
|
||||||
field.IsRequired());
|
|
||||||
}
|
}
|
||||||
case ftEnumKey:
|
case ftEnumKey:
|
||||||
case ftUnionKey: {
|
case ftUnionKey: {
|
||||||
const auto typname = WrapInNameSpace(*type.enum_def);
|
return WrapOption(WrapInNameSpace(*type.enum_def));
|
||||||
return field.IsOptional() ? "Option<" + typname + ">" : typname;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case ftUnionValue: {
|
case ftUnionValue: {
|
||||||
return WrapInOptionIfNotRequired("flatbuffers::Table<" + lifetime + ">",
|
return WrapOption("flatbuffers::Table<" + lifetime + ">");
|
||||||
field.IsRequired());
|
|
||||||
}
|
}
|
||||||
case ftString: {
|
case ftString: {
|
||||||
return WrapInOptionIfNotRequired("&" + lifetime + " str",
|
return WrapOption("&" + lifetime + " str");
|
||||||
field.IsRequired());
|
|
||||||
}
|
}
|
||||||
case ftVectorOfInteger:
|
case ftVectorOfInteger:
|
||||||
case ftVectorOfBool:
|
case ftVectorOfBool:
|
||||||
case ftVectorOfFloat: {
|
case ftVectorOfFloat: {
|
||||||
const auto typname = GetTypeBasic(type.VectorType());
|
const auto typname = GetTypeBasic(type.VectorType());
|
||||||
if (IsOneByte(type.VectorType().base_type)) {
|
const auto vector_type =
|
||||||
return WrapInOptionIfNotRequired(
|
IsOneByte(type.VectorType().base_type)
|
||||||
"&" + lifetime + " [" + typname + "]", field.IsRequired());
|
? "&" + lifetime + " [" + typname + "]"
|
||||||
}
|
: "flatbuffers::Vector<" + lifetime + ", " + typname + ">";
|
||||||
return WrapInOptionIfNotRequired(
|
return WrapOption(vector_type);
|
||||||
"flatbuffers::Vector<" + lifetime + ", " + typname + ">",
|
|
||||||
field.IsRequired());
|
|
||||||
}
|
}
|
||||||
case ftVectorOfEnumKey: {
|
case ftVectorOfEnumKey: {
|
||||||
const auto typname = WrapInNameSpace(*type.enum_def);
|
const auto typname = WrapInNameSpace(*type.enum_def);
|
||||||
return WrapInOptionIfNotRequired(
|
return WrapOption("flatbuffers::Vector<" + lifetime + ", " + typname +
|
||||||
"flatbuffers::Vector<" + lifetime + ", " + typname + ">",
|
">");
|
||||||
field.IsRequired());
|
|
||||||
}
|
}
|
||||||
case ftVectorOfStruct: {
|
case ftVectorOfStruct: {
|
||||||
const auto typname = WrapInNameSpace(*type.struct_def);
|
const auto typname = WrapInNameSpace(*type.struct_def);
|
||||||
return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]",
|
return WrapOption("&" + lifetime + " [" + typname + "]");
|
||||||
field.IsRequired());
|
|
||||||
}
|
}
|
||||||
case ftVectorOfTable: {
|
case ftVectorOfTable: {
|
||||||
const auto typname = WrapInNameSpace(*type.struct_def);
|
const auto typname = WrapInNameSpace(*type.struct_def);
|
||||||
return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime +
|
return WrapOption("flatbuffers::Vector<" + lifetime +
|
||||||
", flatbuffers::ForwardsUOffset<" +
|
", flatbuffers::ForwardsUOffset<" + typname + "<" +
|
||||||
typname + "<" + lifetime + ">>>",
|
lifetime + ">>>");
|
||||||
field.IsRequired());
|
|
||||||
}
|
}
|
||||||
case ftVectorOfString: {
|
case ftVectorOfString: {
|
||||||
return WrapInOptionIfNotRequired(
|
return WrapOption("flatbuffers::Vector<" + lifetime +
|
||||||
"flatbuffers::Vector<" + lifetime +
|
", flatbuffers::ForwardsUOffset<&" + lifetime +
|
||||||
", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>",
|
" str>>");
|
||||||
field.IsRequired());
|
|
||||||
}
|
}
|
||||||
case ftVectorOfUnionValue: {
|
case ftVectorOfUnionValue: {
|
||||||
FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
|
FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
|
||||||
@@ -1354,7 +1361,7 @@ class RustGenerator : public BaseGenerator {
|
|||||||
// Default-y fields (scalars so far) are neither optional nor required.
|
// Default-y fields (scalars so far) are neither optional nor required.
|
||||||
const std::string default_value =
|
const std::string default_value =
|
||||||
!(field.IsOptional() || field.IsRequired())
|
!(field.IsOptional() || field.IsRequired())
|
||||||
? "Some(" + GetDefaultValue(field, /*builder=*/true) + ")"
|
? "Some(" + GetDefaultValue(field, kAccessor) + ")"
|
||||||
: "None";
|
: "None";
|
||||||
const std::string unwrap = field.IsOptional() ? "" : ".unwrap()";
|
const std::string unwrap = field.IsOptional() ? "" : ".unwrap()";
|
||||||
|
|
||||||
@@ -1373,18 +1380,6 @@ class RustGenerator : public BaseGenerator {
|
|||||||
", " + default_value + ")" + safe_slice + unwrap;
|
", " + default_value + ")" + safe_slice + unwrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TableFieldReturnsOption(const FieldDef &field) {
|
|
||||||
if (field.IsOptional()) return true;
|
|
||||||
switch (GetFullType(field.value.type)) {
|
|
||||||
case ftInteger:
|
|
||||||
case ftFloat:
|
|
||||||
case ftBool:
|
|
||||||
case ftEnumKey:
|
|
||||||
case ftUnionKey: return false;
|
|
||||||
default: return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generates a fully-qualified name getter for use with --gen-name-strings
|
// Generates a fully-qualified name getter for use with --gen-name-strings
|
||||||
void GenFullyQualifiedNameGetter(const StructDef &struct_def,
|
void GenFullyQualifiedNameGetter(const StructDef &struct_def,
|
||||||
const std::string &name) {
|
const std::string &name) {
|
||||||
@@ -1425,7 +1420,7 @@ class RustGenerator : public BaseGenerator {
|
|||||||
code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
|
code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
|
||||||
code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
|
code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
|
||||||
code_.SetValue("FIELD_NAME", Name(field));
|
code_.SetValue("FIELD_NAME", Name(field));
|
||||||
code_.SetValue("BLDR_DEF_VAL", GetDefaultValue(field, /*builder=*/true));
|
code_.SetValue("BLDR_DEF_VAL", GetDefaultValue(field, kBuilder));
|
||||||
cb(field);
|
cb(field);
|
||||||
};
|
};
|
||||||
const auto &fields = struct_def.fields.vec;
|
const auto &fields = struct_def.fields.vec;
|
||||||
@@ -1498,7 +1493,7 @@ class RustGenerator : public BaseGenerator {
|
|||||||
if (struct_def.sortbysize &&
|
if (struct_def.sortbysize &&
|
||||||
size != SizeOf(field.value.type.base_type))
|
size != SizeOf(field.value.type.base_type))
|
||||||
return;
|
return;
|
||||||
if (TableFieldReturnsOption(field)) {
|
if (IsOptionalToBuilder(field)) {
|
||||||
code_ +=
|
code_ +=
|
||||||
" if let Some(x) = args.{{FIELD_NAME}} "
|
" if let Some(x) = args.{{FIELD_NAME}} "
|
||||||
"{ builder.add_{{FIELD_NAME}}(x); }";
|
"{ builder.add_{{FIELD_NAME}}(x); }";
|
||||||
@@ -1943,7 +1938,7 @@ class RustGenerator : public BaseGenerator {
|
|||||||
code_ += " Self {";
|
code_ += " Self {";
|
||||||
ForAllObjectTableFields(table, [&](const FieldDef &field) {
|
ForAllObjectTableFields(table, [&](const FieldDef &field) {
|
||||||
if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
|
if (field.value.type.base_type == BASE_TYPE_UTYPE) return;
|
||||||
std::string default_value = GetDefaultValue(field, /*builder=*/false);
|
std::string default_value = GetDefaultValue(field, kObject);
|
||||||
code_ += " {{FIELD_NAME}}: " + default_value + ",";
|
code_ += " {{FIELD_NAME}}: " + default_value + ",";
|
||||||
});
|
});
|
||||||
code_ += " }";
|
code_ += " }";
|
||||||
@@ -2064,17 +2059,17 @@ class RustGenerator : public BaseGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void MapNativeTableField(const FieldDef &field, const std::string &expr) {
|
void MapNativeTableField(const FieldDef &field, const std::string &expr) {
|
||||||
if (field.IsRequired()) {
|
if (field.IsOptional()) {
|
||||||
|
code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}}.as_ref().map(|x|{";
|
||||||
|
code_ += " " + expr;
|
||||||
|
code_ += " });";
|
||||||
|
} else {
|
||||||
// For some reason Args has optional types for required fields.
|
// For some reason Args has optional types for required fields.
|
||||||
// TODO(cneo): Fix this... but its a breaking change?
|
// TODO(cneo): Fix this... but its a breaking change?
|
||||||
code_ += " let {{FIELD_NAME}} = Some({";
|
code_ += " let {{FIELD_NAME}} = Some({";
|
||||||
code_ += " let x = &self.{{FIELD_NAME}};";
|
code_ += " let x = &self.{{FIELD_NAME}};";
|
||||||
code_ += " " + expr;
|
code_ += " " + expr;
|
||||||
code_ += " });";
|
code_ += " });";
|
||||||
} else {
|
|
||||||
code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}}.as_ref().map(|x|{";
|
|
||||||
code_ += " " + expr;
|
|
||||||
code_ += " });";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -794,10 +794,19 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
|
|||||||
if (token_ == '=') {
|
if (token_ == '=') {
|
||||||
NEXT();
|
NEXT();
|
||||||
ECHECK(ParseSingleValue(&field->name, field->value, true));
|
ECHECK(ParseSingleValue(&field->name, field->value, true));
|
||||||
if (!IsScalar(type.base_type) ||
|
if (IsStruct(type) || (struct_def.fixed && field->value.constant != "0"))
|
||||||
(struct_def.fixed && field->value.constant != "0"))
|
|
||||||
return Error(
|
return Error(
|
||||||
"default values currently only supported for scalars in tables");
|
"default values are not supported for struct fields, table fields, "
|
||||||
|
"or in structs.");
|
||||||
|
if ((IsString(type) || IsVector(type)) && field->value.constant != "0" &&
|
||||||
|
field->value.constant != "null" && !SupportsDefaultVectorsAndStrings())
|
||||||
|
return Error(
|
||||||
|
"Default values for strings and vectors are not supported in one of "
|
||||||
|
"the specified programming languages");
|
||||||
|
if (IsVector(type) && field->value.constant != "0" &&
|
||||||
|
field->value.constant != "[]") {
|
||||||
|
return Error("The only supported default for vectors is `[]`.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append .0 if the value has not it (skip hex and scientific floats).
|
// Append .0 if the value has not it (skip hex and scientific floats).
|
||||||
@@ -856,8 +865,11 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
|
|||||||
field->key = field->attributes.Lookup("key") != nullptr;
|
field->key = field->attributes.Lookup("key") != nullptr;
|
||||||
const bool required = field->attributes.Lookup("required") != nullptr ||
|
const bool required = field->attributes.Lookup("required") != nullptr ||
|
||||||
(IsString(type) && field->key);
|
(IsString(type) && field->key);
|
||||||
const bool optional =
|
const bool default_str_or_vec =
|
||||||
IsScalar(type.base_type) ? (field->value.constant == "null") : !required;
|
((IsString(type) || IsVector(type)) && field->value.constant != "0");
|
||||||
|
const bool optional = IsScalar(type.base_type)
|
||||||
|
? (field->value.constant == "null")
|
||||||
|
: !(required || default_str_or_vec);
|
||||||
if (required && optional) {
|
if (required && optional) {
|
||||||
return Error("Fields cannot be both optional and required.");
|
return Error("Fields cannot be both optional and required.");
|
||||||
}
|
}
|
||||||
@@ -1962,6 +1974,15 @@ CheckedError Parser::ParseSingleValue(const std::string *name, Value &e,
|
|||||||
// Integer token can init any scalar (integer of float).
|
// Integer token can init any scalar (integer of float).
|
||||||
FORCE_ECHECK(kTokenIntegerConstant, IsScalar(in_type), BASE_TYPE_INT);
|
FORCE_ECHECK(kTokenIntegerConstant, IsScalar(in_type), BASE_TYPE_INT);
|
||||||
}
|
}
|
||||||
|
// Match empty vectors for default-empty-vectors.
|
||||||
|
if (!match && IsVector(e.type) && token_ == '[') {
|
||||||
|
NEXT();
|
||||||
|
if (token_ != ']') { return Error("Expected `]` in vector default"); }
|
||||||
|
NEXT();
|
||||||
|
match = true;
|
||||||
|
e.constant = "[]";
|
||||||
|
}
|
||||||
|
|
||||||
#undef FORCE_ECHECK
|
#undef FORCE_ECHECK
|
||||||
#undef TRY_ECHECK
|
#undef TRY_ECHECK
|
||||||
#undef IF_ECHECK_
|
#undef IF_ECHECK_
|
||||||
@@ -2406,12 +2427,17 @@ bool Parser::SupportsOptionalScalars(const flatbuffers::IDLOptions &opts) {
|
|||||||
unsigned long langs = opts.lang_to_generate;
|
unsigned long langs = opts.lang_to_generate;
|
||||||
return (langs > 0 && langs < IDLOptions::kMAX) && !(langs & ~supported_langs);
|
return (langs > 0 && langs < IDLOptions::kMAX) && !(langs & ~supported_langs);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Parser::SupportsOptionalScalars() const {
|
bool Parser::SupportsOptionalScalars() const {
|
||||||
// Check in general if a language isn't specified.
|
// Check in general if a language isn't specified.
|
||||||
return opts.lang_to_generate == 0 || SupportsOptionalScalars(opts);
|
return opts.lang_to_generate == 0 || SupportsOptionalScalars(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Parser::SupportsDefaultVectorsAndStrings() const {
|
||||||
|
static FLATBUFFERS_CONSTEXPR unsigned long supported_langs =
|
||||||
|
IDLOptions::kRust;
|
||||||
|
return !(opts.lang_to_generate & ~supported_langs);
|
||||||
|
}
|
||||||
|
|
||||||
bool Parser::SupportsAdvancedUnionFeatures() const {
|
bool Parser::SupportsAdvancedUnionFeatures() const {
|
||||||
return opts.lang_to_generate != 0 &&
|
return opts.lang_to_generate != 0 &&
|
||||||
(opts.lang_to_generate &
|
(opts.lang_to_generate &
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ $TEST_NOINCL_FLAGS $TEST_CPP_FLAGS $TEST_CS_FLAGS $TEST_JS_TS_FLAGS -o namespace
|
|||||||
../flatc --csharp --rust --gen-object-api optional_scalars.fbs
|
../flatc --csharp --rust --gen-object-api optional_scalars.fbs
|
||||||
../flatc $TEST_NOINCL_FLAGS $TEST_CPP_FLAGS --cpp optional_scalars.fbs
|
../flatc $TEST_NOINCL_FLAGS $TEST_CPP_FLAGS --cpp optional_scalars.fbs
|
||||||
|
|
||||||
|
# Generate string/vector default code for tests
|
||||||
|
../flatc --rust --gen-object-api more_defaults.fbs
|
||||||
|
|
||||||
# Generate the schema evolution tests
|
# Generate the schema evolution tests
|
||||||
../flatc --cpp --scoped-enums $TEST_CPP_FLAGS -o evolution_test ./evolution_test/evolution_v*.fbs
|
../flatc --cpp --scoped-enums $TEST_CPP_FLAGS -o evolution_test ./evolution_test/evolution_v*.fbs
|
||||||
|
|
||||||
|
|||||||
@@ -3197,7 +3197,7 @@ impl Default for MonsterT {
|
|||||||
pos: None,
|
pos: None,
|
||||||
mana: 150,
|
mana: 150,
|
||||||
hp: 100,
|
hp: 100,
|
||||||
name: String::new(),
|
name: "".to_string(),
|
||||||
inventory: None,
|
inventory: None,
|
||||||
color: Color::Blue,
|
color: Color::Blue,
|
||||||
test: AnyT::NONE,
|
test: AnyT::NONE,
|
||||||
|
|||||||
7
tests/more_defaults.fbs
Normal file
7
tests/more_defaults.fbs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
table MoreDefaults {
|
||||||
|
ints: [int] = [];
|
||||||
|
floats: [float] = [ ];
|
||||||
|
empty_string: string = "";
|
||||||
|
some_string: string = "some";
|
||||||
|
}
|
||||||
214
tests/more_defaults_generated.rs
Normal file
214
tests/more_defaults_generated.rs
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
// automatically generated by the FlatBuffers compiler, do not modify
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
use std::mem;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
extern crate flatbuffers;
|
||||||
|
use self::flatbuffers::EndianScalar;
|
||||||
|
|
||||||
|
pub enum MoreDefaultsOffset {}
|
||||||
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
|
||||||
|
pub struct MoreDefaults<'a> {
|
||||||
|
pub _tab: flatbuffers::Table<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> flatbuffers::Follow<'a> for MoreDefaults<'a> {
|
||||||
|
type Inner = MoreDefaults<'a>;
|
||||||
|
#[inline]
|
||||||
|
fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {
|
||||||
|
Self { _tab: flatbuffers::Table { buf, loc } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> MoreDefaults<'a> {
|
||||||
|
#[inline]
|
||||||
|
pub fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
|
||||||
|
MoreDefaults { _tab: table }
|
||||||
|
}
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>(
|
||||||
|
_fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,
|
||||||
|
args: &'args MoreDefaultsArgs<'args>) -> flatbuffers::WIPOffset<MoreDefaults<'bldr>> {
|
||||||
|
let mut builder = MoreDefaultsBuilder::new(_fbb);
|
||||||
|
if let Some(x) = args.some_string { builder.add_some_string(x); }
|
||||||
|
if let Some(x) = args.empty_string { builder.add_empty_string(x); }
|
||||||
|
if let Some(x) = args.floats { builder.add_floats(x); }
|
||||||
|
if let Some(x) = args.ints { builder.add_ints(x); }
|
||||||
|
builder.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unpack(&self) -> MoreDefaultsT {
|
||||||
|
let ints = {
|
||||||
|
let x = self.ints();
|
||||||
|
x.into_iter().collect()
|
||||||
|
};
|
||||||
|
let floats = {
|
||||||
|
let x = self.floats();
|
||||||
|
x.into_iter().collect()
|
||||||
|
};
|
||||||
|
let empty_string = {
|
||||||
|
let x = self.empty_string();
|
||||||
|
x.to_string()
|
||||||
|
};
|
||||||
|
let some_string = {
|
||||||
|
let x = self.some_string();
|
||||||
|
x.to_string()
|
||||||
|
};
|
||||||
|
MoreDefaultsT {
|
||||||
|
ints,
|
||||||
|
floats,
|
||||||
|
empty_string,
|
||||||
|
some_string,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const VT_INTS: flatbuffers::VOffsetT = 4;
|
||||||
|
pub const VT_FLOATS: flatbuffers::VOffsetT = 6;
|
||||||
|
pub const VT_EMPTY_STRING: flatbuffers::VOffsetT = 8;
|
||||||
|
pub const VT_SOME_STRING: flatbuffers::VOffsetT = 10;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn ints(&self) -> flatbuffers::Vector<'a, i32> {
|
||||||
|
self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, i32>>>(MoreDefaults::VT_INTS, Some(Default::default())).unwrap()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn floats(&self) -> flatbuffers::Vector<'a, f32> {
|
||||||
|
self._tab.get::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'a, f32>>>(MoreDefaults::VT_FLOATS, Some(Default::default())).unwrap()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn empty_string(&self) -> &'a str {
|
||||||
|
self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(MoreDefaults::VT_EMPTY_STRING, Some(&"")).unwrap()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn some_string(&self) -> &'a str {
|
||||||
|
self._tab.get::<flatbuffers::ForwardsUOffset<&str>>(MoreDefaults::VT_SOME_STRING, Some(&"some")).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl flatbuffers::Verifiable for MoreDefaults<'_> {
|
||||||
|
#[inline]
|
||||||
|
fn run_verifier(
|
||||||
|
v: &mut flatbuffers::Verifier, pos: usize
|
||||||
|
) -> Result<(), flatbuffers::InvalidFlatbuffer> {
|
||||||
|
use self::flatbuffers::Verifiable;
|
||||||
|
v.visit_table(pos)?
|
||||||
|
.visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, i32>>>(&"ints", Self::VT_INTS, false)?
|
||||||
|
.visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, f32>>>(&"floats", Self::VT_FLOATS, false)?
|
||||||
|
.visit_field::<flatbuffers::ForwardsUOffset<&str>>(&"empty_string", Self::VT_EMPTY_STRING, false)?
|
||||||
|
.visit_field::<flatbuffers::ForwardsUOffset<&str>>(&"some_string", Self::VT_SOME_STRING, false)?
|
||||||
|
.finish();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub struct MoreDefaultsArgs<'a> {
|
||||||
|
pub ints: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a, i32>>>,
|
||||||
|
pub floats: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a, f32>>>,
|
||||||
|
pub empty_string: Option<flatbuffers::WIPOffset<&'a str>>,
|
||||||
|
pub some_string: Option<flatbuffers::WIPOffset<&'a str>>,
|
||||||
|
}
|
||||||
|
impl<'a> Default for MoreDefaultsArgs<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self {
|
||||||
|
MoreDefaultsArgs {
|
||||||
|
ints: None,
|
||||||
|
floats: None,
|
||||||
|
empty_string: None,
|
||||||
|
some_string: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub struct MoreDefaultsBuilder<'a: 'b, 'b> {
|
||||||
|
fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,
|
||||||
|
start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
|
||||||
|
}
|
||||||
|
impl<'a: 'b, 'b> MoreDefaultsBuilder<'a, 'b> {
|
||||||
|
#[inline]
|
||||||
|
pub fn add_ints(&mut self, ints: flatbuffers::WIPOffset<flatbuffers::Vector<'b , i32>>) {
|
||||||
|
self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(MoreDefaults::VT_INTS, ints);
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn add_floats(&mut self, floats: flatbuffers::WIPOffset<flatbuffers::Vector<'b , f32>>) {
|
||||||
|
self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(MoreDefaults::VT_FLOATS, floats);
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn add_empty_string(&mut self, empty_string: flatbuffers::WIPOffset<&'b str>) {
|
||||||
|
self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(MoreDefaults::VT_EMPTY_STRING, empty_string);
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn add_some_string(&mut self, some_string: flatbuffers::WIPOffset<&'b str>) {
|
||||||
|
self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(MoreDefaults::VT_SOME_STRING, some_string);
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> MoreDefaultsBuilder<'a, 'b> {
|
||||||
|
let start = _fbb.start_table();
|
||||||
|
MoreDefaultsBuilder {
|
||||||
|
fbb_: _fbb,
|
||||||
|
start_: start,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn finish(self) -> flatbuffers::WIPOffset<MoreDefaults<'a>> {
|
||||||
|
let o = self.fbb_.end_table(self.start_);
|
||||||
|
flatbuffers::WIPOffset::new(o.value())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for MoreDefaults<'_> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let mut ds = f.debug_struct("MoreDefaults");
|
||||||
|
ds.field("ints", &self.ints());
|
||||||
|
ds.field("floats", &self.floats());
|
||||||
|
ds.field("empty_string", &self.empty_string());
|
||||||
|
ds.field("some_string", &self.some_string());
|
||||||
|
ds.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct MoreDefaultsT {
|
||||||
|
pub ints: Vec<i32>,
|
||||||
|
pub floats: Vec<f32>,
|
||||||
|
pub empty_string: String,
|
||||||
|
pub some_string: String,
|
||||||
|
}
|
||||||
|
impl Default for MoreDefaultsT {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
ints: Default::default(),
|
||||||
|
floats: Default::default(),
|
||||||
|
empty_string: "".to_string(),
|
||||||
|
some_string: "some".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl MoreDefaultsT {
|
||||||
|
pub fn pack<'b>(
|
||||||
|
&self,
|
||||||
|
_fbb: &mut flatbuffers::FlatBufferBuilder<'b>
|
||||||
|
) -> flatbuffers::WIPOffset<MoreDefaults<'b>> {
|
||||||
|
let ints = Some({
|
||||||
|
let x = &self.ints;
|
||||||
|
_fbb.create_vector(x)
|
||||||
|
});
|
||||||
|
let floats = Some({
|
||||||
|
let x = &self.floats;
|
||||||
|
_fbb.create_vector(x)
|
||||||
|
});
|
||||||
|
let empty_string = Some({
|
||||||
|
let x = &self.empty_string;
|
||||||
|
_fbb.create_string(x)
|
||||||
|
});
|
||||||
|
let some_string = Some({
|
||||||
|
let x = &self.some_string;
|
||||||
|
_fbb.create_string(x)
|
||||||
|
});
|
||||||
|
MoreDefaults::create(_fbb, &MoreDefaultsArgs{
|
||||||
|
ints,
|
||||||
|
floats,
|
||||||
|
empty_string,
|
||||||
|
some_string,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@ extern crate quickcheck_derive;
|
|||||||
|
|
||||||
mod flexbuffers_tests;
|
mod flexbuffers_tests;
|
||||||
mod optional_scalars_test;
|
mod optional_scalars_test;
|
||||||
|
mod more_defaults_test;
|
||||||
|
|
||||||
#[allow(dead_code, unused_imports)]
|
#[allow(dead_code, unused_imports)]
|
||||||
#[path = "../../include_test/include_test1_generated.rs"]
|
#[path = "../../include_test/include_test1_generated.rs"]
|
||||||
|
|||||||
26
tests/rust_usage_test/tests/more_defaults_test.rs
Normal file
26
tests/rust_usage_test/tests/more_defaults_test.rs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#[allow(dead_code, unused_imports)]
|
||||||
|
#[path = "../../more_defaults_generated.rs"]
|
||||||
|
mod more_defaults_generated;
|
||||||
|
use self::more_defaults_generated::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn object_defaults() {
|
||||||
|
assert_eq!(
|
||||||
|
MoreDefaultsT::default(),
|
||||||
|
MoreDefaultsT {
|
||||||
|
ints: Vec::new(),
|
||||||
|
floats: Vec::new(),
|
||||||
|
empty_string: "".to_string(),
|
||||||
|
some_string: "some".to_string(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nonpresent_values() {
|
||||||
|
let m = flatbuffers::root::<MoreDefaults>(&[0; 4]).unwrap();
|
||||||
|
assert_eq!(m.ints().len(), 0);
|
||||||
|
assert_eq!(m.floats().len(), 0);
|
||||||
|
assert_eq!(m.empty_string(), "");
|
||||||
|
assert_eq!(m.some_string(), "some");
|
||||||
|
}
|
||||||
@@ -204,7 +204,6 @@ flatbuffers::DetachedBuffer CreateFlatBufferTest(std::string &buffer) {
|
|||||||
flexbuild.Int(1234);
|
flexbuild.Int(1234);
|
||||||
flexbuild.Finish();
|
flexbuild.Finish();
|
||||||
auto flex = builder.CreateVector(flexbuild.GetBuffer());
|
auto flex = builder.CreateVector(flexbuild.GetBuffer());
|
||||||
|
|
||||||
// Test vector of enums.
|
// Test vector of enums.
|
||||||
Color colors[] = { Color_Blue, Color_Green };
|
Color colors[] = { Color_Blue, Color_Green };
|
||||||
// We use this special creation function because we have an array of
|
// We use this special creation function because we have an array of
|
||||||
@@ -1645,7 +1644,6 @@ void ErrorTest() {
|
|||||||
TestError("table X { Y:int; Y:int; }", "field already");
|
TestError("table X { Y:int; Y:int; }", "field already");
|
||||||
TestError("table Y {} table X { Y:int; }", "same as table");
|
TestError("table Y {} table X { Y:int; }", "same as table");
|
||||||
TestError("struct X { Y:string; }", "only scalar");
|
TestError("struct X { Y:string; }", "only scalar");
|
||||||
TestError("table X { Y:string = \"\"; }", "default values");
|
|
||||||
TestError("struct X { a:uint = 42; }", "default values");
|
TestError("struct X { a:uint = 42; }", "default values");
|
||||||
TestError("enum Y:byte { Z = 1 } table X { y:Y; }", "not part of enum");
|
TestError("enum Y:byte { Z = 1 } table X { y:Y; }", "not part of enum");
|
||||||
TestError("struct X { Y:int (deprecated); }", "deprecate");
|
TestError("struct X { Y:int (deprecated); }", "deprecate");
|
||||||
@@ -1690,6 +1688,12 @@ void ErrorTest() {
|
|||||||
"may contain only scalar or struct fields");
|
"may contain only scalar or struct fields");
|
||||||
// Non-snake case field names
|
// Non-snake case field names
|
||||||
TestError("table X { Y: int; } root_type Y: {Y:1.0}", "snake_case");
|
TestError("table X { Y: int; } root_type Y: {Y:1.0}", "snake_case");
|
||||||
|
// Complex defaults
|
||||||
|
TestError("table X { y: string = 1; }", "expecting: string");
|
||||||
|
TestError("table X { y: string = []; }", " Cannot assign token");
|
||||||
|
TestError("table X { y: [int] = [1]; }", "Expected `]`");
|
||||||
|
TestError("table X { y: [int] = [; }", "Expected `]`");
|
||||||
|
TestError("table X { y: [int] = \"\"; }", "type mismatch");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -3620,6 +3624,22 @@ void TestEmbeddedBinarySchema() {
|
|||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StringVectorDefaultsTest() {
|
||||||
|
std::vector<std::string> schemas;
|
||||||
|
schemas.push_back("table Monster { mana: string = \"\"; }");
|
||||||
|
schemas.push_back("table Monster { mana: string = \"mystr\"; }");
|
||||||
|
schemas.push_back("table Monster { mana: string = \" \"; }");
|
||||||
|
schemas.push_back("table Monster { mana: [int] = []; }");
|
||||||
|
schemas.push_back("table Monster { mana: [uint] = [ ]; }");
|
||||||
|
schemas.push_back("table Monster { mana: [byte] = [\t\t\n]; }");
|
||||||
|
for (auto s = schemas.begin(); s < schemas.end(); s++) {
|
||||||
|
flatbuffers::Parser parser;
|
||||||
|
TEST_ASSERT(parser.Parse(s->c_str()));
|
||||||
|
const auto *mana = parser.structs_.Lookup("Monster")->fields.Lookup("mana");
|
||||||
|
TEST_EQ(mana->IsDefault(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void OptionalScalarsTest() {
|
void OptionalScalarsTest() {
|
||||||
// Simple schemas and a "has optional scalar" sentinal.
|
// Simple schemas and a "has optional scalar" sentinal.
|
||||||
std::vector<std::string> schemas;
|
std::vector<std::string> schemas;
|
||||||
@@ -3852,6 +3872,7 @@ int FlatBufferTests() {
|
|||||||
FlatbuffersSpanTest();
|
FlatbuffersSpanTest();
|
||||||
FixedLengthArrayConstructorTest();
|
FixedLengthArrayConstructorTest();
|
||||||
FieldIdentifierTest();
|
FieldIdentifierTest();
|
||||||
|
StringVectorDefaultsTest();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user