Skip to content

Commit

Permalink
Fix handling of +/-inf defaults in TS/rust/go/dart codegen
Browse files Browse the repository at this point in the history
+/-inf were not being handled, and so invalid typescript was being
generated when a float/double had an infinite default value. NaN was
being handled correctly.
  • Loading branch information
jkuszmaul committed Oct 17, 2022
1 parent e1c5db9 commit 1157ba8
Show file tree
Hide file tree
Showing 43 changed files with 7,792 additions and 4,600 deletions.
15 changes: 12 additions & 3 deletions dart/test/flat_buffers_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,10 @@ class CheckOtherLangaugesData {
'testrequirednestedflatbuffer: null, scalarKeySortedTables: null, '
'nativeInline: null, '
'longEnumNonEnumDefault: LongEnum{value: 0}, '
'longEnumNormalDefault: LongEnum{value: 2}}, '
'longEnumNormalDefault: LongEnum{value: 2}, nanDefault: NaN, '
'infDefault: Infinity, positiveInfDefault: Infinity, infinityDefault: '
'Infinity, positiveInfinityDefault: Infinity, negativeInfDefault: '
'-Infinity, negativeInfinityDefault: -Infinity}, '
'test4: [Test{a: 10, b: 20}, Test{a: 30, b: 40}], '
'testarrayofstring: [test1, test2], testarrayoftables: null, '
'enemy: Monster{pos: null, mana: 150, hp: 100, name: Fred, '
Expand All @@ -110,7 +113,10 @@ class CheckOtherLangaugesData {
'testrequirednestedflatbuffer: null, scalarKeySortedTables: null, '
'nativeInline: null, '
'longEnumNonEnumDefault: LongEnum{value: 0}, '
'longEnumNormalDefault: LongEnum{value: 2}}, '
'longEnumNormalDefault: LongEnum{value: 2}, nanDefault: NaN, '
'infDefault: Infinity, positiveInfDefault: Infinity, infinityDefault: '
'Infinity, positiveInfinityDefault: Infinity, negativeInfDefault: '
'-Infinity, negativeInfinityDefault: -Infinity}, '
'testnestedflatbuffer: null, testempty: null, testbool: true, '
'testhashs32Fnv1: -579221183, testhashu32Fnv1: 3715746113, '
'testhashs64Fnv1: 7930699090847568257, '
Expand All @@ -137,7 +143,10 @@ class CheckOtherLangaugesData {
'miss, val: 0, count: 0}, Stat{id: hit, val: 10, count: 1}], '
'nativeInline: Test{a: 1, b: 2}, '
'longEnumNonEnumDefault: LongEnum{value: 0}, '
'longEnumNormalDefault: LongEnum{value: 2}}',
'longEnumNormalDefault: LongEnum{value: 2}, nanDefault: NaN, '
'infDefault: Infinity, positiveInfDefault: Infinity, infinityDefault: '
'Infinity, positiveInfinityDefault: Infinity, negativeInfDefault: '
'-Infinity, negativeInfinityDefault: -Infinity}'
);
}
}
Expand Down
12 changes: 12 additions & 0 deletions include/flatbuffers/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,18 @@ inline uint64_t StringToUInt(const char *s, int base = 10) {
return StringToIntegerImpl(&val, s, base) ? val : 0;
}

inline bool StringIsFlatbufferNan(const std::string &s) {
return s == "nan" || s == "+nan" || s == "-nan";
}

inline bool StringIsFlatbufferPositiveInfinity(const std::string &s) {
return s == "inf" || s == "+inf" || s == "infinity" || s == "+infinity";
}

inline bool StringIsFlatbufferNegativeInfinity(const std::string &s) {
return s == "-inf" || s == "-infinity";
}

typedef bool (*LoadFileFunction)(const char *filename, bool binary,
std::string *dest);
typedef bool (*FileExistsFunction)(const char *filename);
Expand Down
20 changes: 11 additions & 9 deletions src/idl_gen_dart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

// independent from idl_parser, since this code is not needed for most clients
#include <cassert>
#include <cmath>

