diff options
author | Gregory Noma <gregory.noma@gmail.com> | 2022-01-26 22:50:27 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-01-26 23:43:54 +0000 |
commit | 90239f246867eb632ad03520dbe6856af50e5c7e (patch) | |
tree | 4e3c0c2853168f8191010194216d0bae8f6f2b92 /buildscripts | |
parent | 9b3c10f0baba2522c37db5dfdb1d41c78522c20b (diff) | |
download | mongo-90239f246867eb632ad03520dbe6856af50e5c7e.tar.gz |
SERVER-63002 Support bindata types for variants in IDL
Diffstat (limited to 'buildscripts')
-rw-r--r-- | buildscripts/idl/idl/binder.py | 16 | ||||
-rw-r--r-- | buildscripts/idl/idl/generator.py | 33 | ||||
-rw-r--r-- | buildscripts/idl/tests/test_binder.py | 71 |
3 files changed, 83 insertions, 37 deletions
diff --git a/buildscripts/idl/idl/binder.py b/buildscripts/idl/idl/binder.py index d615f4a633b..49fab8a39e1 100644 --- a/buildscripts/idl/idl/binder.py +++ b/buildscripts/idl/idl/binder.py @@ -87,15 +87,15 @@ def _validate_bson_types_list(ctxt, idl_type, syntax_type): ctxt.add_bad_bson_type_error(idl_type, syntax_type, idl_type.name, bson_type) return False - # V1 restiction: cannot mix bindata into list of types - if bson_type == "bindata": - ctxt.add_bad_bson_type_error(idl_type, syntax_type, idl_type.name, bson_type) - return False + if not isinstance(idl_type, syntax.VariantType): + if bson_type == "bindata": + ctxt.add_bad_bson_type_error(idl_type, syntax_type, idl_type.name, bson_type) + return False - # Cannot mix non-scalar types into the list of types - if not isinstance(idl_type, syntax.VariantType) and not bson.is_scalar_bson_type(bson_type): - ctxt.add_bad_bson_scalar_type_error(idl_type, syntax_type, idl_type.name, bson_type) - return False + # Cannot mix non-scalar types into the list of types + if not bson.is_scalar_bson_type(bson_type): + ctxt.add_bad_bson_scalar_type_error(idl_type, syntax_type, idl_type.name, bson_type) + return False return True diff --git a/buildscripts/idl/idl/generator.py b/buildscripts/idl/idl/generator.py index d9879e97109..ff9da001069 100644 --- a/buildscripts/idl/idl/generator.py +++ b/buildscripts/idl/idl/generator.py @@ -30,6 +30,7 @@ import hashlib import io +import itertools import os import re import sys @@ -1962,11 +1963,26 @@ class _CppSourceFileWriter(_CppFileWriterBase): } with self._with_template(template_params): - # See https://en.cppreference.com/w/cpp/utility/variant/visit - # This lambda is a template instantiated for each alternate type. Use "if constexpr" - # to compile the appropriate serialization code for each. - with self._block('stdx::visit([builder](auto&& arg) {', '}, ${access_member});'): - self._writer.write_template('idl::idlSerialize(builder, ${field_name}, arg);') + with self._block('stdx::visit(visit_helper::Overloaded{', '}, ${access_member});'): + for variant_type in itertools.chain( + field.type.variant_types, + [field.type.variant_struct_type] if field.type.variant_struct_type else []): + + template_params[ + 'cpp_type'] = 'std::vector<' + variant_type.cpp_type + '>' if variant_type.is_array else variant_type.cpp_type + + with self._block('[builder](const ${cpp_type}& value) {', '},'): + bson_cpp_type = cpp_types.get_bson_cpp_type(variant_type) + if bson_cpp_type and bson_cpp_type.has_serializer(): + assert not field.type.is_array + expression = bson_cpp_type.gen_serializer_expression( + self._writer, 'value') + template_params['expression'] = expression + self._writer.write_template( + 'builder->append(${field_name}, ${expression});') + else: + self._writer.write_template( + 'idl::idlSerialize(builder, ${field_name}, value);') def _gen_serializer_method_common(self, field): # type: (ast.Field) -> None @@ -2604,10 +2620,9 @@ class _CppSourceFileWriter(_CppFileWriterBase): # Generate mongo includes third header_list = [ - 'mongo/bson/bsonobjbuilder.h', - 'mongo/db/auth/authorization_contract.h', - 'mongo/db/commands.h', - 'mongo/idl/command_generic_argument.h', + 'mongo/bson/bsonobjbuilder.h', 'mongo/db/auth/authorization_contract.h', + 'mongo/db/commands.h', 'mongo/idl/command_generic_argument.h', + 'mongo/util/visit_helper.h' ] if spec.server_parameters: diff --git a/buildscripts/idl/tests/test_binder.py b/buildscripts/idl/tests/test_binder.py index 47f6d62efa4..b1f809ff5c7 100644 --- a/buildscripts/idl/tests/test_binder.py +++ b/buildscripts/idl/tests/test_binder.py @@ -602,6 +602,57 @@ class TestBinder(testcase.IDLTestcase): foo: array<int> """)) + def test_variant_positive(self): + # type: () -> None + """Positive variant test cases.""" + + # Setup some common types + test_preamble = textwrap.dedent(""" + types: + string: + description: foo + cpp_type: foo + bson_serialization_type: string + serializer: foo + deserializer: foo + default: foo + int: + description: foo + cpp_type: std::int32_t + bson_serialization_type: int + deserializer: mongo::BSONElement::_numberInt + bindata_function: + bson_serialization_type: bindata + bindata_subtype: function + description: "A BSON bindata of function sub type" + cpp_type: "std::vector<std::uint8_t>" + deserializer: "mongo::BSONElement::_binDataVector" + """) + + self.assert_bind(test_preamble + textwrap.dedent(""" + structs: + foo: + description: foo + fields: + my_variant_field: + type: + variant: + - string + - int + """)) + + self.assert_bind(test_preamble + textwrap.dedent(""" + structs: + foo: + description: foo + fields: + my_variant_field: + type: + variant: + - string + - bindata_function + """)) + def test_variant_negative(self): # type: () -> None """Negative variant test cases.""" @@ -637,12 +688,6 @@ class TestBinder(testcase.IDLTestcase): description: foo cpp_type: "std::int32_t" deserializer: "mongo::BSONElement::safeNumberInt" - bindata_function: - bson_serialization_type: bindata - bindata_subtype: function - description: "A BSON bindata of function sub type" - cpp_type: "std::vector<std::uint8_t>" - deserializer: "mongo::BSONElement::_binDataVector" """) self.assert_bind_fail( @@ -685,20 +730,6 @@ class TestBinder(testcase.IDLTestcase): default: 1 """), idl.errors.ERROR_ID_VARIANT_NO_DEFAULT) - # Bindata is banned in variants for now. - self.assert_bind_fail( - test_preamble + textwrap.dedent(""" - structs: - foo: - description: foo - fields: - my_variant_field: - type: - variant: - - string - - bindata_function - """), idl.errors.ERROR_ID_BAD_BSON_TYPE) - # Enums are banned in variants for now. self.assert_bind_fail( test_preamble + textwrap.dedent(""" |