|
15 | 15 | */
|
16 | 16 |
|
17 | 17 | #include <folly/Overload.h>
|
| 18 | +#include <thrift/lib/cpp2/Flags.h> |
18 | 19 | #include <thrift/lib/cpp2/op/Clear.h>
|
19 | 20 | #include <thrift/lib/cpp2/op/Patch.h>
|
20 | 21 | #include <thrift/lib/thrift/detail/DynamicPatch.h>
|
|
23 | 24 | #include <thrift/lib/cpp2/patch/detail/PatchBadge.h>
|
24 | 25 |
|
25 | 26 | namespace apache::thrift::protocol {
|
| 27 | +THRIFT_FLAG_DEFINE_bool( |
| 28 | + thrift_patch_diff_visitor_ensure_on_potential_terse_write_field, false); |
| 29 | + |
26 | 30 | using detail::badge;
|
27 | 31 | using detail::ValueList;
|
28 | 32 | using detail::ValueMap;
|
@@ -841,6 +845,38 @@ DynamicMapPatch DiffVisitorBase::diffMap(
|
841 | 845 | return patch;
|
842 | 846 | }
|
843 | 847 |
|
| 848 | +// Check whether value should not be serialized due to deprecated_terse_writes, |
| 849 | +// but serialized in languages other than C++. |
| 850 | +static bool maybeEmptyDeprecatedTerseField(const Value& value) { |
| 851 | + switch (value.getType()) { |
| 852 | + case Value::Type::boolValue: |
| 853 | + case Value::Type::byteValue: |
| 854 | + case Value::Type::i16Value: |
| 855 | + case Value::Type::i32Value: |
| 856 | + case Value::Type::i64Value: |
| 857 | + case Value::Type::floatValue: |
| 858 | + case Value::Type::doubleValue: |
| 859 | + // Numeric fields maybe empty terse field regardless the value, since it |
| 860 | + // honors custom default |
| 861 | + return true; |
| 862 | + case Value::Type::stringValue: |
| 863 | + case Value::Type::binaryValue: |
| 864 | + case Value::Type::listValue: |
| 865 | + case Value::Type::setValue: |
| 866 | + case Value::Type::mapValue: |
| 867 | + // string/binary and containers fields don't honor custom default. |
| 868 | + // It can only be empty if it is intrinsic default |
| 869 | + return protocol::isIntrinsicDefault(value); |
| 870 | + case Value::Type::objectValue: |
| 871 | + // struct/union/exception can never be empty terse field |
| 872 | + return false; |
| 873 | + case Value::Type::__EMPTY__: |
| 874 | + folly::throw_exception<std::runtime_error>("value is empty."); |
| 875 | + default: |
| 876 | + notImpl(); |
| 877 | + } |
| 878 | +} |
| 879 | + |
844 | 880 | void DiffVisitorBase::diffElement(
|
845 | 881 | const ValueMap& src,
|
846 | 882 | const ValueMap& dst,
|
@@ -889,6 +925,16 @@ DynamicPatch DiffVisitorBase::diffStructured(
|
889 | 925 | bool shouldUseAssignPatch =
|
890 | 926 | src.empty() || dst.empty() || src.begin()->first != dst.begin()->first;
|
891 | 927 |
|
| 928 | + if (THRIFT_FLAG( |
| 929 | + thrift_patch_diff_visitor_ensure_on_potential_terse_write_field)) { |
| 930 | + // If field is src looks like deprecated terse field, we need to use |
| 931 | + // EnsureStruct, which is not supported by UnionPatch, thus we need to use |
| 932 | + // AssignPatch. |
| 933 | + shouldUseAssignPatch = shouldUseAssignPatch || |
| 934 | + (src.begin()->second != dst.begin()->second && |
| 935 | + maybeEmptyDeprecatedTerseField(src.begin()->second)); |
| 936 | + } |
| 937 | + |
892 | 938 | if (shouldUseAssignPatch) {
|
893 | 939 | DynamicUnknownPatch patch;
|
894 | 940 | patch.doNotConvertStringToBinary(badge);
|
@@ -1027,6 +1073,11 @@ void DiffVisitorBase::diffField(
|
1027 | 1073 | auto guard = folly::makeGuard([&] { pop(); });
|
1028 | 1074 | auto subPatch = diff(badge, src.at(id), dst.at(id));
|
1029 | 1075 | if (!subPatch.empty(badge)) {
|
| 1076 | + if (THRIFT_FLAG( |
| 1077 | + thrift_patch_diff_visitor_ensure_on_potential_terse_write_field) && |
| 1078 | + maybeEmptyDeprecatedTerseField(src.at(id))) { |
| 1079 | + patch.ensure(badge, id, emptyValue(src.at(id).getType())); |
| 1080 | + } |
1030 | 1081 | patch.patchIfSet(badge, id).merge(badge, DynamicPatch{std::move(subPatch)});
|
1031 | 1082 | }
|
1032 | 1083 | }
|
|
0 commit comments