#include "flatbuffers/code_generators.h"
#include "flatbuffers/flatbuffers.h"
Expand Down Expand Up @@ -721,16 +722,17 @@ class DartGenerator : public BaseGenerator {
if (!value.constant.empty() && value.constant != "0") {
if (IsBool(value.type.base_type)) {
return "true";
} else if (value.constant == "nan" || value.constant == "+nan" ||
value.constant == "-nan") {
return "double.nan";
} else if (value.constant == "inf" || value.constant == "+inf") {
return "double.infinity";
} else if (value.constant == "-inf") {
return "double.negativeInfinity";
} else {
return value.constant;
}
if (IsScalar(value.type.base_type)) {
if (StringIsFlatbufferNan(value.constant)) {
return "double.nan";
} else if (StringIsFlatbufferPositiveInfinity(value.constant)) {
return "double.infinity";
} else if (StringIsFlatbufferNegativeInfinity(value.constant)) {
return "double.negativeInfinity";
}
}
return value.constant;
} else if (IsBool(value.type.base_type)) {
return "false";
} else if (IsScalar(value.type.base_type) && !IsUnion(value.type)) {
Expand Down
27 changes: 27 additions & 0 deletions src/idl_gen_go.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

// independent from idl_parser, since this code is not needed for most clients

#include <cmath>
#include <sstream>
#include <string>

Expand Down Expand Up @@ -101,6 +102,7 @@ class GoGenerator : public BaseGenerator {
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
++it) {
tracked_imported_namespaces_.clear();
needs_math_import_ = false;
needs_imports = false;
std::string enumcode;
GenEnum(**it, &enumcode);
Expand All @@ -120,6 +122,7 @@ class GoGenerator : public BaseGenerator {
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
tracked_imported_namespaces_.clear();
needs_math_import_ = false;
std::string declcode;
GenStruct(**it, &declcode);
if (parser_.opts.one_file) {
Expand Down Expand Up @@ -153,6 +156,7 @@ class GoGenerator : public BaseGenerator {
}
};
std::set<const Namespace *, NamespacePtrLess> tracked_imported_namespaces_;
bool needs_math_import_ = false;

// Most field accessors need to retrieve and test the field offset first,
// this is the prefix code for that.
Expand Down Expand Up @@ -1276,6 +1280,23 @@ class GoGenerator : public BaseGenerator {
switch (field.value.type.base_type) {
case BASE_TYPE_BOOL:
return field.value.constant == "0" ? "false" : "true";
case BASE_TYPE_FLOAT:
case BASE_TYPE_DOUBLE: {
const std::string float_type =
field.value.type.base_type == BASE_TYPE_FLOAT ? "float32"
: "float64";
if (StringIsFlatbufferNan(field.value.constant)) {
needs_math_import_ = true;
return float_type + "(math.NaN())";
} else if (StringIsFlatbufferPositiveInfinity(field.value.constant)) {
needs_math_import_ = true;
return float_type + "(math.Inf(1))";
} else if (StringIsFlatbufferNegativeInfinity(field.value.constant)) {
needs_math_import_ = true;
return float_type + "(math.Inf(-1))";
}
return field.value.constant;
}
default: return field.value.constant;
}
}
Expand Down Expand Up @@ -1329,6 +1350,8 @@ class GoGenerator : public BaseGenerator {
if (needs_imports) {
code += "import (\n";
if (is_enum) { code += "\t\"strconv\"\n\n"; }
// math is needed to support non-finite scalar default values.
if (needs_math_import_) { code += "\t\"math\"\n\n"; }
if (!parser_.opts.go_import.empty()) {
code += "\tflatbuffers \"" + parser_.opts.go_import + "\"\n";
} else {
Expand All @@ -1345,6 +1368,10 @@ class GoGenerator : public BaseGenerator {
code += ")\n\n";
} else {
if (is_enum) { code += "import \"strconv\"\n\n"; }
if (needs_math_import_) {
// math is needed to support non-finite scalar default values.
code += "import \"math\"\n\n";
}
}
}

Expand Down
15 changes: 14 additions & 1 deletion src/idl_gen_rust.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

// independent from idl_parser, since this code is not needed for most clients

#include <cmath>

#include "flatbuffers/code_generators.h"
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
Expand Down Expand Up @@ -1046,8 +1048,19 @@ class RustGenerator : public BaseGenerator {
if (field.IsOptional() && !IsUnion(field.value.type)) { return "None"; }
}
switch (GetFullType(field.value.type)) {
case ftInteger:
case ftInteger: {
return field.value.constant;
}
case ftFloat: {
const std::string float_prefix =
(field.value.type.base_type == BASE_TYPE_FLOAT) ? "f32::" : "f64::";
if (StringIsFlatbufferNan(field.value.constant)) {
return float_prefix + "NAN";
} else if (StringIsFlatbufferPositiveInfinity(field.value.constant)) {
return float_prefix + "INFINITY";
} else if (StringIsFlatbufferNegativeInfinity(field.value.constant)) {
return float_prefix + "NEG_INFINITY";
}
return field.value.constant;
}
case ftBool: {
Expand Down
12 changes: 10 additions & 2 deletions src/idl_gen_ts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include <algorithm>
#include <cassert>
#include <cmath>
#include <unordered_map>
#include <unordered_set>

Expand Down Expand Up @@ -439,9 +440,16 @@ class TsGenerator : public BaseGenerator {
return "BigInt('" + value.constant + "')";
}

default:
if (value.constant == "nan") { return "NaN"; }
default: {
if (StringIsFlatbufferNan(value.constant)) {
return "NaN";
} else if (StringIsFlatbufferPositiveInfinity(value.constant)) {
return "Infinity";
} else if (StringIsFlatbufferNegativeInfinity(value.constant)) {
return "-Infinity";
}
return value.constant;
}
}
}

Expand Down
78 changes: 74 additions & 4 deletions tests/MyGame/Example/Monster.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,20 @@ public struct Monster : IFlatbufferObject
public bool MutateLongEnumNonEnumDefault(MyGame.Example.LongEnum long_enum_non_enum_default) { int o = __p.__offset(108); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, (ulong)long_enum_non_enum_default); return true; } else { return false; } }
public MyGame.Example.LongEnum LongEnumNormalDefault { get { int o = __p.__offset(110); return o != 0 ? (MyGame.Example.LongEnum)__p.bb.GetUlong(o + __p.bb_pos) : MyGame.Example.LongEnum.LongOne; } }
public bool MutateLongEnumNormalDefault(MyGame.Example.LongEnum long_enum_normal_default) { int o = __p.__offset(110); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, (ulong)long_enum_normal_default); return true; } else { return false; } }
public float NanDefault { get { int o = __p.__offset(112); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)Single.NaN; } }
public bool MutateNanDefault(float nan_default) { int o = __p.__offset(112); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, nan_default); return true; } else { return false; } }
public float InfDefault { get { int o = __p.__offset(114); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)Single.PositiveInfinity; } }
public bool MutateInfDefault(float inf_default) { int o = __p.__offset(114); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, inf_default); return true; } else { return false; } }
public float PositiveInfDefault { get { int o = __p.__offset(116); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)Single.PositiveInfinity; } }
public bool MutatePositiveInfDefault(float positive_inf_default) { int o = __p.__offset(116); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, positive_inf_default); return true; } else { return false; } }
public float InfinityDefault { get { int o = __p.__offset(118); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)Single.PositiveInfinity; } }
public bool MutateInfinityDefault(float infinity_default) { int o = __p.__offset(118); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, infinity_default); return true; } else { return false; } }
public float PositiveInfinityDefault { get { int o = __p.__offset(120); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)Single.PositiveInfinity; } }
public bool MutatePositiveInfinityDefault(float positive_infinity_default) { int o = __p.__offset(120); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, positive_infinity_default); return true; } else { return false; } }
public float NegativeInfDefault { get { int o = __p.__offset(122); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)Single.NegativeInfinity; } }
public bool MutateNegativeInfDefault(float negative_inf_default) { int o = __p.__offset(122); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, negative_inf_default); return true; } else { return false; } }
public float NegativeInfinityDefault { get { int o = __p.__offset(124); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)Single.NegativeInfinity; } }
public bool MutateNegativeInfinityDefault(float negative_infinity_default) { int o = __p.__offset(124); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, negative_infinity_default); return true; } else { return false; } }

