kDefault,
};
Presence static MakeFieldPresence(bool optional, bool required) {
+ FLATBUFFERS_ASSERT(!(required && optional));
// clang-format off
return required ? FieldDef::kRequired
: optional ? FieldDef::kOptional
bool SupportsAdvancedUnionFeatures() const;
bool SupportsAdvancedArrayFeatures() const;
bool SupportsOptionalScalars() const;
+ bool SupportsDefaultVectorsAndStrings() const;
Namespace *UniqueNamespace(Namespace *ns);
FLATBUFFERS_CHECKED_ERROR RecurseError();
[package]
name = "flatbuffers"
-version = "0.8.2"
+version = "0.8.3"
edition = "2018"
authors = ["Robert Winslow <hello@rwinslow.com>", "FlatBuffers Maintainers"]
license = "Apache-2.0"
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>
where
T: 'a + Follow<'a>,
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 {
class RustGenerator : public BaseGenerator {
return "VT_" + MakeUpper(Name(field));
}
- std::string GetDefaultValue(const FieldDef &field, bool for_builder) {
- if (for_builder) {
+ enum DefaultContext { kBuilder, kAccessor, kObject };
+ std::string GetDefaultValue(const FieldDef &field,
+ const DefaultContext context) {
+ if (context == kBuilder) {
// Builders and Args structs model nonscalars "optional" even if they're
// required or have defaults according to the schema. I guess its because
// WIPOffset is not nullable.
return ObjectFieldType(field, true) + "::NONE";
}
case ftString: {
- // Required strings.
- return "String::new()"; // No default strings yet.
+ // Required fields do not have defaults defined by the schema, but we
+ // 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 ftVectorOfFloat:
case ftVectorOfInteger:
case ftVectorOfStruct:
case ftVectorOfTable:
case ftVectorOfEnumKey:
- case ftVectorOfUnionValue: {
- // Required vectors.
- return "Vec::new()"; // No default strings yet.
- }
+ case ftVectorOfUnionValue:
case ftStruct:
case ftTable: {
- // Required struct/tables.
- return "Default::default()"; // punt.
+ // We only support empty vectors which matches the defaults for
+ // &[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.");
std::string TableBuilderArgsDefnType(const FieldDef &field,
const std::string &lifetime) {
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)) {
case ftInteger:
case ftFloat:
case ftBool: {
- const auto typname = GetTypeBasic(type);
- return field.IsOptional() ? "Option<" + typname + ">" : typname;
+ return WrapOption(GetTypeBasic(type));
}
case ftStruct: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return "Option<&" + lifetime + " " + typname + ">";
+ return WrapOption("&" + lifetime + " " + typname);
}
case ftTable: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return "Option<flatbuffers::WIPOffset<" + typname + "<" + lifetime +
- ">>>";
+ return WrapOption("flatbuffers::WIPOffset<" + typname + "<" + lifetime +
+ ">>");
}
case ftString: {
- return "Option<flatbuffers::WIPOffset<&" + lifetime + " str>>";
+ return WrapOption("flatbuffers::WIPOffset<&" + lifetime + " str>");
}
case ftEnumKey:
case ftUnionKey: {
- const auto typname = WrapInNameSpace(*type.enum_def);
- return field.IsOptional() ? "Option<" + typname + ">" : typname;
+ return WrapOption(WrapInNameSpace(*type.enum_def));
}
case ftUnionValue: {
return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>";
case ftVectorOfBool:
case ftVectorOfFloat: {
const auto typname = GetTypeBasic(type.VectorType());
- return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
- ", " + typname + ">>>";
+ return WrapVector(typname);
}
case ftVectorOfEnumKey: {
const auto typname = WrapInNameSpace(*type.enum_def);
- return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
- ", " + typname + ">>>";
+ return WrapVector(typname);
}
case ftVectorOfStruct: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
- ", " + typname + ">>>";
+ return WrapVector(typname);
}
case ftVectorOfTable: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
- ", flatbuffers::ForwardsUOffset<" + typname + "<" + lifetime +
- ">>>>>";
+ return WrapUOffsetsVector(typname + "<" + lifetime + ">");
}
case ftVectorOfString: {
- return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
- ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>>";
+ return WrapUOffsetsVector("&" + lifetime + " str");
}
case ftVectorOfUnionValue: {
- const auto typname =
- WrapInNameSpace(*type.enum_def) + "UnionTableOffset";
- return "Option<flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime +
- ", flatbuffers::ForwardsUOffset<"
- "flatbuffers::Table<" +
- lifetime + ">>>>";
+ return WrapUOffsetsVector("flatbuffers::Table<" + lifetime + ">");
}
}
return "INVALID_CODE_GENERATION"; // for return analysis
return "INVALID_CODE_GENERATION"; // OH NO!
}
}
- if (in_a_table && !IsUnion(type) &&
- (IsScalar(type.base_type) ? field.IsOptional() : !field.IsRequired())) {
+ if (in_a_table && !IsUnion(type) && field.IsOptional()) {
return "Option<" + ty + ">";
} else {
return ty;
std::string GenTableAccessorFuncReturnType(const FieldDef &field,
const std::string &lifetime) {
const Type &type = field.value.type;
+ const auto WrapOption = [&](std::string s) {
+ return field.IsOptional() ? "Option<" + s + ">" : s;
+ };
switch (GetFullType(field.value.type)) {
case ftInteger:
case ftFloat:
case ftBool: {
- const auto typname = GetTypeBasic(type);
- return field.IsOptional() ? "Option<" + typname + ">" : typname;
+ return WrapOption(GetTypeBasic(type));
}
case ftStruct: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return WrapInOptionIfNotRequired("&" + lifetime + " " + typname,
- field.IsRequired());
+ return WrapOption("&" + lifetime + " " + typname);
}
case ftTable: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return WrapInOptionIfNotRequired(typname + "<" + lifetime + ">",
- field.IsRequired());
+ return WrapOption(typname + "<" + lifetime + ">");
}
case ftEnumKey:
case ftUnionKey: {
- const auto typname = WrapInNameSpace(*type.enum_def);
- return field.IsOptional() ? "Option<" + typname + ">" : typname;
+ return WrapOption(WrapInNameSpace(*type.enum_def));
}
case ftUnionValue: {
- return WrapInOptionIfNotRequired("flatbuffers::Table<" + lifetime + ">",
- field.IsRequired());
+ return WrapOption("flatbuffers::Table<" + lifetime + ">");
}
case ftString: {
- return WrapInOptionIfNotRequired("&" + lifetime + " str",
- field.IsRequired());
+ return WrapOption("&" + lifetime + " str");
}
case ftVectorOfInteger:
case ftVectorOfBool:
case ftVectorOfFloat: {
const auto typname = GetTypeBasic(type.VectorType());
- if (IsOneByte(type.VectorType().base_type)) {
- return WrapInOptionIfNotRequired(
- "&" + lifetime + " [" + typname + "]", field.IsRequired());
- }
- return WrapInOptionIfNotRequired(
- "flatbuffers::Vector<" + lifetime + ", " + typname + ">",
- field.IsRequired());
+ const auto vector_type =
+ IsOneByte(type.VectorType().base_type)
+ ? "&" + lifetime + " [" + typname + "]"
+ : "flatbuffers::Vector<" + lifetime + ", " + typname + ">";
+ return WrapOption(vector_type);
}
case ftVectorOfEnumKey: {
const auto typname = WrapInNameSpace(*type.enum_def);
- return WrapInOptionIfNotRequired(
- "flatbuffers::Vector<" + lifetime + ", " + typname + ">",
- field.IsRequired());
+ return WrapOption("flatbuffers::Vector<" + lifetime + ", " + typname +
+ ">");
}
case ftVectorOfStruct: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return WrapInOptionIfNotRequired("&" + lifetime + " [" + typname + "]",
- field.IsRequired());
+ return WrapOption("&" + lifetime + " [" + typname + "]");
}
case ftVectorOfTable: {
const auto typname = WrapInNameSpace(*type.struct_def);
- return WrapInOptionIfNotRequired("flatbuffers::Vector<" + lifetime +
- ", flatbuffers::ForwardsUOffset<" +
- typname + "<" + lifetime + ">>>",
- field.IsRequired());
+ return WrapOption("flatbuffers::Vector<" + lifetime +
+ ", flatbuffers::ForwardsUOffset<" + typname + "<" +
+ lifetime + ">>>");
}
case ftVectorOfString: {
- return WrapInOptionIfNotRequired(
- "flatbuffers::Vector<" + lifetime +
- ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>",
- field.IsRequired());
+ return WrapOption("flatbuffers::Vector<" + lifetime +
+ ", flatbuffers::ForwardsUOffset<&" + lifetime +
+ " str>>");
}
case ftVectorOfUnionValue: {
FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported");
// Default-y fields (scalars so far) are neither optional nor required.
const std::string default_value =
!(field.IsOptional() || field.IsRequired())
- ? "Some(" + GetDefaultValue(field, /*builder=*/true) + ")"
+ ? "Some(" + GetDefaultValue(field, kAccessor) + ")"
: "None";
const std::string unwrap = field.IsOptional() ? "" : ".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
void GenFullyQualifiedNameGetter(const StructDef &struct_def,
const std::string &name) {
code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field));
code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset));
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);
};
const auto &fields = struct_def.fields.vec;
if (struct_def.sortbysize &&
size != SizeOf(field.value.type.base_type))
return;
- if (TableFieldReturnsOption(field)) {
+ if (IsOptionalToBuilder(field)) {
code_ +=
" if let Some(x) = args.{{FIELD_NAME}} "
"{ builder.add_{{FIELD_NAME}}(x); }";
code_ += " Self {";
ForAllObjectTableFields(table, [&](const FieldDef &field) {
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_ += " }";
}
}
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.
// TODO(cneo): Fix this... but its a breaking change?
code_ += " let {{FIELD_NAME}} = Some({";
code_ += " let x = &self.{{FIELD_NAME}};";
code_ += " " + expr;
code_ += " });";
- } else {
- code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}}.as_ref().map(|x|{";
- code_ += " " + expr;
- code_ += " });";
}
}
if (token_ == '=') {
NEXT();
ECHECK(ParseSingleValue(&field->name, field->value, true));
- if (!IsScalar(type.base_type) ||
- (struct_def.fixed && field->value.constant != "0"))
+ if (IsStruct(type) || (struct_def.fixed && field->value.constant != "0"))
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).
field->key = field->attributes.Lookup("key") != nullptr;
const bool required = field->attributes.Lookup("required") != nullptr ||
(IsString(type) && field->key);
- const bool optional =
- IsScalar(type.base_type) ? (field->value.constant == "null") : !required;
+ const bool default_str_or_vec =
+ ((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) {
return Error("Fields cannot be both optional and required.");
}
// Integer token can init any scalar (integer of float).
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 TRY_ECHECK
#undef IF_ECHECK_
unsigned long langs = opts.lang_to_generate;
return (langs > 0 && langs < IDLOptions::kMAX) && !(langs & ~supported_langs);
}
-
bool Parser::SupportsOptionalScalars() const {
// Check in general if a language isn't specified.
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 {
return opts.lang_to_generate != 0 &&
(opts.lang_to_generate &
../flatc --csharp --rust --gen-object-api 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
../flatc --cpp --scoped-enums $TEST_CPP_FLAGS -o evolution_test ./evolution_test/evolution_v*.fbs
pos: None,
mana: 150,
hp: 100,
- name: String::new(),
+ name: "".to_string(),
inventory: None,
color: Color::Blue,
test: AnyT::NONE,
--- /dev/null
+
+table MoreDefaults {
+ ints: [int] = [];
+ floats: [float] = [ ];
+ empty_string: string = "";
+ some_string: string = "some";
+}
--- /dev/null
+// 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,
+ })
+ }
+}
mod flexbuffers_tests;
mod optional_scalars_test;
+mod more_defaults_test;
#[allow(dead_code, unused_imports)]
#[path = "../../include_test/include_test1_generated.rs"]
--- /dev/null
+#[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");
+}
flexbuild.Int(1234);
flexbuild.Finish();
auto flex = builder.CreateVector(flexbuild.GetBuffer());
-
// Test vector of enums.
Color colors[] = { Color_Blue, Color_Green };
// We use this special creation function because we have an array of
TestError("table X { Y:int; Y:int; }", "field already");
TestError("table Y {} table X { Y:int; }", "same as table");
TestError("struct X { Y:string; }", "only scalar");
- TestError("table X { Y:string = \"\"; }", "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("struct X { Y:int (deprecated); }", "deprecate");
"may contain only scalar or struct fields");
// Non-snake case field names
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>
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() {
// Simple schemas and a "has optional scalar" sentinal.
std::vector<std::string> schemas;
FlatbuffersSpanTest();
FixedLengthArrayConstructorTest();
FieldIdentifierTest();
+ StringVectorDefaultsTest();
return 0;
}