mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-09 22:56:27 +00:00
[C#] Optional Scalars (#6217)
* [C#] Optional Scalars * Moved scalar optional check to avoid null enum conversion
This commit is contained in:
@@ -214,6 +214,9 @@ class CSharpGenerator : public BaseGenerator {
|
||||
|
||||
std::string GenDefaultValue(const FieldDef &field,
|
||||
bool enableLangOverrides) const {
|
||||
// If it is an optional scalar field, the default is null
|
||||
if (field.IsScalarOptional()) { return "null"; }
|
||||
|
||||
auto &value = field.value;
|
||||
if (enableLangOverrides) {
|
||||
// handles both enum case and vector of enum case
|
||||
@@ -396,6 +399,7 @@ class CSharpGenerator : public BaseGenerator {
|
||||
} else {
|
||||
code += ", ";
|
||||
code += GenTypeBasic(type);
|
||||
if (field.IsScalarOptional()) { code += "?"; }
|
||||
if (array_cnt > 0) {
|
||||
code += "[";
|
||||
for (size_t i = 1; i < array_cnt; i++) code += ",";
|
||||
@@ -610,6 +614,7 @@ class CSharpGenerator : public BaseGenerator {
|
||||
optional = "?";
|
||||
conditional_cast = "(" + type_name_dest + optional + ")";
|
||||
}
|
||||
if (field.IsScalarOptional()) { optional = "?"; }
|
||||
std::string dest_mask = "";
|
||||
std::string dest_cast = DestinationCast(field.value.type);
|
||||
std::string src_cast = SourceCast(field.value.type);
|
||||
@@ -646,9 +651,11 @@ class CSharpGenerator : public BaseGenerator {
|
||||
// that doesn't need to be casted. However, default values for enum
|
||||
// elements of vectors are integer literals ("0") and are still casted
|
||||
// for clarity.
|
||||
if (field.value.type.enum_def == nullptr ||
|
||||
IsVector(field.value.type)) {
|
||||
default_cast = "(" + type_name_dest + ")";
|
||||
// If the scalar is optional and enum, we still need the cast.
|
||||
if ((field.value.type.enum_def == nullptr ||
|
||||
IsVector(field.value.type)) ||
|
||||
(IsEnum(field.value.type) && field.IsScalarOptional())) {
|
||||
default_cast = "(" + type_name_dest + optional + ")";
|
||||
}
|
||||
}
|
||||
std::string member_suffix = "; ";
|
||||
@@ -974,6 +981,7 @@ class CSharpGenerator : public BaseGenerator {
|
||||
code += " = null";
|
||||
} else {
|
||||
code += GenTypeBasic(field.value.type);
|
||||
if (field.IsScalarOptional()) { code += "?"; }
|
||||
code += " ";
|
||||
code += field.name;
|
||||
if (!IsScalar(field.value.type.base_type)) code += "Offset";
|
||||
@@ -1034,6 +1042,7 @@ class CSharpGenerator : public BaseGenerator {
|
||||
code += GenTypeBasic(field.value.type);
|
||||
auto argname = MakeCamel(field.name, false);
|
||||
if (!IsScalar(field.value.type.base_type)) argname += "Offset";
|
||||
if (field.IsScalarOptional()) { code += "?"; }
|
||||
code += " " + argname + ") { builder.Add";
|
||||
code += GenMethod(field.value.type) + "(";
|
||||
code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
|
||||
@@ -1043,8 +1052,13 @@ class CSharpGenerator : public BaseGenerator {
|
||||
field.value.type.base_type != BASE_TYPE_UNION) {
|
||||
code += ".Value";
|
||||
}
|
||||
code += ", ";
|
||||
code += GenDefaultValue(field, false);
|
||||
if (!field.IsScalarOptional()) {
|
||||
// When the scalar is optional, use the builder method that doesn't
|
||||
// supply a default value. Otherwise, we to continue to use the
|
||||
// default value method.
|
||||
code += ", ";
|
||||
code += GenDefaultValue(field, false);
|
||||
}
|
||||
code += "); }\n";
|
||||
if (IsVector(field.value.type)) {
|
||||
auto vector_type = field.value.type.VectorType();
|
||||
@@ -1069,7 +1083,7 @@ class CSharpGenerator : public BaseGenerator {
|
||||
code += SourceCastBasic(vector_type);
|
||||
code += "data[i]";
|
||||
if (vector_type.base_type == BASE_TYPE_STRUCT ||
|
||||
IsString(vector_type))
|
||||
IsString(vector_type))
|
||||
code += ".Value";
|
||||
code += "); return ";
|
||||
code += "builder.EndVector(); }\n";
|
||||
@@ -1476,11 +1490,10 @@ class CSharpGenerator : public BaseGenerator {
|
||||
case BASE_TYPE_ARRAY: {
|
||||
auto type_name = GenTypeGet_ObjectAPI(field.value.type, opts);
|
||||
auto length_str = NumToString(field.value.type.fixed_length);
|
||||
auto unpack_method = field.value.type.struct_def == nullptr
|
||||
? ""
|
||||
: field.value.type.struct_def->fixed
|
||||
? ".UnPack()"
|
||||
: "?.UnPack()";
|
||||
auto unpack_method = field.value.type.struct_def == nullptr ? ""
|
||||
: field.value.type.struct_def->fixed
|
||||
? ".UnPack()"
|
||||
: "?.UnPack()";
|
||||
code += start + "new " + type_name.substr(0, type_name.length() - 1) +
|
||||
length_str + "];\n";
|
||||
code += " for (var _j = 0; _j < " + length_str + "; ++_j) { _o." +
|
||||
|
||||
@@ -716,8 +716,7 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
|
||||
// with a special suffix.
|
||||
ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
|
||||
type.enum_def->underlying_type, &typefield));
|
||||
} else if (IsVector(type) &&
|
||||
type.element == BASE_TYPE_UNION) {
|
||||
} else if (IsVector(type) && type.element == BASE_TYPE_UNION) {
|
||||
// Only cpp, js and ts supports the union vector feature so far.
|
||||
if (!SupportsAdvancedUnionFeatures()) {
|
||||
return Error(
|
||||
@@ -792,8 +791,8 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
|
||||
// Table, struct or string can't have enum_def.
|
||||
// Default value of union and vector in NONE, NULL translated to "0".
|
||||
FLATBUFFERS_ASSERT(IsInteger(type.base_type) ||
|
||||
(type.base_type == BASE_TYPE_UNION) ||
|
||||
IsVector(type) || IsArray(type));
|
||||
(type.base_type == BASE_TYPE_UNION) || IsVector(type) ||
|
||||
IsArray(type));
|
||||
if (IsVector(type)) {
|
||||
// Vector can't use initialization list.
|
||||
FLATBUFFERS_ASSERT(field->value.constant == "0");
|
||||
@@ -814,8 +813,7 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
|
||||
field->deprecated = field->attributes.Lookup("deprecated") != nullptr;
|
||||
auto hash_name = field->attributes.Lookup("hash");
|
||||
if (hash_name) {
|
||||
switch ((IsVector(type)) ? type.element
|
||||
: type.base_type) {
|
||||
switch ((IsVector(type)) ? type.element : type.base_type) {
|
||||
case BASE_TYPE_SHORT:
|
||||
case BASE_TYPE_USHORT: {
|
||||
if (FindHashFunction16(hash_name->constant.c_str()) == nullptr)
|
||||
@@ -968,8 +966,7 @@ CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
|
||||
auto &type = elem->second->value.type;
|
||||
if (type.enum_def == val.type.enum_def) {
|
||||
if (inside_vector) {
|
||||
if (IsVector(type) &&
|
||||
type.element == BASE_TYPE_UTYPE) {
|
||||
if (IsVector(type) && type.element == BASE_TYPE_UTYPE) {
|
||||
// Vector of union type field.
|
||||
uoffset_t offset;
|
||||
ECHECK(atot(elem->first.constant.c_str(), *this, &offset));
|
||||
@@ -2283,7 +2280,7 @@ bool Parser::SupportsOptionalScalars(const flatbuffers::IDLOptions &opts) {
|
||||
static FLATBUFFERS_CONSTEXPR unsigned long supported_langs =
|
||||
IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kLobster |
|
||||
IDLOptions::kKotlin | IDLOptions::kCpp | IDLOptions::kJava |
|
||||
IDLOptions::kTs | IDLOptions::kJs;
|
||||
IDLOptions::kCSharp | IDLOptions::kTs | IDLOptions::kJs;
|
||||
unsigned long langs = opts.lang_to_generate;
|
||||
return (langs > 0 && langs < IDLOptions::kMAX) && !(langs & ~supported_langs);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user