public static Offset<MyGame.Example.Monster> CreateMonster(FlatBufferBuilder builder,
MyGame.Example.Vec3T pos = null,
Expand Down Expand Up @@ -269,8 +283,15 @@ public struct Monster : IFlatbufferObject
VectorOffset scalar_key_sorted_tablesOffset = default(VectorOffset),
MyGame.Example.TestT native_inline = null,
MyGame.Example.LongEnum long_enum_non_enum_default = 0,
MyGame.Example.LongEnum long_enum_normal_default = MyGame.Example.LongEnum.LongOne) {
builder.StartTable(54);
MyGame.Example.LongEnum long_enum_normal_default = MyGame.Example.LongEnum.LongOne,
float nan_default = Single.NaN,
float inf_default = Single.PositiveInfinity,
float positive_inf_default = Single.PositiveInfinity,
float infinity_default = Single.PositiveInfinity,
float positive_infinity_default = Single.PositiveInfinity,
float negative_inf_default = Single.NegativeInfinity,
float negative_infinity_default = Single.NegativeInfinity) {
builder.StartTable(61);
Monster.AddLongEnumNormalDefault(builder, long_enum_normal_default);
Monster.AddLongEnumNonEnumDefault(builder, long_enum_non_enum_default);
Monster.AddNonOwningReference(builder, non_owning_reference);
Expand All @@ -280,6 +301,13 @@ public struct Monster : IFlatbufferObject
Monster.AddTesthashs64Fnv1a(builder, testhashs64_fnv1a);
Monster.AddTesthashu64Fnv1(builder, testhashu64_fnv1);
Monster.AddTesthashs64Fnv1(builder, testhashs64_fnv1);
Monster.AddNegativeInfinityDefault(builder, negative_infinity_default);
Monster.AddNegativeInfDefault(builder, negative_inf_default);
Monster.AddPositiveInfinityDefault(builder, positive_infinity_default);
Monster.AddInfinityDefault(builder, infinity_default);
Monster.AddPositiveInfDefault(builder, positive_inf_default);
Monster.AddInfDefault(builder, inf_default);
Monster.AddNanDefault(builder, nan_default);
Monster.AddNativeInline(builder, MyGame.Example.Test.Pack(builder, native_inline));
Monster.AddScalarKeySortedTables(builder, scalar_key_sorted_tablesOffset);
Monster.AddTestrequirednestedflatbuffer(builder, testrequirednestedflatbufferOffset);
Expand Down Expand Up @@ -327,7 +355,7 @@ public struct Monster : IFlatbufferObject
return Monster.EndMonster(builder);
}

