Add support for container of nullable primitives to js-lite
This change updates the js-lite binding to support arrays of nullables. The change checks a bitfield in the serialized format when decoding and encodes the same bitfield when serializing. This is only used for arrays of nullable primitives. The wire format is as follows: | header | | bitfield | | padding | | values | The bitfield dictates whether or not a value in the array is null or not. Note that null values are still serialized (the value that is used is up to the implementation). Working: C++ Js Not working: Java Ts Change-Id: I657e8ab381181dcce1829ed7c7f7e3420d84935f Bug: 657632 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5280977 Reviewed-by: Rebekah Potter <rbpotter@chromium.org> Reviewed-by: Yuzhu Shen <yzshen@chromium.org> Commit-Queue: Fred Shih <ffred@chromium.org> Reviewed-by: Daniel Cheng <dcheng@chromium.org> Reviewed-by: Peter Beverloo <peter@chromium.org> Cr-Commit-Position: refs/heads/main@{#1288235}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
f81706c658
commit
2392b787b9
content/web_test
browser
common
mojo/public/js
third_party/blink/web_tests/http/tests/mojo/shared
@ -85,6 +85,76 @@ void Params::SendNullEnum(std::optional<mojom::RegularEnum> optional_enum,
|
||||
std::move(callback).Run();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void CheckAllNulls(const std::vector<T>& optionals) {
|
||||
for (auto& optional : optionals) {
|
||||
CHECK(!optional.has_value());
|
||||
}
|
||||
}
|
||||
|
||||
void Params::SendNullBools(
|
||||
const std::vector<std::optional<bool>>& optional_bools,
|
||||
SendNullBoolsCallback callback) {
|
||||
CheckAllNulls(optional_bools);
|
||||
std::move(callback).Run();
|
||||
}
|
||||
|
||||
void Params::SendNullInt16s(
|
||||
const std::vector<std::optional<int16_t>>& optional_int16s,
|
||||
SendNullInt16sCallback callback) {
|
||||
CheckAllNulls(optional_int16s);
|
||||
std::move(callback).Run();
|
||||
}
|
||||
|
||||
void Params::SendNullUint32s(
|
||||
const std::vector<std::optional<uint32_t>>& optional_uint32s,
|
||||
SendNullUint32sCallback callback) {
|
||||
CheckAllNulls(optional_uint32s);
|
||||
std::move(callback).Run();
|
||||
}
|
||||
|
||||
void Params::SendNullDoubles(
|
||||
const std::vector<std::optional<double>>& optional_doubles,
|
||||
SendNullDoublesCallback callback) {
|
||||
CheckAllNulls(optional_doubles);
|
||||
std::move(callback).Run();
|
||||
}
|
||||
|
||||
void Params::SendNullEnums(
|
||||
const std::vector<std::optional<mojom::RegularEnum>>& optional_enums,
|
||||
SendNullEnumsCallback callback) {
|
||||
CheckAllNulls(optional_enums);
|
||||
std::move(callback).Run();
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
void CheckAllNulls(const base::flat_map<K, V>& values) {
|
||||
for (auto& pair : values) {
|
||||
CHECK(!pair.second.has_value());
|
||||
}
|
||||
}
|
||||
|
||||
void Params::SendNullBoolMap(
|
||||
const base::flat_map<int32_t, std::optional<bool>>& values,
|
||||
SendNullBoolMapCallback callback) {
|
||||
CheckAllNulls(values);
|
||||
std::move(callback).Run();
|
||||
}
|
||||
|
||||
void Params::SendNullDoubleMap(
|
||||
const base::flat_map<int32_t, std::optional<double>>& values,
|
||||
SendNullDoubleMapCallback callback) {
|
||||
CheckAllNulls(values);
|
||||
std::move(callback).Run();
|
||||
}
|
||||
|
||||
void Params::SendNullEnumMap(
|
||||
const base::flat_map<int32_t, std::optional<mojom::RegularEnum>>& values,
|
||||
SendNullEnumMapCallback callback) {
|
||||
CheckAllNulls(values);
|
||||
std::move(callback).Run();
|
||||
}
|
||||
|
||||
void Params::SendOptionalBool(std::optional<bool> optional_bool,
|
||||
SendOptionalBoolCallback callback) {
|
||||
std::move(callback).Run(optional_bool.value());
|
||||
@ -145,6 +215,76 @@ void Params::SendOptionalEnum(std::optional<mojom::RegularEnum> optional_enum,
|
||||
std::move(callback).Run(optional_enum.value());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> Unwrap(const std::vector<std::optional<T>>& in) {
|
||||
std::vector<T> out;
|
||||
for (auto e : in) {
|
||||
if (e) {
|
||||
out.push_back(*e);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void Params ::SendOptionalBools(
|
||||
const std::vector<std::optional<bool>>& optional_bools,
|
||||
SendOptionalBoolsCallback callback) {
|
||||
std::move(callback).Run(Unwrap(optional_bools));
|
||||
}
|
||||
|
||||
void Params ::SendOptionalInt16s(
|
||||
const std::vector<std::optional<int16_t>>& optional_int16s,
|
||||
SendOptionalInt16sCallback callback) {
|
||||
std::move(callback).Run(Unwrap(optional_int16s));
|
||||
}
|
||||
|
||||
void Params ::SendOptionalUint32s(
|
||||
const std::vector<std::optional<uint32_t>>& optional_uint32s,
|
||||
SendOptionalUint32sCallback callback) {
|
||||
std::move(callback).Run(Unwrap(optional_uint32s));
|
||||
}
|
||||
|
||||
void Params ::SendOptionalDoubles(
|
||||
const std::vector<std::optional<double>>& optional_doubles,
|
||||
SendOptionalDoublesCallback callback) {
|
||||
std::move(callback).Run(Unwrap(optional_doubles));
|
||||
}
|
||||
|
||||
void Params ::SendOptionalEnums(
|
||||
const std::vector<std::optional<mojom::RegularEnum>>& optional_enums,
|
||||
SendOptionalEnumsCallback callback) {
|
||||
std::move(callback).Run(Unwrap(optional_enums));
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
base::flat_map<K, V> Unwrap(const base::flat_map<K, std::optional<V>>& values) {
|
||||
base::flat_map<K, V> out;
|
||||
for (const auto& entry : values) {
|
||||
if (entry.second) {
|
||||
out.insert({entry.first, *entry.second});
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void Params::SendOptionalBoolMap(
|
||||
const base::flat_map<int32_t, std::optional<bool>>& values,
|
||||
SendOptionalBoolMapCallback callback) {
|
||||
std::move(callback).Run(Unwrap(values));
|
||||
}
|
||||
|
||||
void Params::SendOptionalDoubleMap(
|
||||
const base::flat_map<int32_t, std::optional<double>>& values,
|
||||
SendOptionalDoubleMapCallback callback) {
|
||||
std::move(callback).Run(Unwrap(values));
|
||||
}
|
||||
|
||||
void Params::SendOptionalEnumMap(
|
||||
const base::flat_map<int32_t, std::optional<mojom::RegularEnum>>& values,
|
||||
SendOptionalEnumMapCallback callback) {
|
||||
std::move(callback).Run(Unwrap(values));
|
||||
}
|
||||
|
||||
void Params::SendNullStructWithOptionalNumerics(
|
||||
mojom::OptionalNumericsStructPtr s,
|
||||
SendNullStructWithOptionalNumericsCallback callback) {
|
||||
@ -235,6 +375,41 @@ void ResponseParams::GetNullDouble(GetNullDoubleCallback callback) {
|
||||
void ResponseParams::GetNullEnum(GetNullEnumCallback callback) {
|
||||
std::move(callback).Run(std::nullopt);
|
||||
}
|
||||
void ResponseParams::GetNullBools(GetNullBoolsCallback callback) {
|
||||
std::move(callback).Run(std::vector({std::optional<bool>()}));
|
||||
}
|
||||
|
||||
void ResponseParams::GetNullInt16s(GetNullInt16sCallback callback) {
|
||||
std::move(callback).Run(std::vector({std::optional<int16_t>()}));
|
||||
}
|
||||
|
||||
void ResponseParams::GetNullUint32s(GetNullUint32sCallback callback) {
|
||||
std::move(callback).Run(std::vector({std::optional<uint32_t>()}));
|
||||
}
|
||||
|
||||
void ResponseParams::GetNullDoubles(GetNullDoublesCallback callback) {
|
||||
std::move(callback).Run(std::vector({std::optional<double>()}));
|
||||
}
|
||||
|
||||
void ResponseParams::GetNullEnums(GetNullEnumsCallback callback) {
|
||||
std::move(callback).Run(std::vector({std::optional<mojom::RegularEnum>()}));
|
||||
}
|
||||
|
||||
void ResponseParams::GetNullBoolMap(GetNullBoolMapCallback callback) {
|
||||
std::move(callback).Run(
|
||||
base::flat_map<int16_t, std::optional<bool>>({{0, std::nullopt}}));
|
||||
}
|
||||
|
||||
void ResponseParams::GetNullInt32Map(GetNullInt32MapCallback callback) {
|
||||
std::move(callback).Run(
|
||||
base::flat_map<int16_t, std::optional<int32_t>>({{0, std::nullopt}}));
|
||||
}
|
||||
|
||||
void ResponseParams::GetNullEnumMap(GetNullEnumMapCallback callback) {
|
||||
std::move(callback).Run(
|
||||
base::flat_map<int16_t, std::optional<mojom::RegularEnum>>(
|
||||
{{0, std::nullopt}}));
|
||||
}
|
||||
|
||||
void ResponseParams::GetOptionalBool(bool value,
|
||||
GetOptionalBoolCallback callback) {
|
||||
@ -296,6 +471,54 @@ void ResponseParams::GetOptionalEnum(mojom::RegularEnum value,
|
||||
std::move(callback).Run(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<std::optional<T>> WrapWithNulls(T value) {
|
||||
return std::vector<std::optional<T>>({std::nullopt, value, std::nullopt});
|
||||
}
|
||||
|
||||
void ResponseParams::GetOptionalBools(bool value,
|
||||
GetOptionalBoolsCallback callback) {
|
||||
std::move(callback).Run(WrapWithNulls(value));
|
||||
}
|
||||
void ResponseParams::GetOptionalInt16s(int16_t value,
|
||||
GetOptionalInt16sCallback callback) {
|
||||
std::move(callback).Run(WrapWithNulls(value));
|
||||
}
|
||||
void ResponseParams::GetOptionalUint32s(uint32_t value,
|
||||
GetOptionalUint32sCallback callback) {
|
||||
std::move(callback).Run(WrapWithNulls(value));
|
||||
}
|
||||
void ResponseParams::GetOptionalDoubles(double value,
|
||||
GetOptionalDoublesCallback callback) {
|
||||
std::move(callback).Run(WrapWithNulls(value));
|
||||
}
|
||||
void ResponseParams::GetOptionalEnums(mojom::RegularEnum value,
|
||||
GetOptionalEnumsCallback callback) {
|
||||
std::move(callback).Run(WrapWithNulls(value));
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
base::flat_map<K, std::optional<V>> WrapWithNulls(K key, V value) {
|
||||
return base::flat_map<K, std::optional<V>>(
|
||||
{{key - 1, std::nullopt}, {key, value}, {key + 1, std::nullopt}});
|
||||
}
|
||||
|
||||
void ResponseParams::GetOptionalBoolMap(int16_t key,
|
||||
bool value,
|
||||
GetOptionalBoolMapCallback callback) {
|
||||
std::move(callback).Run(WrapWithNulls(key, value));
|
||||
}
|
||||
void ResponseParams::GetOptionalFloatMap(int16_t key,
|
||||
float value,
|
||||
GetOptionalFloatMapCallback callback) {
|
||||
std::move(callback).Run(WrapWithNulls(key, value));
|
||||
}
|
||||
void ResponseParams::GetOptionalEnumMap(int16_t key,
|
||||
mojom::RegularEnum value,
|
||||
GetOptionalEnumMapCallback callback) {
|
||||
std::move(callback).Run(WrapWithNulls(key, value));
|
||||
}
|
||||
|
||||
void ResponseParams::GetNullStructWithOptionalNumerics(
|
||||
GetNullStructWithOptionalNumericsCallback callback) {
|
||||
std::move(callback).Run(nullptr);
|
||||
|
@ -38,6 +38,31 @@ class Params : public mojom::Params {
|
||||
void SendNullEnum(std::optional<mojom::RegularEnum> optional_enum,
|
||||
SendNullEnumCallback callback) override;
|
||||
|
||||
void SendNullBools(const std::vector<std::optional<bool>>& optional_bools,
|
||||
SendNullBoolsCallback callback) override;
|
||||
void SendNullInt16s(
|
||||
const std::vector<std::optional<int16_t>>& optional_int16s,
|
||||
SendNullInt16sCallback callback) override;
|
||||
void SendNullUint32s(
|
||||
const std::vector<std::optional<uint32_t>>& optional_uint32s,
|
||||
SendNullUint32sCallback callback) override;
|
||||
void SendNullDoubles(
|
||||
const std::vector<std::optional<double>>& optional_doubles,
|
||||
SendNullDoublesCallback callback) override;
|
||||
void SendNullEnums(
|
||||
const std::vector<std::optional<mojom::RegularEnum>>& optional_enums,
|
||||
SendNullEnumsCallback callback) override;
|
||||
|
||||
void SendNullBoolMap(
|
||||
const base::flat_map<int32_t, std::optional<bool>>& values,
|
||||
SendNullBoolMapCallback callback) override;
|
||||
void SendNullDoubleMap(
|
||||
const base::flat_map<int32_t, std::optional<double>>& values,
|
||||
SendNullDoubleMapCallback callback) override;
|
||||
void SendNullEnumMap(
|
||||
const base::flat_map<int32_t, std::optional<mojom::RegularEnum>>& values,
|
||||
SendNullEnumMapCallback callback) override;
|
||||
|
||||
void SendOptionalBool(std::optional<bool> optional_bool,
|
||||
SendOptionalBoolCallback callback) override;
|
||||
void SendOptionalUint8(std::optional<uint8_t> optional_uint8,
|
||||
@ -63,6 +88,31 @@ class Params : public mojom::Params {
|
||||
void SendOptionalEnum(std::optional<mojom::RegularEnum> optional_enum,
|
||||
SendOptionalEnumCallback callback) override;
|
||||
|
||||
void SendOptionalBools(const std::vector<std::optional<bool>>& optional_bools,
|
||||
SendOptionalBoolsCallback callback) override;
|
||||
void SendOptionalInt16s(
|
||||
const std::vector<std::optional<int16_t>>& optional_int16s,
|
||||
SendOptionalInt16sCallback callback) override;
|
||||
void SendOptionalUint32s(
|
||||
const std::vector<std::optional<uint32_t>>& optional_uint32s,
|
||||
SendOptionalUint32sCallback callback) override;
|
||||
void SendOptionalDoubles(
|
||||
const std::vector<std::optional<double>>& optional_doubles,
|
||||
SendOptionalDoublesCallback callback) override;
|
||||
void SendOptionalEnums(
|
||||
const std::vector<std::optional<mojom::RegularEnum>>& optional_enums,
|
||||
SendOptionalEnumsCallback callback) override;
|
||||
|
||||
void SendOptionalBoolMap(
|
||||
const base::flat_map<int32_t, std::optional<bool>>& values,
|
||||
SendOptionalBoolMapCallback callback) override;
|
||||
void SendOptionalDoubleMap(
|
||||
const base::flat_map<int32_t, std::optional<double>>& values,
|
||||
SendOptionalDoubleMapCallback callback) override;
|
||||
void SendOptionalEnumMap(
|
||||
const base::flat_map<int32_t, std::optional<mojom::RegularEnum>>& values,
|
||||
SendOptionalEnumMapCallback callback) override;
|
||||
|
||||
void SendNullStructWithOptionalNumerics(
|
||||
mojom::OptionalNumericsStructPtr s,
|
||||
SendNullStructWithOptionalNumericsCallback callback) override;
|
||||
@ -92,6 +142,16 @@ class ResponseParams : public mojom::ResponseParams {
|
||||
void GetNullDouble(GetNullDoubleCallback callback) override;
|
||||
void GetNullEnum(GetNullEnumCallback callback) override;
|
||||
|
||||
void GetNullBools(GetNullBoolsCallback callback) override;
|
||||
void GetNullInt16s(GetNullInt16sCallback callback) override;
|
||||
void GetNullUint32s(GetNullUint32sCallback callback) override;
|
||||
void GetNullDoubles(GetNullDoublesCallback callback) override;
|
||||
void GetNullEnums(GetNullEnumsCallback callback) override;
|
||||
|
||||
void GetNullBoolMap(GetNullBoolMapCallback callback) override;
|
||||
void GetNullInt32Map(GetNullInt32MapCallback callback) override;
|
||||
void GetNullEnumMap(GetNullEnumMapCallback callback) override;
|
||||
|
||||
void GetOptionalBool(bool value, GetOptionalBoolCallback callback) override;
|
||||
void GetOptionalUint8(uint8_t value,
|
||||
GetOptionalUint8Callback callback) override;
|
||||
@ -115,6 +175,26 @@ class ResponseParams : public mojom::ResponseParams {
|
||||
void GetOptionalEnum(mojom::RegularEnum value,
|
||||
GetOptionalEnumCallback callback) override;
|
||||
|
||||
void GetOptionalBools(bool value, GetOptionalBoolsCallback callback) override;
|
||||
void GetOptionalInt16s(int16_t value,
|
||||
GetOptionalInt16sCallback callback) override;
|
||||
void GetOptionalUint32s(uint32_t value,
|
||||
GetOptionalUint32sCallback callback) override;
|
||||
void GetOptionalDoubles(double value,
|
||||
GetOptionalDoublesCallback callback) override;
|
||||
void GetOptionalEnums(mojom::RegularEnum value,
|
||||
GetOptionalEnumsCallback callback) override;
|
||||
|
||||
void GetOptionalBoolMap(int16_t key,
|
||||
bool value,
|
||||
GetOptionalBoolMapCallback callback) override;
|
||||
void GetOptionalFloatMap(int16_t key,
|
||||
float value,
|
||||
GetOptionalFloatMapCallback callback) override;
|
||||
void GetOptionalEnumMap(int16_t key,
|
||||
mojom::RegularEnum value,
|
||||
GetOptionalEnumMapCallback callback) override;
|
||||
|
||||
void GetNullStructWithOptionalNumerics(
|
||||
GetNullStructWithOptionalNumericsCallback callback) override;
|
||||
void GetStructWithNullOptionalNumerics(
|
||||
|
@ -57,6 +57,24 @@ interface Params {
|
||||
// Runs the empty callback. CHECKs if `optional_enum` is not null.
|
||||
SendNullEnum(RegularEnum? optional_enum) => ();
|
||||
|
||||
// Runs the empty callback. CHECKs if `optional_bools` is not null.
|
||||
SendNullBools(array<bool?> optional_bools) => ();
|
||||
// Runs the empty callback. CHECKs if `optional_int16s` is not null.
|
||||
SendNullInt16s(array<int16?> optional_int16s) => ();
|
||||
// Runs the empty callback. CHECKs if `optional_uint32s` is not null.
|
||||
SendNullUint32s(array<uint32?> optional_uint32s) => ();
|
||||
// Runs the empty callback. CHECKs if `optional_doubles` is not null.
|
||||
SendNullDoubles(array<double?> optional_doubles) => ();
|
||||
// Runs the empty callback. CHECKs if `optional_enums` is not null.
|
||||
SendNullEnums(array<RegularEnum?> optional_enums) => ();
|
||||
|
||||
// Runs the empty callback. CHECKs if `optional_bools` is not null.
|
||||
SendNullBoolMap(map<int32, bool?> values) => ();
|
||||
// Runs the empty callback. CHECKs if `optional_bools` is not null.
|
||||
SendNullDoubleMap(map<int32, double?> values) => ();
|
||||
// Runs the empty callback. CHECKs if `optional_bools` is not null.
|
||||
SendNullEnumMap(map<int32, RegularEnum?> values) => ();
|
||||
|
||||
// The following methods help test that JS correctly handles optional
|
||||
// numerics with a value.
|
||||
//
|
||||
@ -85,6 +103,30 @@ interface Params {
|
||||
// Runs callback with `optional_enum`.
|
||||
SendOptionalEnum(RegularEnum? optional_enum) => (RegularEnum value);
|
||||
|
||||
// Runs callback with `optional_enum`.
|
||||
SendOptionalBools(array<bool?> optional_enums) => (array<bool> values);
|
||||
// Runs callback with `optional_int16`.
|
||||
SendOptionalInt16s(array<int16?> optional_int16s) => (array<int16> values);
|
||||
// Runs callback with `optional_uint32`.
|
||||
SendOptionalUint32s(array<uint32?> optional_uint32s)
|
||||
=> (array<uint32> values);
|
||||
// Runs callback with `optional_double`.
|
||||
SendOptionalDoubles(array<double?> optional_doubles)
|
||||
=> (array<double> values);
|
||||
// Runs callback with `optional_enum`.
|
||||
SendOptionalEnums(array<RegularEnum?> optional_enums)
|
||||
=> (array<RegularEnum> values);
|
||||
|
||||
// Runs callback by unwrapping all null values.
|
||||
SendOptionalBoolMap(map<int32, bool?> values)
|
||||
=> (map<int32, bool> values);
|
||||
// Runs callback by unwrapping all null values.
|
||||
SendOptionalDoubleMap(map<int32, double?> values)
|
||||
=> (map<int32, double> values);
|
||||
// Runs callback by unwrapping all null values.
|
||||
SendOptionalEnumMap(map<int32, RegularEnum?> values)
|
||||
=> (map<int32, RegularEnum> values);
|
||||
|
||||
// Runs a callback with null. Helps test that JS can correctly handle null
|
||||
// structs with optional numerics.
|
||||
SendNullStructWithOptionalNumerics(OptionalNumericsStruct? s) => ();
|
||||
@ -143,6 +185,24 @@ interface ResponseParams {
|
||||
// Returns a null optional enum.
|
||||
GetNullEnum() => (RegularEnum? optional_value);
|
||||
|
||||
// Returns a list of optional bools.
|
||||
GetNullBools() => (array<bool?> optional_values);
|
||||
// Returns a list of optional int16s.
|
||||
GetNullInt16s() => (array<int16?> optional_values);
|
||||
// Returns a list of optional uint32s.
|
||||
GetNullUint32s() => (array<uint32?> optional_values);
|
||||
// Returns a list of optional doubles.
|
||||
GetNullDoubles() => (array<double?> optional_values);
|
||||
// Returns a list of optional enums.
|
||||
GetNullEnums() => (array<RegularEnum?> optional_values);
|
||||
|
||||
// Returns a simple map with a single {0, null} entry.
|
||||
GetNullBoolMap() => (map<int16, bool?> optional_values);
|
||||
// Returns a simple map with a single {0, null} entry.
|
||||
GetNullInt32Map() => (map<int16, int32?> optional_values);
|
||||
// Returns a simple map with a single {0, null} entry.
|
||||
GetNullEnumMap() => (map<int16, RegularEnum?> optional_values);
|
||||
|
||||
// The following methods help test that JS can correctly handle optional
|
||||
// numerics in response params.
|
||||
//
|
||||
@ -171,6 +231,37 @@ interface ResponseParams {
|
||||
// Returns |value| in an optional enum.
|
||||
GetOptionalEnum(RegularEnum value) => (RegularEnum? optional_value);
|
||||
|
||||
// Returns |value| sandwiched between two null values. E.g.:
|
||||
// [null, |value|, null].
|
||||
GetOptionalBools(bool value) => (array<bool?> optional_values);
|
||||
// Returns |value| sandwiched between two null values. E.g.:
|
||||
// [null, |value|, null].
|
||||
GetOptionalInt16s(int16 value) => (array<int16?> optional_values);
|
||||
// Returns |value| sandwiched between two null values. E.g.:
|
||||
// [null, |value|, null].
|
||||
GetOptionalUint32s(uint32 value) => (array<uint32?> optional_values);
|
||||
// Returns |value| sandwiched between two null values. E.g.:
|
||||
// [null, |value|, null].
|
||||
GetOptionalDoubles(double value) => (array<double?> optional_values);
|
||||
// Returns |value| sandwiched between two null values. E.g.:
|
||||
// [null, |value|, null].
|
||||
GetOptionalEnums(RegularEnum value) => (array<RegularEnum?> optional_values);
|
||||
|
||||
// Returns {|key|, |value|} sandwiched between two null values. E.g.:
|
||||
// {
|
||||
// [key - 1]: null,
|
||||
// [key]: value,
|
||||
// [key +1]: value,
|
||||
// }
|
||||
GetOptionalBoolMap(int16 key, bool value)
|
||||
=> (map<int16, bool?> optional_values);
|
||||
// Same as above.
|
||||
GetOptionalFloatMap(int16 key, float value)
|
||||
=> (map<int16, float?> optional_values);
|
||||
// Same as above.
|
||||
GetOptionalEnumMap(int16 key, RegularEnum value)
|
||||
=> (map<int16, RegularEnum?> optional_values);
|
||||
|
||||
// Runs a callback with null. Helps test that JS can correctly handle null
|
||||
// structs with optional numerics.
|
||||
GetNullStructWithOptionalNumerics() => (OptionalNumericsStruct? s);
|
||||
|
@ -240,14 +240,38 @@ mojo.internal.computeUnionDimensions = function(unionSpec, nullable, value) {
|
||||
*/
|
||||
mojo.internal.computeInlineArraySize = function(arraySpec, value) {
|
||||
if (arraySpec.elementType === mojo.internal.Bool) {
|
||||
return mojo.internal.kArrayHeaderSize + ((value.length + 7) >> 3);
|
||||
return mojo.internal.kArrayHeaderSize +
|
||||
mojo.internal.computeHasValueBitfieldSize(arraySpec, value.length) +
|
||||
((value.length + 7) >> 3);
|
||||
} else {
|
||||
return mojo.internal.kArrayHeaderSize +
|
||||
mojo.internal.computeHasValueBitfieldSize(arraySpec, value.length) +
|
||||
value.length *
|
||||
arraySpec.elementType.$.arrayElementSize(!!arraySpec.elementNullable);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {!mojo.internal.ArraySpec} arraySpec
|
||||
* @param {number} length
|
||||
* @return {number} the number of bytes needed for the an array's has-value
|
||||
* bitfield. If the arraySpec does not require a has-value bitfield, this
|
||||
* method will return 0.
|
||||
*/
|
||||
mojo.internal.computeHasValueBitfieldSize = function(arraySpec, length) {
|
||||
const isNullableValueType = !!arraySpec.elementNullable &&
|
||||
!!arraySpec.elementType.$.isValueType;
|
||||
if (!isNullableValueType) {
|
||||
return 0;
|
||||
}
|
||||
const element_type_bytes =
|
||||
arraySpec.elementType.$.arrayElementSize(/* nullable= */ true);
|
||||
const element_type_bits = element_type_bytes * 8;
|
||||
const needed_bits = length + element_type_bits - 1;
|
||||
// >> 0 to force integer arithmetic.
|
||||
return ((needed_bits/element_type_bits) >> 0) * element_type_bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!mojo.internal.ArraySpec} arraySpec
|
||||
* @param {!Array|!Uint8Array} value
|
||||
@ -485,10 +509,6 @@ mojo.internal.Encoder = class {
|
||||
* @param {!Array|!Uint8Array} value
|
||||
*/
|
||||
encodeArray(arraySpec, offset, value) {
|
||||
if (arraySpec.elementNullable &&
|
||||
!!arraySpec.elementType.$.preventNullableElement) {
|
||||
throw new Error('nullable primitive elements are not supported yet');
|
||||
}
|
||||
const arraySize = mojo.internal.computeInlineArraySize(arraySpec, value);
|
||||
const arrayData = this.message_.allocate(arraySize);
|
||||
const arrayEncoder =
|
||||
@ -497,8 +517,10 @@ mojo.internal.Encoder = class {
|
||||
|
||||
arrayEncoder.encodeUint32(0, arraySize);
|
||||
arrayEncoder.encodeUint32(4, value.length);
|
||||
this.maybeEncodeHasValueBitfield(arraySpec, arrayEncoder, 8, value);
|
||||
|
||||
let byteOffset = 8;
|
||||
let byteOffset = 8 +
|
||||
mojo.internal.computeHasValueBitfieldSize(arraySpec, value.length);
|
||||
if (arraySpec.elementType === mojo.internal.Bool) {
|
||||
let bitOffset = 0;
|
||||
for (const e of value) {
|
||||
@ -518,15 +540,47 @@ mojo.internal.Encoder = class {
|
||||
'non-nullable elements');
|
||||
}
|
||||
arraySpec.elementType.$.encodeNull(arrayEncoder, byteOffset);
|
||||
} else {
|
||||
arraySpec.elementType.$.encode(
|
||||
e, arrayEncoder, byteOffset, 0, !!arraySpec.elementNullable);
|
||||
}
|
||||
arraySpec.elementType.$.encode(
|
||||
e, arrayEncoder, byteOffset, 0, !!arraySpec.elementNullable);
|
||||
byteOffset += arraySpec.elementType.$.arrayElementSize(
|
||||
!!arraySpec.elementNullable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Optionally writes a has-value bitfield to the encoder if necessary. If the
|
||||
* arraySpec does not require a has-value bitfield, this method call is
|
||||
* noop.
|
||||
* @param {!mojo.internal.ArraySpec} arraySpec
|
||||
* @param {mojo.internal.Encoder} arrayEncoder
|
||||
* @param {number} startOffset
|
||||
* @param {!Array|!Uint8Array} value
|
||||
*/
|
||||
maybeEncodeHasValueBitfield(arraySpec, arrayEncoder, startOffset, value) {
|
||||
if (!arraySpec.elementNullable ||
|
||||
!arraySpec.elementType.$.isValueType) {
|
||||
return;
|
||||
}
|
||||
|
||||
let bitOffset = 0;
|
||||
let byteOffset = startOffset;
|
||||
for (const e of value) {
|
||||
if (e === null || e === undefined) {
|
||||
arrayEncoder.encodeBool(byteOffset, bitOffset, false);
|
||||
} else {
|
||||
arrayEncoder.encodeBool(byteOffset, bitOffset, true);
|
||||
}
|
||||
bitOffset++;
|
||||
if (bitOffset == 8) {
|
||||
bitOffset = 0;
|
||||
byteOffset++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!mojo.internal.MapSpec} mapSpec
|
||||
* @param {number} offset
|
||||
@ -553,7 +607,7 @@ mojo.internal.Encoder = class {
|
||||
mapEncoder.encodeArray(
|
||||
{
|
||||
elementType: mapSpec.valueType,
|
||||
elementNullable: mapSpec.valueNullable
|
||||
elementNullable: mapSpec.valueNullable,
|
||||
},
|
||||
16, values);
|
||||
}
|
||||
@ -782,11 +836,6 @@ mojo.internal.Decoder = class {
|
||||
* @return {Array}
|
||||
*/
|
||||
decodeArray(arraySpec, offset) {
|
||||
if (arraySpec.elementNullable &&
|
||||
!!arraySpec.elementType.$.preventNullableElement) {
|
||||
throw new Error('nullable primitive elements are not supported yet');
|
||||
}
|
||||
|
||||
const arrayOffset = this.decodeOffset(offset);
|
||||
if (!arrayOffset)
|
||||
return null;
|
||||
@ -799,18 +848,49 @@ mojo.internal.Decoder = class {
|
||||
if (!numElements)
|
||||
return [];
|
||||
|
||||
// Nullable primitives use a bitfield to represent whether a value at a
|
||||
// certain index is set. This is not needed for non-primitive or
|
||||
// non-nullable types.
|
||||
const isNullableValueType = !!arraySpec.elementNullable &&
|
||||
arraySpec.elementType.$.isValueType;
|
||||
const elementHasValue = isNullableValueType ? [] : null;
|
||||
|
||||
if (isNullableValueType) {
|
||||
let bitfieldByte = 8;
|
||||
let bitfieldBit = 0;
|
||||
|
||||
for (let i = 0; i < numElements; ++i) {
|
||||
elementHasValue.push(
|
||||
arrayDecoder.decodeBool(bitfieldByte, bitfieldBit));
|
||||
bitfieldBit++;
|
||||
if (bitfieldBit === 8) {
|
||||
bitfieldBit = 0;
|
||||
bitfieldByte++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let byteOffset = 8 +
|
||||
mojo.internal.computeHasValueBitfieldSize(arraySpec, numElements);
|
||||
const result = [];
|
||||
if (arraySpec.elementType === mojo.internal.Bool) {
|
||||
for (let i = 0; i < numElements; ++i)
|
||||
result.push(arrayDecoder.decodeBool(8 + (i >> 3), i % 8));
|
||||
if (isNullableValueType && !elementHasValue[i]) {
|
||||
result.push(null);
|
||||
} else {
|
||||
result.push(arrayDecoder.decodeBool(byteOffset + (i >> 3), i % 8));
|
||||
}
|
||||
} else {
|
||||
let byteOffset = 8;
|
||||
for (let i = 0; i < numElements; ++i) {
|
||||
const element = arraySpec.elementType.$.decode(
|
||||
if (isNullableValueType && !elementHasValue[i]) {
|
||||
result.push(null);
|
||||
} else {
|
||||
const element = arraySpec.elementType.$.decode(
|
||||
arrayDecoder, byteOffset, 0, !!arraySpec.elementNullable);
|
||||
if (element === null && !arraySpec.elementNullable)
|
||||
throw new Error('Received unexpected array element');
|
||||
result.push(element);
|
||||
if (element === null && !arraySpec.elementNullable)
|
||||
throw new Error('Received unexpected array element');
|
||||
result.push(element);
|
||||
}
|
||||
byteOffset += arraySpec.elementType.$.arrayElementSize(
|
||||
!!arraySpec.elementNullable);
|
||||
}
|
||||
@ -1098,7 +1178,7 @@ mojo.internal.deserializeMessageHeader = function(data) {
|
||||
/**
|
||||
* @typedef {{
|
||||
* encode: function(*, !mojo.internal.Encoder, number, number, boolean),
|
||||
* encodeNull: ((function(!mojo.internal.Encoder, number))|undefined),
|
||||
* encodeNull: function(!mojo.internal.Encoder, number),
|
||||
* decode: function(!mojo.internal.Decoder, number, number, boolean):*,
|
||||
* computeDimensions:
|
||||
* ((function(*, boolean):!mojo.internal.MessageDimensions)|undefined),
|
||||
@ -1108,11 +1188,8 @@ mojo.internal.deserializeMessageHeader = function(data) {
|
||||
* arraySpec: (!mojo.internal.ArraySpec|undefined),
|
||||
* mapSpec: (!mojo.internal.MapSpec|undefined),
|
||||
* structSpec: (!mojo.internal.StructSpec|undefined),
|
||||
* preventNullableElement: (boolean|undefined)
|
||||
* isValueType: boolean
|
||||
* }}
|
||||
* TODO(ffred): preventNullableElement is used to prevent arrays of nullables
|
||||
* from being used until support is fully implemented. Remove once support is
|
||||
* fully added.
|
||||
*/
|
||||
mojo.internal.MojomTypeInfo;
|
||||
|
||||
@ -1213,11 +1290,17 @@ mojo.internal.Bool = {
|
||||
encode: function(value, encoder, byteOffset, bitOffset, nullable) {
|
||||
encoder.encodeBool(byteOffset, bitOffset, value);
|
||||
},
|
||||
encodeNull: function(encoder, byteOffset) {
|
||||
throw new Error('encoding bool null from type is not implemented');
|
||||
},
|
||||
decode: function(decoder, byteOffset, bitOffset, nullable) {
|
||||
return decoder.decodeBool(byteOffset, bitOffset);
|
||||
},
|
||||
// Bool has specialized serialize/deserialize logic to bit pack. However,
|
||||
// memory allocation is still a single byte.
|
||||
arrayElementSize: nullable => 1,
|
||||
isValidObjectKeyType: true,
|
||||
preventNullableElement: true,
|
||||
isValueType: true,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1230,12 +1313,15 @@ mojo.internal.Int8 = {
|
||||
encode: function(value, encoder, byteOffset, bitOffset, nullable) {
|
||||
encoder.encodeInt8(byteOffset, value);
|
||||
},
|
||||
encodeNull: function(encoder, byteOffset) {
|
||||
encoder.encodeInt8(byteOffset, 0);
|
||||
},
|
||||
decode: function(decoder, byteOffset, bitOffset, nullable) {
|
||||
return decoder.decodeInt8(byteOffset);
|
||||
},
|
||||
arrayElementSize: nullable => 1,
|
||||
isValidObjectKeyType: true,
|
||||
preventNullableElement: true,
|
||||
isValueType: true,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1248,12 +1334,15 @@ mojo.internal.Uint8 = {
|
||||
encode: function(value, encoder, byteOffset, bitOffset, nullable) {
|
||||
encoder.encodeUint8(byteOffset, value);
|
||||
},
|
||||
encodeNull: function(encoder, byteOffset) {
|
||||
encoder.encodeUint8(byteOffset, 0);
|
||||
},
|
||||
decode: function(decoder, byteOffset, bitOffset, nullable) {
|
||||
return decoder.decodeUint8(byteOffset);
|
||||
},
|
||||
arrayElementSize: nullable => 1,
|
||||
isValidObjectKeyType: true,
|
||||
preventNullableElement: true,
|
||||
isValueType: true,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1266,12 +1355,15 @@ mojo.internal.Int16 = {
|
||||
encode: function(value, encoder, byteOffset, bitOffset, nullable) {
|
||||
encoder.encodeInt16(byteOffset, value);
|
||||
},
|
||||
encodeNull: function(encoder, byteOffset) {
|
||||
encoder.encodeInt16(byteOffset, 0);
|
||||
},
|
||||
decode: function(decoder, byteOffset, bitOffset, nullable) {
|
||||
return decoder.decodeInt16(byteOffset);
|
||||
},
|
||||
arrayElementSize: nullable => 2,
|
||||
isValidObjectKeyType: true,
|
||||
preventNullableElement: true,
|
||||
isValueType: true,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1284,12 +1376,15 @@ mojo.internal.Uint16 = {
|
||||
encode: function(value, encoder, byteOffset, bitOffset, nullable) {
|
||||
encoder.encodeUint16(byteOffset, value);
|
||||
},
|
||||
encodeNull: function(encoder, byteOffset) {
|
||||
encoder.encodeUint16(byteOffset, 0);
|
||||
},
|
||||
decode: function(decoder, byteOffset, bitOffset, nullable) {
|
||||
return decoder.decodeUint16(byteOffset);
|
||||
},
|
||||
arrayElementSize: nullable => 2,
|
||||
isValidObjectKeyType: true,
|
||||
preventNullableElement: true,
|
||||
isValueType: true,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1302,12 +1397,15 @@ mojo.internal.Int32 = {
|
||||
encode: function(value, encoder, byteOffset, bitOffset, nullable) {
|
||||
encoder.encodeInt32(byteOffset, value);
|
||||
},
|
||||
encodeNull: function(encoder, byteOffset) {
|
||||
encoder.encodeInt32(byteOffset, 0);
|
||||
},
|
||||
decode: function(decoder, byteOffset, bitOffset, nullable) {
|
||||
return decoder.decodeInt32(byteOffset);
|
||||
},
|
||||
arrayElementSize: nullable => 4,
|
||||
isValidObjectKeyType: true,
|
||||
preventNullableElement: true,
|
||||
isValueType: true,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1320,12 +1418,15 @@ mojo.internal.Uint32 = {
|
||||
encode: function(value, encoder, byteOffset, bitOffset, nullable) {
|
||||
encoder.encodeUint32(byteOffset, value);
|
||||
},
|
||||
encodeNull: function(encoder, byteOffset) {
|
||||
encoder.encodeUint32(byteOffset, 0);
|
||||
},
|
||||
decode: function(decoder, byteOffset, bitOffset, nullable) {
|
||||
return decoder.decodeUint32(byteOffset);
|
||||
},
|
||||
arrayElementSize: nullable => 4,
|
||||
isValidObjectKeyType: true,
|
||||
preventNullableElement: true,
|
||||
isValueType: true,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1338,13 +1439,16 @@ mojo.internal.Int64 = {
|
||||
encode: function(value, encoder, byteOffset, bitOffset, nullable) {
|
||||
encoder.encodeInt64(byteOffset, value);
|
||||
},
|
||||
encodeNull: function(encoder, byteOffset) {
|
||||
encoder.encodeInt64(byteOffset, 0);
|
||||
},
|
||||
decode: function(decoder, byteOffset, bitOffset, nullable) {
|
||||
return decoder.decodeInt64(byteOffset);
|
||||
},
|
||||
arrayElementSize: nullable => 8,
|
||||
// TS Compiler does not allow Object maps to have bigint keys.
|
||||
isValidObjectKeyType: false,
|
||||
preventNullableElement: true,
|
||||
isValueType: true,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1357,13 +1461,16 @@ mojo.internal.Uint64 = {
|
||||
encode: function(value, encoder, byteOffset, bitOffset, nullable) {
|
||||
encoder.encodeUint64(byteOffset, value);
|
||||
},
|
||||
encodeNull: function(encoder, byteOffset) {
|
||||
encoder.encodeUint64(byteOffset, 0);
|
||||
},
|
||||
decode: function(decoder, byteOffset, bitOffset, nullable) {
|
||||
return decoder.decodeUint64(byteOffset);
|
||||
},
|
||||
arrayElementSize: nullable => 8,
|
||||
// TS Compiler does not allow Object maps to have bigint keys.
|
||||
isValidObjectKeyType: false,
|
||||
preventNullableElement: true,
|
||||
isValueType: true,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1376,12 +1483,15 @@ mojo.internal.Float = {
|
||||
encode: function(value, encoder, byteOffset, bitOffset, nullable) {
|
||||
encoder.encodeFloat(byteOffset, value);
|
||||
},
|
||||
encodeNull: function(encoder, byteOffset) {
|
||||
encoder.encodeFloat(byteOffset, 0);
|
||||
},
|
||||
decode: function(decoder, byteOffset, bitOffset, nullable) {
|
||||
return decoder.decodeFloat(byteOffset);
|
||||
},
|
||||
arrayElementSize: nullable => 4,
|
||||
isValidObjectKeyType: true,
|
||||
preventNullableElement: true,
|
||||
isValueType: true,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1394,12 +1504,15 @@ mojo.internal.Double = {
|
||||
encode: function(value, encoder, byteOffset, bitOffset, nullable) {
|
||||
encoder.encodeDouble(byteOffset, value);
|
||||
},
|
||||
encodeNull: function(encoder, byteOffset) {
|
||||
encoder.encodeDouble(byteOffset, 0);
|
||||
},
|
||||
decode: function(decoder, byteOffset, bitOffset, nullable) {
|
||||
return decoder.decodeDouble(byteOffset);
|
||||
},
|
||||
arrayElementSize: nullable => 8,
|
||||
isValidObjectKeyType: true,
|
||||
preventNullableElement: true,
|
||||
isValueType: true,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1420,6 +1533,7 @@ mojo.internal.Handle = {
|
||||
},
|
||||
arrayElementSize: nullable => 4,
|
||||
isValidObjectKeyType: false,
|
||||
isValueType: false,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1444,6 +1558,7 @@ mojo.internal.String = {
|
||||
},
|
||||
arrayElementSize: nullable => 8,
|
||||
isValidObjectKeyType: true,
|
||||
isValueType: false,
|
||||
}
|
||||
};
|
||||
|
||||
@ -1474,6 +1589,7 @@ mojo.internal.Array = function(elementType, elementNullable) {
|
||||
},
|
||||
arrayElementSize: nullable => 8,
|
||||
isValidObjectKeyType: false,
|
||||
isValueType: false,
|
||||
},
|
||||
};
|
||||
};
|
||||
@ -1526,6 +1642,7 @@ mojo.internal.Map = function(keyType, valueType, valueNullable) {
|
||||
},
|
||||
arrayElementSize: nullable => 8,
|
||||
isValidObjectKeyType: false,
|
||||
isValueType: false,
|
||||
},
|
||||
};
|
||||
};
|
||||
@ -1541,6 +1658,7 @@ mojo.internal.Enum = function() {
|
||||
// TODO: Do some sender-side error checking on the input value.
|
||||
encoder.encodeUint32(byteOffset, value);
|
||||
},
|
||||
encodeNull: function(encoder, byteOffset) {},
|
||||
decode: function(decoder, byteOffset, bitOffset, nullable) {
|
||||
const value = decoder.decodeInt32(byteOffset);
|
||||
// TODO: validate
|
||||
@ -1548,7 +1666,7 @@ mojo.internal.Enum = function() {
|
||||
},
|
||||
arrayElementSize: nullable => 4,
|
||||
isValidObjectKeyType: true,
|
||||
preventNullableElement: true,
|
||||
isValueType: true,
|
||||
},
|
||||
};
|
||||
};
|
||||
@ -1678,6 +1796,7 @@ mojo.internal.InterfaceProxy = function(type) {
|
||||
},
|
||||
arrayElementSize: nullable => 8,
|
||||
isValidObjectKeyType: false,
|
||||
isValueType: false,
|
||||
},
|
||||
};
|
||||
};
|
||||
@ -1703,6 +1822,7 @@ mojo.internal.InterfaceRequest = function(type) {
|
||||
},
|
||||
arrayElementSize: nullable => 8,
|
||||
isValidObjectKeyType: false,
|
||||
isValueType: false,
|
||||
},
|
||||
};
|
||||
};
|
||||
@ -1734,6 +1854,7 @@ mojo.internal.AssociatedInterfaceProxy = function(type) {
|
||||
},
|
||||
isValidObjectKeyType: false,
|
||||
hasInterfaceId: true,
|
||||
isValueType: false,
|
||||
},
|
||||
};
|
||||
};
|
||||
@ -1764,7 +1885,7 @@ mojo.internal.AssociatedInterfaceRequest = function(type) {
|
||||
},
|
||||
isValidObjectKeyType: false,
|
||||
hasInterfaceId: true,
|
||||
isValueType: false,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -26,6 +26,16 @@ class ParamsJsImpl {
|
||||
'sendNullFloat',
|
||||
'sendNullDouble',
|
||||
'sendNullEnum',
|
||||
|
||||
'sendNullBools',
|
||||
'sendNullInt16s',
|
||||
'sendNullUint32s',
|
||||
'sendNullDoubles',
|
||||
'sendNullEnums',
|
||||
|
||||
'sendNullBoolMap',
|
||||
'sendNullDoubleMap',
|
||||
'sendNullEnumMap',
|
||||
];
|
||||
for (const method of sendNullMethods) {
|
||||
this[method] = this.sendNull;
|
||||
@ -44,6 +54,16 @@ class ParamsJsImpl {
|
||||
'sendOptionalFloat',
|
||||
'sendOptionalDouble',
|
||||
'sendOptionalEnum',
|
||||
|
||||
'sendOptionalBools',
|
||||
'sendOptionalInt16s',
|
||||
'sendOptionalUint32s',
|
||||
'sendOptionalDoubles',
|
||||
'sendOptionalEnums',
|
||||
|
||||
'sendOptionalBoolMap',
|
||||
'sendOptionalDoubleMap',
|
||||
'sendOptionalEnumMap',
|
||||
];
|
||||
for (const method of sendOptionalMethods) {
|
||||
this[method] = this.sendOptional;
|
||||
@ -159,6 +179,20 @@ for (const {method, numericalType} of testNullMethods) {
|
||||
}, `JS decoding of null ${numericalType} param.`);
|
||||
}
|
||||
|
||||
promise_test(async () => {
|
||||
assert_empty_response(await cpp.sendNullBools([null, null]));
|
||||
assert_empty_response(await cpp.sendNullInt16s([null, null]));
|
||||
assert_empty_response(await cpp.sendNullUint32s([null, null]));
|
||||
assert_empty_response(await cpp.sendNullDoubles([null, null]));
|
||||
assert_empty_response(await cpp.sendNullEnums([null, null]));
|
||||
});
|
||||
|
||||
promise_test(async () => {
|
||||
assert_empty_response(await cpp.sendNullBoolMap({0: null}));
|
||||
assert_empty_response(await cpp.sendNullDoubleMap({1: null}));
|
||||
assert_empty_response(await cpp.sendNullEnumMap({2: null}));
|
||||
});
|
||||
|
||||
promise_test(async () => {
|
||||
assert_empty_response(await cpp.sendNullStructWithOptionalNumerics(null));
|
||||
}, `JS encoding and C++ decoding of null struct with optional numerics.`);
|
||||
@ -225,10 +259,56 @@ for (const {method, valueToUse, numericalType} of testMethods) {
|
||||
promise_test(async () => {
|
||||
assert_value_equals(await cpp[method](valueToUse), valueToUse);
|
||||
}, `JS encoding and C++ decoding of optional ${numericalType}.`);
|
||||
}
|
||||
|
||||
promise_test(async () => {
|
||||
assert_value_equals(await cpp[method](valueToUse), valueToUse);
|
||||
}, `JS decoding of optional ${numericalType} params.`);
|
||||
const testArrayMethods = [{
|
||||
method: 'sendOptionalBools',
|
||||
valuesToUse: [true, null, false, true],
|
||||
expected: [true, false, true],
|
||||
}, {
|
||||
method: 'sendOptionalInt16s',
|
||||
valuesToUse: [3, null, 2, 1],
|
||||
expected: [3, 2, 1],
|
||||
}, {
|
||||
method: 'sendOptionalUint32s',
|
||||
valuesToUse: [null, 1],
|
||||
expected: [1],
|
||||
}, {
|
||||
method: 'sendOptionalDoubles',
|
||||
valuesToUse: [6.66, 9.99],
|
||||
expected: [6.66, 9.99],
|
||||
}, {
|
||||
method: 'sendOptionalEnums',
|
||||
valuesToUse: [null, OptionalNumericsRegularEnum.kBar, null, null],
|
||||
expected: [OptionalNumericsRegularEnum.kBar],
|
||||
}];
|
||||
|
||||
for (const {method, valuesToUse, expected} of testArrayMethods) {
|
||||
promise_test(async() => {
|
||||
const response = await cpp[method](valuesToUse);
|
||||
assert_array_equals(response.values, expected, `JS encoding and C++ decoding of: ${method}`);
|
||||
});
|
||||
}
|
||||
|
||||
const testMapMethods = [{
|
||||
method: 'sendOptionalBoolMap',
|
||||
valuesToUse: {0: true, 1: null, 2:false},
|
||||
expected: {0: true, 2: false},
|
||||
}, {
|
||||
method: 'sendOptionalDoubleMap',
|
||||
valuesToUse: {3: 3.33, 4: null},
|
||||
expected: {3: 3.33},
|
||||
}, {
|
||||
method: 'sendOptionalEnumMap',
|
||||
valuesToUse: {5: null, 6: OptionalNumericsRegularEnum.kBar},
|
||||
expected: {6: OptionalNumericsRegularEnum.kBar},
|
||||
}];
|
||||
|
||||
for (const {method, valuesToUse, expected} of testMapMethods) {
|
||||
promise_test(async() => {
|
||||
const response = await cpp[method](valuesToUse);
|
||||
assert_object_equals(response.values, expected, `JS encoding and C++ decoding of: ${method}`);
|
||||
});
|
||||
}
|
||||
|
||||
const structFields = [
|
||||
|
@ -27,6 +27,16 @@ class ResponseParamsJsImpl {
|
||||
'getNullFloat',
|
||||
'getNullDouble',
|
||||
'getNullEnum',
|
||||
|
||||
'getNullBools',
|
||||
'getNullInt16s',
|
||||
'getNullUint32s',
|
||||
'getNullDoubles',
|
||||
'getNullEnums',
|
||||
|
||||
'getNullBoolMap',
|
||||
'getNullInt32Map',
|
||||
'getNullEnumMap',
|
||||
];
|
||||
for (const method of nullMethods) {
|
||||
this[method] = this.getNullOptional;
|
||||
@ -45,6 +55,16 @@ class ResponseParamsJsImpl {
|
||||
'getOptionalFloat',
|
||||
'getOptionalDouble',
|
||||
'getOptionalEnum',
|
||||
|
||||
'getOptionalBools',
|
||||
'getOptionalInt16s',
|
||||
'getOptionalUint32s',
|
||||
'getOptionalDoubles',
|
||||
'getOptionalEnums',
|
||||
|
||||
'getOptionalBoolMap',
|
||||
'getOptionalFloatMap',
|
||||
'getOptionalEnumMap',
|
||||
];
|
||||
for (const method of methods) {
|
||||
this[method] = this.getOptional;
|
||||
@ -279,6 +299,35 @@ promise_test(async () => {
|
||||
}
|
||||
}, 'JS decoding of null struct with optional numerics.');
|
||||
|
||||
|
||||
const testGetArraysOfNullsMethods = [
|
||||
'getNullBools',
|
||||
'getNullInt16s',
|
||||
'getNullUint32s',
|
||||
'getNullDoubles',
|
||||
'getNullEnums',
|
||||
];
|
||||
|
||||
for (const method of testGetArraysOfNullsMethods) {
|
||||
promise_test(async() => {
|
||||
const response = await cpp[method]();
|
||||
assert_array_equals(response.optionalValues, [null]);
|
||||
});
|
||||
}
|
||||
|
||||
const testGetMapOfNullsMethods = [
|
||||
'getNullBoolMap',
|
||||
'getNullInt32Map',
|
||||
'getNullEnumMap',
|
||||
];
|
||||
|
||||
for (const method of testGetMapOfNullsMethods) {
|
||||
promise_test(async() => {
|
||||
const response = await cpp[method]();
|
||||
assert_object_equals(response.optionalValues, {0: null});
|
||||
});
|
||||
}
|
||||
|
||||
const testMethods = [{
|
||||
method: 'getOptionalBool',
|
||||
valueToUse: true,
|
||||
@ -459,3 +508,52 @@ promise_test(async () => {
|
||||
assert_equals(s[field.name], field.value, field.name);
|
||||
}
|
||||
}, 'JS encoding of struct with optional numerics in response params.');
|
||||
|
||||
const testNullWrapping = [{
|
||||
name: 'getOptionalBools',
|
||||
value: true,
|
||||
}, {
|
||||
name: 'getOptionalInt16s',
|
||||
value: 16,
|
||||
}, {
|
||||
name: 'getOptionalUint32s',
|
||||
value: 32,
|
||||
}, {
|
||||
name: 'getOptionalDoubles',
|
||||
value: 22.2,
|
||||
}, {
|
||||
name: 'getOptionalEnums',
|
||||
value: OptionalNumericsRegularEnum.kFoo,
|
||||
}];
|
||||
|
||||
for (const {name, value} of testNullWrapping) {
|
||||
promise_test(async() => {
|
||||
const response = await cpp[name](value);
|
||||
assert_array_equals(response.optionalValues, [null, value, null]);
|
||||
});
|
||||
}
|
||||
|
||||
const testNullWrappingForMap = [{
|
||||
name: 'getOptionalBoolMap',
|
||||
key: 6,
|
||||
value: false,
|
||||
}, {
|
||||
name: 'getOptionalFloatMap',
|
||||
key: 7,
|
||||
value: 1.25,
|
||||
}, {
|
||||
name: 'getOptionalEnumMap',
|
||||
key: 8,
|
||||
value: OptionalNumericsRegularEnum.kFoo,
|
||||
}];
|
||||
|
||||
for (const {name, key, value} of testNullWrappingForMap) {
|
||||
promise_test(async() => {
|
||||
const response = await cpp[name](key, value);
|
||||
assert_object_equals(response.optionalValues, {
|
||||
[key - 1]: null,
|
||||
[key]: value,
|
||||
[key + 1]: null,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
Reference in New Issue
Block a user