public static void StartMonster(FlatBufferBuilder builder) { builder.StartTable(54); }
public static void StartMonster(FlatBufferBuilder builder) { builder.StartTable(61); }
public static void AddPos(FlatBufferBuilder builder, Offset<MyGame.Example.Vec3> posOffset) { builder.AddStruct(0, posOffset.Value, 0); }
public static void AddMana(FlatBufferBuilder builder, short mana) { builder.AddShort(1, mana, 150); }
public static void AddHp(FlatBufferBuilder builder, short hp) { builder.AddShort(2, hp, 100); }
Expand Down Expand Up @@ -469,6 +497,13 @@ public struct Monster : IFlatbufferObject
public static void AddNativeInline(FlatBufferBuilder builder, Offset<MyGame.Example.Test> nativeInlineOffset) { builder.AddStruct(51, nativeInlineOffset.Value, 0); }
public static void AddLongEnumNonEnumDefault(FlatBufferBuilder builder, MyGame.Example.LongEnum longEnumNonEnumDefault) { builder.AddUlong(52, (ulong)longEnumNonEnumDefault, 0); }
public static void AddLongEnumNormalDefault(FlatBufferBuilder builder, MyGame.Example.LongEnum longEnumNormalDefault) { builder.AddUlong(53, (ulong)longEnumNormalDefault, 2); }
public static void AddNanDefault(FlatBufferBuilder builder, float nanDefault) { builder.AddFloat(54, nanDefault, Single.NaN); }
public static void AddInfDefault(FlatBufferBuilder builder, float infDefault) { builder.AddFloat(55, infDefault, Single.PositiveInfinity); }
public static void AddPositiveInfDefault(FlatBufferBuilder builder, float positiveInfDefault) { builder.AddFloat(56, positiveInfDefault, Single.PositiveInfinity); }
public static void AddInfinityDefault(FlatBufferBuilder builder, float infinityDefault) { builder.AddFloat(57, infinityDefault, Single.PositiveInfinity); }
public static void AddPositiveInfinityDefault(FlatBufferBuilder builder, float positiveInfinityDefault) { builder.AddFloat(58, positiveInfinityDefault, Single.PositiveInfinity); }
public static void AddNegativeInfDefault(FlatBufferBuilder builder, float negativeInfDefault) { builder.AddFloat(59, negativeInfDefault, Single.NegativeInfinity); }
public static void AddNegativeInfinityDefault(FlatBufferBuilder builder, float negativeInfinityDefault) { builder.AddFloat(60, negativeInfinityDefault, Single.NegativeInfinity); }
public static Offset<MyGame.Example.Monster> EndMonster(FlatBufferBuilder builder) {
int o = builder.EndTable();
builder.Required(o, 10); // name
Expand Down Expand Up @@ -620,6 +655,13 @@ public void UnPackTo(MonsterT _o) {
_o.NativeInline = this.NativeInline.HasValue ? this.NativeInline.Value.UnPack() : null;
_o.LongEnumNonEnumDefault = this.LongEnumNonEnumDefault;
_o.LongEnumNormalDefault = this.LongEnumNormalDefault;
_o.NanDefault = this.NanDefault;
_o.InfDefault = this.InfDefault;
_o.PositiveInfDefault = this.PositiveInfDefault;
_o.InfinityDefault = this.InfinityDefault;
_o.PositiveInfinityDefault = this.PositiveInfinityDefault;
_o.NegativeInfDefault = this.NegativeInfDefault;
_o.NegativeInfinityDefault = this.NegativeInfinityDefault;
}
public static Offset<MyGame.Example.Monster> Pack(FlatBufferBuilder builder, MonsterT _o) {
if (_o == null) return default(Offset<MyGame.Example.Monster>);
Expand Down Expand Up @@ -796,7 +838,14 @@ public void UnPackTo(MonsterT _o) {
_scalar_key_sorted_tables,
_o.NativeInline,
_o.LongEnumNonEnumDefault,
_o.LongEnumNormalDefault);
_o.LongEnumNormalDefault,
_o.NanDefault,
_o.InfDefault,
_o.PositiveInfDefault,
_o.InfinityDefault,
_o.PositiveInfinityDefault,
_o.NegativeInfDefault,
_o.NegativeInfinityDefault);
}
}

Expand Down Expand Up @@ -949,6 +998,20 @@ private MyGame.Example.AnyAmbiguousAliases AnyAmbiguousType {
public MyGame.Example.LongEnum LongEnumNonEnumDefault { get; set; }
[Newtonsoft.Json.JsonProperty("long_enum_normal_default")]
public MyGame.Example.LongEnum LongEnumNormalDefault { get; set; }
[Newtonsoft.Json.JsonProperty("nan_default")]
public float NanDefault { get; set; }
[Newtonsoft.Json.JsonProperty("inf_default")]
public float InfDefault { get; set; }
[Newtonsoft.Json.JsonProperty("positive_inf_default")]
public float PositiveInfDefault { get; set; }
[Newtonsoft.Json.JsonProperty("infinity_default")]
public float InfinityDefault { get; set; }
[Newtonsoft.Json.JsonProperty("positive_infinity_default")]
public float PositiveInfinityDefault { get; set; }
[Newtonsoft.Json.JsonProperty("negative_inf_default")]
public float NegativeInfDefault { get; set; }
[Newtonsoft.Json.JsonProperty("negative_infinity_default")]
public float NegativeInfinityDefault { get; set; }

public MonsterT() {
this.Pos = new MyGame.Example.Vec3T();
Expand Down Expand Up @@ -1001,6 +1064,13 @@ public MonsterT() {
this.NativeInline = new MyGame.Example.TestT();
this.LongEnumNonEnumDefault = 0;
this.LongEnumNormalDefault = MyGame.Example.LongEnum.LongOne;
this.NanDefault = Single.NaN;
this.InfDefault = Single.PositiveInfinity;
this.PositiveInfDefault = Single.PositiveInfinity;
this.InfinityDefault = Single.PositiveInfinity;
this.PositiveInfinityDefault = Single.PositiveInfinity;
this.NegativeInfDefault = Single.NegativeInfinity;
this.NegativeInfinityDefault = Single.NegativeInfinity;
}

public static MonsterT DeserializeFromJson(string jsonText) {
Expand Down
Loading

0 comments on commit 1157ba8

Please sign in to comment.