dawn_wire: Move BufferConsumer to it's own file. Unify WIRE_TRY

Bug: dawn:680
Change-Id: I6d57280ab11381649deef51ee7babf5ca73f359b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/42340
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Stephen White <senorblanco@chromium.org>
This commit is contained in:
Austin Eng 2021-02-25 20:21:25 +00:00 committed by Commit Bot service account
parent 12827fb805
commit bd3f58612f
13 changed files with 311 additions and 227 deletions

View File

@ -16,6 +16,7 @@
#include "common/Assert.h" #include "common/Assert.h"
#include "common/Log.h" #include "common/Log.h"
#include "dawn_wire/BufferConsumer_impl.h"
#include "dawn_wire/Wire.h" #include "dawn_wire/Wire.h"
#include <algorithm> #include <algorithm>
@ -60,9 +61,9 @@
{% elif member.type.category == "structure"%} {% elif member.type.category == "structure"%}
{%- set Provider = ", provider" if member.type.may_have_dawn_object else "" -%} {%- set Provider = ", provider" if member.type.may_have_dawn_object else "" -%}
{% if member.annotation == "const*const*" %} {% if member.annotation == "const*const*" %}
{{as_cType(member.type.name)}}Serialize(*{{in}}, &{{out}}, buffer{{Provider}}); WIRE_TRY({{as_cType(member.type.name)}}Serialize(*{{in}}, &{{out}}, buffer{{Provider}}));
{% else %} {% else %}
{{as_cType(member.type.name)}}Serialize({{in}}, &{{out}}, buffer{{Provider}}); WIRE_TRY({{as_cType(member.type.name)}}Serialize({{in}}, &{{out}}, buffer{{Provider}}));
{% endif %} {% endif %}
{%- else -%} {%- else -%}
{{out}} = {{in}}; {{out}} = {{in}};
@ -73,9 +74,9 @@
{% macro deserialize_member(member, in, out) %} {% macro deserialize_member(member, in, out) %}
{%- if member.type.category == "object" -%} {%- if member.type.category == "object" -%}
{%- set Optional = "Optional" if member.optional else "" -%} {%- set Optional = "Optional" if member.optional else "" -%}
DESERIALIZE_TRY(resolver.Get{{Optional}}FromId({{in}}, &{{out}})); WIRE_TRY(resolver.Get{{Optional}}FromId({{in}}, &{{out}}));
{%- elif member.type.category == "structure" -%} {%- elif member.type.category == "structure" -%}
DESERIALIZE_TRY({{as_cType(member.type.name)}}Deserialize(&{{out}}, &{{in}}, deserializeBuffer, allocator WIRE_TRY({{as_cType(member.type.name)}}Deserialize(&{{out}}, &{{in}}, deserializeBuffer, allocator
{%- if member.type.may_have_dawn_object -%} {%- if member.type.may_have_dawn_object -%}
, resolver , resolver
{%- endif -%} {%- endif -%}
@ -203,7 +204,7 @@ namespace {
//* Serializes `record` into `transfer`, using `buffer` to get more space for pointed-to data //* Serializes `record` into `transfer`, using `buffer` to get more space for pointed-to data
//* and `provider` to serialize objects. //* and `provider` to serialize objects.
DAWN_DECLARE_UNUSED bool {{Return}}{{name}}Serialize(const {{Return}}{{name}}{{Cmd}}& record, {{Return}}{{name}}Transfer* transfer, DAWN_DECLARE_UNUSED WireResult {{Return}}{{name}}Serialize(const {{Return}}{{name}}{{Cmd}}& record, {{Return}}{{name}}Transfer* transfer,
SerializeBuffer* buffer SerializeBuffer* buffer
{%- if record.may_have_dawn_object -%} {%- if record.may_have_dawn_object -%}
, const ObjectIdProvider& provider , const ObjectIdProvider& provider
@ -225,7 +226,7 @@ namespace {
{% if record.extensible %} {% if record.extensible %}
if (record.nextInChain != nullptr) { if (record.nextInChain != nullptr) {
transfer->hasNextInChain = true; transfer->hasNextInChain = true;
SERIALIZE_TRY(SerializeChainedStruct(record.nextInChain, buffer, provider)); WIRE_TRY(SerializeChainedStruct(record.nextInChain, buffer, provider));
} else { } else {
transfer->hasNextInChain = false; transfer->hasNextInChain = false;
} }
@ -250,7 +251,7 @@ namespace {
transfer->{{memberName}}Strlen = std::strlen(record.{{memberName}}); transfer->{{memberName}}Strlen = std::strlen(record.{{memberName}});
char* stringInBuffer; char* stringInBuffer;
SERIALIZE_TRY(buffer->NextN(transfer->{{memberName}}Strlen, &stringInBuffer)); WIRE_TRY(buffer->NextN(transfer->{{memberName}}Strlen, &stringInBuffer));
memcpy(stringInBuffer, record.{{memberName}}, transfer->{{memberName}}Strlen); memcpy(stringInBuffer, record.{{memberName}}, transfer->{{memberName}}Strlen);
} }
{% endfor %} {% endfor %}
@ -268,7 +269,7 @@ namespace {
auto memberLength = {{member_length(member, "record.")}}; auto memberLength = {{member_length(member, "record.")}};
{{member_transfer_type(member)}}* memberBuffer; {{member_transfer_type(member)}}* memberBuffer;
SERIALIZE_TRY(buffer->NextN(memberLength, &memberBuffer)); WIRE_TRY(buffer->NextN(memberLength, &memberBuffer));
//* This loop cannot overflow because it iterates up to |memberLength|. Even if //* This loop cannot overflow because it iterates up to |memberLength|. Even if
//* memberLength were the maximum integer value, |i| would become equal to it just before //* memberLength were the maximum integer value, |i| would become equal to it just before
@ -278,14 +279,14 @@ namespace {
} }
} }
{% endfor %} {% endfor %}
return true; return WireResult::Success;
} }
DAWN_UNUSED_FUNC({{Return}}{{name}}Serialize); DAWN_UNUSED_FUNC({{Return}}{{name}}Serialize);
//* Deserializes `transfer` into `record` getting more serialized data from `buffer` and `size` //* Deserializes `transfer` into `record` getting more serialized data from `buffer` and `size`
//* if needed, using `allocator` to store pointed-to values and `resolver` to translate object //* if needed, using `allocator` to store pointed-to values and `resolver` to translate object
//* Ids to actual objects. //* Ids to actual objects.
DAWN_DECLARE_UNUSED DeserializeResult {{Return}}{{name}}Deserialize({{Return}}{{name}}{{Cmd}}* record, const volatile {{Return}}{{name}}Transfer* transfer, DAWN_DECLARE_UNUSED WireResult {{Return}}{{name}}Deserialize({{Return}}{{name}}{{Cmd}}* record, const volatile {{Return}}{{name}}Transfer* transfer,
DeserializeBuffer* deserializeBuffer, DeserializeAllocator* allocator DeserializeBuffer* deserializeBuffer, DeserializeAllocator* allocator
{%- if record.may_have_dawn_object -%} {%- if record.may_have_dawn_object -%}
, const ObjectIdResolver& resolver , const ObjectIdResolver& resolver
@ -310,7 +311,7 @@ namespace {
{% if record.extensible %} {% if record.extensible %}
record->nextInChain = nullptr; record->nextInChain = nullptr;
if (transfer->hasNextInChain) { if (transfer->hasNextInChain) {
DESERIALIZE_TRY(DeserializeChainedStruct(&record->nextInChain, deserializeBuffer, allocator, resolver)); WIRE_TRY(DeserializeChainedStruct(&record->nextInChain, deserializeBuffer, allocator, resolver));
} }
{% endif %} {% endif %}
@ -336,15 +337,15 @@ namespace {
if (stringLength64 >= std::numeric_limits<size_t>::max()) { if (stringLength64 >= std::numeric_limits<size_t>::max()) {
//* Cannot allocate space for the string. It can be at most //* Cannot allocate space for the string. It can be at most
//* size_t::max() - 1. We need 1 byte for the null-terminator. //* size_t::max() - 1. We need 1 byte for the null-terminator.
return DeserializeResult::FatalError; return WireResult::FatalError;
} }
size_t stringLength = static_cast<size_t>(stringLength64); size_t stringLength = static_cast<size_t>(stringLength64);
const volatile char* stringInBuffer; const volatile char* stringInBuffer;
DESERIALIZE_TRY(deserializeBuffer->ReadN(stringLength, &stringInBuffer)); WIRE_TRY(deserializeBuffer->ReadN(stringLength, &stringInBuffer));
char* copiedString; char* copiedString;
DESERIALIZE_TRY(GetSpace(allocator, stringLength + 1, &copiedString)); WIRE_TRY(GetSpace(allocator, stringLength + 1, &copiedString));
//* We can cast away the volatile qualifier because DeserializeBuffer::ReadN already //* We can cast away the volatile qualifier because DeserializeBuffer::ReadN already
//* validated that the range [stringInBuffer, stringInBuffer + stringLength) is valid. //* validated that the range [stringInBuffer, stringInBuffer + stringLength) is valid.
//* memcpy may have an unknown access pattern, but this is fine since the string is only //* memcpy may have an unknown access pattern, but this is fine since the string is only
@ -367,13 +368,14 @@ namespace {
{ {
auto memberLength = {{member_length(member, "record->")}}; auto memberLength = {{member_length(member, "record->")}};
const volatile {{member_transfer_type(member)}}* memberBuffer; const volatile {{member_transfer_type(member)}}* memberBuffer;
DESERIALIZE_TRY(deserializeBuffer->ReadN(memberLength, &memberBuffer)); WIRE_TRY(deserializeBuffer->ReadN(memberLength, &memberBuffer));
{{as_cType(member.type.name)}}* copiedMembers; {{as_cType(member.type.name)}}* copiedMembers;
DESERIALIZE_TRY(GetSpace(allocator, memberLength, &copiedMembers)); WIRE_TRY(GetSpace(allocator, memberLength, &copiedMembers));
{% if member.annotation == "const*const*" %} {% if member.annotation == "const*const*" %}
{{as_cType(member.type.name)}}** pointerArray; {{as_cType(member.type.name)}}** pointerArray;
DESERIALIZE_TRY(GetSpace(allocator, memberLength, &pointerArray)); WIRE_TRY(GetSpace(allocator, memberLength, &pointerArray));
//* This loop cannot overflow because it iterates up to |memberLength|. Even if //* This loop cannot overflow because it iterates up to |memberLength|. Even if
//* memberLength were the maximum integer value, |i| would become equal to it just before //* memberLength were the maximum integer value, |i| would become equal to it just before
//* exiting the loop, but not increment past or wrap around. //* exiting the loop, but not increment past or wrap around.
@ -394,7 +396,7 @@ namespace {
} }
{% endfor %} {% endfor %}
return DeserializeResult::Success; return WireResult::Success;
} }
DAWN_UNUSED_FUNC({{Return}}{{name}}Deserialize); DAWN_UNUSED_FUNC({{Return}}{{name}}Deserialize);
{% endmacro %} {% endmacro %}
@ -409,30 +411,30 @@ namespace {
return size; return size;
} }
bool {{Cmd}}::Serialize(size_t commandSize, SerializeBuffer* buffer WireResult {{Cmd}}::Serialize(size_t commandSize, SerializeBuffer* buffer
{%- if not is_return -%} {%- if not is_return -%}
, const ObjectIdProvider& objectIdProvider , const ObjectIdProvider& objectIdProvider
{%- endif -%} {%- endif -%}
) const { ) const {
{{Name}}Transfer* transfer; {{Name}}Transfer* transfer;
SERIALIZE_TRY(buffer->Next(&transfer)); WIRE_TRY(buffer->Next(&transfer));
transfer->commandSize = commandSize; transfer->commandSize = commandSize;
SERIALIZE_TRY({{Name}}Serialize(*this, transfer, buffer WIRE_TRY({{Name}}Serialize(*this, transfer, buffer
{%- if command.may_have_dawn_object -%} {%- if command.may_have_dawn_object -%}
, objectIdProvider , objectIdProvider
{%- endif -%} {%- endif -%}
)); ));
return true; return WireResult::Success;
} }
DeserializeResult {{Cmd}}::Deserialize(DeserializeBuffer* deserializeBuffer, DeserializeAllocator* allocator WireResult {{Cmd}}::Deserialize(DeserializeBuffer* deserializeBuffer, DeserializeAllocator* allocator
{%- if command.may_have_dawn_object -%} {%- if command.may_have_dawn_object -%}
, const ObjectIdResolver& resolver , const ObjectIdResolver& resolver
{%- endif -%} {%- endif -%}
) { ) {
const volatile {{Name}}Transfer* transfer; const volatile {{Name}}Transfer* transfer;
DESERIALIZE_TRY(deserializeBuffer->Read(&transfer)); WIRE_TRY(deserializeBuffer->Read(&transfer));
return {{Name}}Deserialize(this, transfer, deserializeBuffer, allocator return {{Name}}Deserialize(this, transfer, deserializeBuffer, allocator
{%- if command.may_have_dawn_object -%} {%- if command.may_have_dawn_object -%}
@ -444,22 +446,6 @@ namespace {
namespace dawn_wire { namespace dawn_wire {
// Macro to simplify error handling, similar to DAWN_TRY but for DeserializeResult.
#define DESERIALIZE_TRY(EXPR) \
do { \
DeserializeResult exprResult = EXPR; \
if (exprResult != DeserializeResult::Success) { \
return exprResult; \
} \
} while (0)
#define SERIALIZE_TRY(EXPR) \
do { \
if (!(EXPR)) { \
return false; \
} \
} while (0)
ObjectHandle::ObjectHandle() = default; ObjectHandle::ObjectHandle() = default;
ObjectHandle::ObjectHandle(ObjectId id, ObjectGeneration generation) ObjectHandle::ObjectHandle(ObjectId id, ObjectGeneration generation)
: id(id), generation(generation) { : id(id), generation(generation) {
@ -485,77 +471,31 @@ namespace dawn_wire {
return *this; return *this;
} }
template <typename BufferT>
template <typename T>
bool BufferConsumer<BufferT>::Peek(T** data) {
if (sizeof(T) > mSize) {
return false;
}
*data = reinterpret_cast<T*>(mBuffer);
return true;
}
template <typename BufferT>
template <typename T>
bool BufferConsumer<BufferT>::Next(T** data) {
if (sizeof(T) > mSize) {
return false;
}
*data = reinterpret_cast<T*>(mBuffer);
mBuffer += sizeof(T);
mSize -= sizeof(T);
return true;
}
template <typename BufferT>
template <typename T, typename N>
bool BufferConsumer<BufferT>::NextN(N count, T** data) {
static_assert(std::is_unsigned<N>::value, "|count| argument of NextN must be unsigned.");
constexpr size_t kMaxCountWithoutOverflows = std::numeric_limits<size_t>::max() / sizeof(T);
if (count > kMaxCountWithoutOverflows) {
return false;
}
// Cannot overflow because |count| is not greater than |kMaxCountWithoutOverflows|.
size_t totalSize = sizeof(T) * count;
if (totalSize > mSize) {
return false;
}
*data = reinterpret_cast<T*>(mBuffer);
mBuffer += totalSize;
mSize -= totalSize;
return true;
}
namespace { namespace {
// Allocates enough space from allocator to countain T[count] and return it in out. // Allocates enough space from allocator to countain T[count] and return it in out.
// Return FatalError if the allocator couldn't allocate the memory. // Return FatalError if the allocator couldn't allocate the memory.
// Always writes to |out| on success. // Always writes to |out| on success.
template <typename T, typename N> template <typename T, typename N>
DeserializeResult GetSpace(DeserializeAllocator* allocator, N count, T** out) { WireResult GetSpace(DeserializeAllocator* allocator, N count, T** out) {
constexpr size_t kMaxCountWithoutOverflows = std::numeric_limits<size_t>::max() / sizeof(T); constexpr size_t kMaxCountWithoutOverflows = std::numeric_limits<size_t>::max() / sizeof(T);
if (count > kMaxCountWithoutOverflows) { if (count > kMaxCountWithoutOverflows) {
return DeserializeResult::FatalError; return WireResult::FatalError;
} }
size_t totalSize = sizeof(T) * count; size_t totalSize = sizeof(T) * count;
*out = static_cast<T*>(allocator->GetSpace(totalSize)); *out = static_cast<T*>(allocator->GetSpace(totalSize));
if (*out == nullptr) { if (*out == nullptr) {
return DeserializeResult::FatalError; return WireResult::FatalError;
} }
return DeserializeResult::Success; return WireResult::Success;
} }
size_t GetChainedStructExtraRequiredSize(const WGPUChainedStruct* chainedStruct); size_t GetChainedStructExtraRequiredSize(const WGPUChainedStruct* chainedStruct);
DAWN_NO_DISCARD bool SerializeChainedStruct(WGPUChainedStruct const* chainedStruct, DAWN_NO_DISCARD WireResult SerializeChainedStruct(WGPUChainedStruct const* chainedStruct,
SerializeBuffer* buffer, SerializeBuffer* buffer,
const ObjectIdProvider& provider); const ObjectIdProvider& provider);
DeserializeResult DeserializeChainedStruct(const WGPUChainedStruct** outChainNext, WireResult DeserializeChainedStruct(const WGPUChainedStruct** outChainNext,
DeserializeBuffer* deserializeBuffer, DeserializeBuffer* deserializeBuffer,
DeserializeAllocator* allocator, DeserializeAllocator* allocator,
const ObjectIdResolver& resolver); const ObjectIdResolver& resolver);
@ -593,9 +533,9 @@ namespace dawn_wire {
return result; return result;
} }
DAWN_NO_DISCARD bool SerializeChainedStruct(WGPUChainedStruct const* chainedStruct, DAWN_NO_DISCARD WireResult SerializeChainedStruct(WGPUChainedStruct const* chainedStruct,
SerializeBuffer* buffer, SerializeBuffer* buffer,
const ObjectIdProvider& provider) { const ObjectIdProvider& provider) {
ASSERT(chainedStruct != nullptr); ASSERT(chainedStruct != nullptr);
ASSERT(buffer != nullptr); ASSERT(buffer != nullptr);
do { do {
@ -605,11 +545,11 @@ namespace dawn_wire {
case {{as_cEnum(types["s type"].name, sType.name)}}: { case {{as_cEnum(types["s type"].name, sType.name)}}: {
{{CType}}Transfer* transfer; {{CType}}Transfer* transfer;
SERIALIZE_TRY(buffer->Next(&transfer)); WIRE_TRY(buffer->Next(&transfer));
transfer->chain.sType = chainedStruct->sType; transfer->chain.sType = chainedStruct->sType;
transfer->chain.hasNext = chainedStruct->next != nullptr; transfer->chain.hasNext = chainedStruct->next != nullptr;
SERIALIZE_TRY({{CType}}Serialize(*reinterpret_cast<{{CType}} const*>(chainedStruct), transfer, buffer WIRE_TRY({{CType}}Serialize(*reinterpret_cast<{{CType}} const*>(chainedStruct), transfer, buffer
{%- if types[sType.name.get()].may_have_dawn_object -%} {%- if types[sType.name.get()].may_have_dawn_object -%}
, provider , provider
{%- endif -%} {%- endif -%}
@ -626,7 +566,7 @@ namespace dawn_wire {
} }
WGPUChainedStructTransfer* transfer; WGPUChainedStructTransfer* transfer;
SERIALIZE_TRY(buffer->Next(&transfer)); WIRE_TRY(buffer->Next(&transfer));
transfer->sType = WGPUSType_Invalid; transfer->sType = WGPUSType_Invalid;
transfer->hasNext = chainedStruct->next != nullptr; transfer->hasNext = chainedStruct->next != nullptr;
@ -636,34 +576,34 @@ namespace dawn_wire {
} }
} }
} while (chainedStruct != nullptr); } while (chainedStruct != nullptr);
return true; return WireResult::Success;
} }
DeserializeResult DeserializeChainedStruct(const WGPUChainedStruct** outChainNext, WireResult DeserializeChainedStruct(const WGPUChainedStruct** outChainNext,
DeserializeBuffer* deserializeBuffer, DeserializeBuffer* deserializeBuffer,
DeserializeAllocator* allocator, DeserializeAllocator* allocator,
const ObjectIdResolver& resolver) { const ObjectIdResolver& resolver) {
bool hasNext; bool hasNext;
do { do {
const volatile WGPUChainedStructTransfer* header; const volatile WGPUChainedStructTransfer* header;
DESERIALIZE_TRY(deserializeBuffer->Peek(&header)); WIRE_TRY(deserializeBuffer->Peek(&header));
WGPUSType sType = header->sType; WGPUSType sType = header->sType;
switch (sType) { switch (sType) {
{% for sType in types["s type"].values if sType.valid and sType.name.CamelCase() not in client_side_structures %} {% for sType in types["s type"].values if sType.valid and sType.name.CamelCase() not in client_side_structures %}
{% set CType = as_cType(sType.name) %} {% set CType = as_cType(sType.name) %}
case {{as_cEnum(types["s type"].name, sType.name)}}: { case {{as_cEnum(types["s type"].name, sType.name)}}: {
const volatile {{CType}}Transfer* transfer; const volatile {{CType}}Transfer* transfer;
DESERIALIZE_TRY(deserializeBuffer->Read(&transfer)); WIRE_TRY(deserializeBuffer->Read(&transfer));
{{CType}}* outStruct; {{CType}}* outStruct;
DESERIALIZE_TRY(GetSpace(allocator, sizeof({{CType}}), &outStruct)); WIRE_TRY(GetSpace(allocator, sizeof({{CType}}), &outStruct));
outStruct->chain.sType = sType; outStruct->chain.sType = sType;
outStruct->chain.next = nullptr; outStruct->chain.next = nullptr;
*outChainNext = &outStruct->chain; *outChainNext = &outStruct->chain;
outChainNext = &outStruct->chain.next; outChainNext = &outStruct->chain.next;
DESERIALIZE_TRY({{CType}}Deserialize(outStruct, transfer, deserializeBuffer, allocator WIRE_TRY({{CType}}Deserialize(outStruct, transfer, deserializeBuffer, allocator
{%- if types[sType.name.get()].may_have_dawn_object -%} {%- if types[sType.name.get()].may_have_dawn_object -%}
, resolver , resolver
{%- endif -%} {%- endif -%}
@ -680,10 +620,10 @@ namespace dawn_wire {
} }
const volatile WGPUChainedStructTransfer* transfer; const volatile WGPUChainedStructTransfer* transfer;
DESERIALIZE_TRY(deserializeBuffer->Read(&transfer)); WIRE_TRY(deserializeBuffer->Read(&transfer));
WGPUChainedStruct* outStruct; WGPUChainedStruct* outStruct;
DESERIALIZE_TRY(GetSpace(allocator, sizeof(WGPUChainedStruct), &outStruct)); WIRE_TRY(GetSpace(allocator, sizeof(WGPUChainedStruct), &outStruct));
outStruct->sType = WGPUSType_Invalid; outStruct->sType = WGPUSType_Invalid;
outStruct->next = nullptr; outStruct->next = nullptr;
@ -696,7 +636,7 @@ namespace dawn_wire {
} }
} while (hasNext); } while (hasNext);
return DeserializeResult::Success; return WireResult::Success;
} }
//* Output [de]serialization helpers for commands //* Output [de]serialization helpers for commands
@ -733,10 +673,12 @@ namespace dawn_wire {
SerializeBuffer serializeBuffer(buffer, SerializedWGPUDevicePropertiesSize(deviceProperties)); SerializeBuffer serializeBuffer(buffer, SerializedWGPUDevicePropertiesSize(deviceProperties));
WGPUDevicePropertiesTransfer* transfer; WGPUDevicePropertiesTransfer* transfer;
bool success =
serializeBuffer.Next(&transfer) && WireResult result = serializeBuffer.Next(&transfer);
WGPUDevicePropertiesSerialize(*deviceProperties, transfer, &serializeBuffer); ASSERT(result == WireResult::Success);
ASSERT(success);
result = WGPUDevicePropertiesSerialize(*deviceProperties, transfer, &serializeBuffer);
ASSERT(result == WireResult::Success);
} }
bool DeserializeWGPUDeviceProperties(WGPUDeviceProperties* deviceProperties, bool DeserializeWGPUDeviceProperties(WGPUDeviceProperties* deviceProperties,
@ -744,12 +686,12 @@ namespace dawn_wire {
size_t size) { size_t size) {
const volatile WGPUDevicePropertiesTransfer* transfer; const volatile WGPUDevicePropertiesTransfer* transfer;
DeserializeBuffer deserializeBuffer(buffer, size); DeserializeBuffer deserializeBuffer(buffer, size);
if (deserializeBuffer.Read(&transfer) != DeserializeResult::Success) { if (deserializeBuffer.Read(&transfer) != WireResult::Success) {
return false; return false;
} }
return WGPUDevicePropertiesDeserialize(deviceProperties, transfer, &deserializeBuffer, return WGPUDevicePropertiesDeserialize(deviceProperties, transfer, &deserializeBuffer,
nullptr) == DeserializeResult::Success; nullptr) == WireResult::Success;
} }
} // namespace dawn_wire } // namespace dawn_wire

View File

@ -17,7 +17,9 @@
#include <dawn/webgpu.h> #include <dawn/webgpu.h>
#include "dawn_wire/BufferConsumer.h"
#include "dawn_wire/ObjectType_autogen.h" #include "dawn_wire/ObjectType_autogen.h"
#include "dawn_wire/WireResult.h"
namespace dawn_wire { namespace dawn_wire {
@ -43,67 +45,6 @@ namespace dawn_wire {
ObjectHandle& AssignFrom(const volatile ObjectHandle& rhs); ObjectHandle& AssignFrom(const volatile ObjectHandle& rhs);
}; };
enum class DeserializeResult {
Success,
FatalError,
};
template <typename BufferT>
class BufferConsumer {
public:
BufferConsumer(BufferT* buffer, size_t size) : mBuffer(buffer), mSize(size) {}
BufferT* Buffer() const { return mBuffer; }
size_t AvailableSize() const { return mSize; }
protected:
template <typename T, typename N>
DAWN_NO_DISCARD bool NextN(N count, T** data);
template <typename T>
DAWN_NO_DISCARD bool Next(T** data);
template <typename T>
DAWN_NO_DISCARD bool Peek(T** data);
private:
BufferT* mBuffer;
size_t mSize;
};
class SerializeBuffer : public BufferConsumer<char> {
public:
using BufferConsumer::BufferConsumer;
using BufferConsumer::NextN;
using BufferConsumer::Next;
};
class DeserializeBuffer : public BufferConsumer<const volatile char> {
public:
using BufferConsumer::BufferConsumer;
template <typename T, typename N>
DAWN_NO_DISCARD DeserializeResult ReadN(N count, const volatile T** data) {
return NextN(count, data)
? DeserializeResult::Success
: DeserializeResult::FatalError;
}
template <typename T>
DAWN_NO_DISCARD DeserializeResult Read(const volatile T** data) {
return Next(data)
? DeserializeResult::Success
: DeserializeResult::FatalError;
}
template <typename T>
DAWN_NO_DISCARD DeserializeResult Peek(const volatile T** data) {
return BufferConsumer::Peek(data)
? DeserializeResult::Success
: DeserializeResult::FatalError;
}
};
// Interface to allocate more space to deserialize pointed-to data. // Interface to allocate more space to deserialize pointed-to data.
// nullptr is treated as an error. // nullptr is treated as an error.
class DeserializeAllocator { class DeserializeAllocator {
@ -116,8 +57,8 @@ namespace dawn_wire {
class ObjectIdResolver { class ObjectIdResolver {
public: public:
{% for type in by_category["object"] %} {% for type in by_category["object"] %}
virtual DeserializeResult GetFromId(ObjectId id, {{as_cType(type.name)}}* out) const = 0; virtual WireResult GetFromId(ObjectId id, {{as_cType(type.name)}}* out) const = 0;
virtual DeserializeResult GetOptionalFromId(ObjectId id, {{as_cType(type.name)}}* out) const = 0; virtual WireResult GetOptionalFromId(ObjectId id, {{as_cType(type.name)}}* out) const = 0;
{% endfor %} {% endfor %}
}; };
@ -157,7 +98,7 @@ namespace dawn_wire {
//* Serialize the structure and everything it points to into serializeBuffer which must be //* Serialize the structure and everything it points to into serializeBuffer which must be
//* big enough to contain all the data (as queried from GetRequiredSize). //* big enough to contain all the data (as queried from GetRequiredSize).
DAWN_NO_DISCARD bool Serialize(size_t commandSize, SerializeBuffer* serializeBuffer WireResult Serialize(size_t commandSize, SerializeBuffer* serializeBuffer
{%- if not is_return_command -%} {%- if not is_return_command -%}
, const ObjectIdProvider& objectIdProvider , const ObjectIdProvider& objectIdProvider
{%- endif -%} {%- endif -%}
@ -170,7 +111,7 @@ namespace dawn_wire {
//* Deserialize returns: //* Deserialize returns:
//* - Success if everything went well (yay!) //* - Success if everything went well (yay!)
//* - FatalError is something bad happened (buffer too small for example) //* - FatalError is something bad happened (buffer too small for example)
DeserializeResult Deserialize(DeserializeBuffer* deserializeBuffer, DeserializeAllocator* allocator WireResult Deserialize(DeserializeBuffer* deserializeBuffer, DeserializeAllocator* allocator
{%- if command.may_have_dawn_object -%} {%- if command.may_have_dawn_object -%}
, const ObjectIdResolver& resolver , const ObjectIdResolver& resolver
{%- endif -%} {%- endif -%}

View File

@ -21,9 +21,9 @@ namespace dawn_wire { namespace client {
{% for command in cmd_records["return command"] %} {% for command in cmd_records["return command"] %}
bool Client::Handle{{command.name.CamelCase()}}(DeserializeBuffer* deserializeBuffer) { bool Client::Handle{{command.name.CamelCase()}}(DeserializeBuffer* deserializeBuffer) {
Return{{command.name.CamelCase()}}Cmd cmd; Return{{command.name.CamelCase()}}Cmd cmd;
DeserializeResult deserializeResult = cmd.Deserialize(deserializeBuffer, &mAllocator); WireResult deserializeResult = cmd.Deserialize(deserializeBuffer, &mAllocator);
if (deserializeResult == DeserializeResult::FatalError) { if (deserializeResult == WireResult::FatalError) {
return false; return false;
} }

View File

@ -70,20 +70,20 @@ namespace dawn_wire { namespace server {
private: private:
// Implementation of the ObjectIdResolver interface // Implementation of the ObjectIdResolver interface
{% for type in by_category["object"] %} {% for type in by_category["object"] %}
DeserializeResult GetFromId(ObjectId id, {{as_cType(type.name)}}* out) const final { WireResult GetFromId(ObjectId id, {{as_cType(type.name)}}* out) const final {
auto data = mKnown{{type.name.CamelCase()}}.Get(id); auto data = mKnown{{type.name.CamelCase()}}.Get(id);
if (data == nullptr) { if (data == nullptr) {
return DeserializeResult::FatalError; return WireResult::FatalError;
} }
*out = data->handle; *out = data->handle;
return DeserializeResult::Success; return WireResult::Success;
} }
DeserializeResult GetOptionalFromId(ObjectId id, {{as_cType(type.name)}}* out) const final { WireResult GetOptionalFromId(ObjectId id, {{as_cType(type.name)}}* out) const final {
if (id == 0) { if (id == 0) {
*out = nullptr; *out = nullptr;
return DeserializeResult::Success; return WireResult::Success;
} }
return GetFromId(id, out); return GetFromId(id, out);

View File

@ -25,13 +25,13 @@ namespace dawn_wire { namespace server {
//* The generic command handlers //* The generic command handlers
bool Server::Handle{{Suffix}}(DeserializeBuffer* deserializeBuffer) { bool Server::Handle{{Suffix}}(DeserializeBuffer* deserializeBuffer) {
{{Suffix}}Cmd cmd; {{Suffix}}Cmd cmd;
DeserializeResult deserializeResult = cmd.Deserialize(deserializeBuffer, &mAllocator WireResult deserializeResult = cmd.Deserialize(deserializeBuffer, &mAllocator
{%- if command.may_have_dawn_object -%} {%- if command.may_have_dawn_object -%}
, *this , *this
{%- endif -%} {%- endif -%}
); );
if (deserializeResult == DeserializeResult::FatalError) { if (deserializeResult == WireResult::FatalError) {
return false; return false;
} }

View File

@ -59,6 +59,8 @@ dawn_component("dawn_wire") {
configs = [ "${dawn_root}/src/common:dawn_internal" ] configs = [ "${dawn_root}/src/common:dawn_internal" ]
sources = get_target_outputs(":dawn_wire_gen") sources = get_target_outputs(":dawn_wire_gen")
sources += [ sources += [
"BufferConsumer.h",
"BufferConsumer_impl.h",
"ChunkedCommandHandler.cpp", "ChunkedCommandHandler.cpp",
"ChunkedCommandHandler.h", "ChunkedCommandHandler.h",
"ChunkedCommandSerializer.cpp", "ChunkedCommandSerializer.cpp",
@ -67,6 +69,7 @@ dawn_component("dawn_wire") {
"WireClient.cpp", "WireClient.cpp",
"WireDeserializeAllocator.cpp", "WireDeserializeAllocator.cpp",
"WireDeserializeAllocator.h", "WireDeserializeAllocator.h",
"WireResult.h",
"WireServer.cpp", "WireServer.cpp",
"client/ApiObjects.h", "client/ApiObjects.h",
"client/Buffer.cpp", "client/Buffer.cpp",

View File

@ -0,0 +1,85 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_BUFFERCONSUMER_H_
#define DAWNWIRE_BUFFERCONSUMER_H_
#include "dawn_wire/WireResult.h"
#include <cstddef>
namespace dawn_wire {
// BufferConsumer is a utility class that allows reading bytes from a buffer
// while simultaneously decrementing the amount of remaining space by exactly
// the amount read. It helps prevent bugs where incrementing a pointer and
// decrementing a size value are not kept in sync.
// BufferConsumer also contains bounds checks to prevent reading out-of-bounds.
template <typename BufferT>
class BufferConsumer {
static_assert(sizeof(BufferT) == 1,
"BufferT must be 1-byte, but may have const/volatile qualifiers.");
public:
BufferConsumer(BufferT* buffer, size_t size) : mBuffer(buffer), mSize(size) {
}
BufferT* Buffer() const {
return mBuffer;
}
size_t AvailableSize() const {
return mSize;
}
protected:
template <typename T, typename N>
WireResult NextN(N count, T** data);
template <typename T>
WireResult Next(T** data);
template <typename T>
WireResult Peek(T** data);
private:
BufferT* mBuffer;
size_t mSize;
};
class SerializeBuffer : public BufferConsumer<char> {
public:
using BufferConsumer::BufferConsumer;
using BufferConsumer::Next;
using BufferConsumer::NextN;
};
class DeserializeBuffer : public BufferConsumer<const volatile char> {
public:
using BufferConsumer::BufferConsumer;
using BufferConsumer::Peek;
template <typename T, typename N>
WireResult ReadN(N count, const volatile T** data) {
return NextN(count, data);
}
template <typename T>
WireResult Read(const volatile T** data) {
return Next(data);
}
};
} // namespace dawn_wire
#endif // DAWNWIRE_BUFFERCONSUMER_H_

View File

@ -0,0 +1,72 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_BUFFERCONSUMER_IMPL_H_
#define DAWNWIRE_BUFFERCONSUMER_IMPL_H_
#include "dawn_wire/BufferConsumer.h"
#include <limits>
namespace dawn_wire {
template <typename BufferT>
template <typename T>
WireResult BufferConsumer<BufferT>::Peek(T** data) {
if (sizeof(T) > mSize) {
return WireResult::FatalError;
}
*data = reinterpret_cast<T*>(mBuffer);
return WireResult::Success;
}
template <typename BufferT>
template <typename T>
WireResult BufferConsumer<BufferT>::Next(T** data) {
if (sizeof(T) > mSize) {
return WireResult::FatalError;
}
*data = reinterpret_cast<T*>(mBuffer);
mBuffer += sizeof(T);
mSize -= sizeof(T);
return WireResult::Success;
}
template <typename BufferT>
template <typename T, typename N>
WireResult BufferConsumer<BufferT>::NextN(N count, T** data) {
static_assert(std::is_unsigned<N>::value, "|count| argument of NextN must be unsigned.");
constexpr size_t kMaxCountWithoutOverflows = std::numeric_limits<size_t>::max() / sizeof(T);
if (count > kMaxCountWithoutOverflows) {
return WireResult::FatalError;
}
// Cannot overflow because |count| is not greater than |kMaxCountWithoutOverflows|.
size_t totalSize = sizeof(T) * count;
if (totalSize > mSize) {
return WireResult::FatalError;
}
*data = reinterpret_cast<T*>(mBuffer);
mBuffer += totalSize;
mSize -= totalSize;
return WireResult::Success;
}
} // namespace dawn_wire
#endif // DAWNWIRE_BUFFERCONSUMER_IMPL_H_

View File

@ -31,6 +31,8 @@ target_sources(dawn_wire PRIVATE
"${DAWN_INCLUDE_DIR}/dawn_wire/WireServer.h" "${DAWN_INCLUDE_DIR}/dawn_wire/WireServer.h"
"${DAWN_INCLUDE_DIR}/dawn_wire/dawn_wire_export.h" "${DAWN_INCLUDE_DIR}/dawn_wire/dawn_wire_export.h"
${DAWN_WIRE_GEN_SOURCES} ${DAWN_WIRE_GEN_SOURCES}
"BufferConsumer.h"
"BufferConsumer_impl.h"
"ChunkedCommandHandler.cpp" "ChunkedCommandHandler.cpp"
"ChunkedCommandHandler.h" "ChunkedCommandHandler.h"
"ChunkedCommandSerializer.cpp" "ChunkedCommandSerializer.cpp"
@ -39,6 +41,7 @@ target_sources(dawn_wire PRIVATE
"WireClient.cpp" "WireClient.cpp"
"WireDeserializeAllocator.cpp" "WireDeserializeAllocator.cpp"
"WireDeserializeAllocator.h" "WireDeserializeAllocator.h"
"WireResult.h"
"WireServer.cpp" "WireServer.cpp"
"client/ApiObjects.h" "client/ApiObjects.h"
"client/Buffer.cpp" "client/Buffer.cpp"

View File

@ -32,7 +32,7 @@ namespace dawn_wire {
template <typename Cmd> template <typename Cmd>
void SerializeCommand(const Cmd& cmd) { void SerializeCommand(const Cmd& cmd) {
SerializeCommand(cmd, 0, [](SerializeBuffer*) { return true; }); SerializeCommand(cmd, 0, [](SerializeBuffer*) { return WireResult::Success; });
} }
template <typename Cmd, typename ExtraSizeSerializeFn> template <typename Cmd, typename ExtraSizeSerializeFn>
@ -49,7 +49,8 @@ namespace dawn_wire {
template <typename Cmd> template <typename Cmd>
void SerializeCommand(const Cmd& cmd, const ObjectIdProvider& objectIdProvider) { void SerializeCommand(const Cmd& cmd, const ObjectIdProvider& objectIdProvider) {
SerializeCommand(cmd, objectIdProvider, 0, [](SerializeBuffer*) { return true; }); SerializeCommand(cmd, objectIdProvider, 0,
[](SerializeBuffer*) { return WireResult::Success; });
} }
template <typename Cmd, typename ExtraSizeSerializeFn> template <typename Cmd, typename ExtraSizeSerializeFn>
@ -79,10 +80,9 @@ namespace dawn_wire {
char* allocatedBuffer = static_cast<char*>(mSerializer->GetCmdSpace(requiredSize)); char* allocatedBuffer = static_cast<char*>(mSerializer->GetCmdSpace(requiredSize));
if (allocatedBuffer != nullptr) { if (allocatedBuffer != nullptr) {
SerializeBuffer serializeBuffer(allocatedBuffer, requiredSize); SerializeBuffer serializeBuffer(allocatedBuffer, requiredSize);
bool success = true; WireResult r1 = SerializeCmd(cmd, requiredSize, &serializeBuffer);
success &= SerializeCmd(cmd, requiredSize, &serializeBuffer); WireResult r2 = SerializeExtraSize(&serializeBuffer);
success &= SerializeExtraSize(&serializeBuffer); if (DAWN_UNLIKELY(r1 != WireResult::Success || r2 != WireResult::Success)) {
if (DAWN_UNLIKELY(!success)) {
mSerializer->OnSerializeError(); mSerializer->OnSerializeError();
} }
} }
@ -94,10 +94,9 @@ namespace dawn_wire {
return; return;
} }
SerializeBuffer serializeBuffer(cmdSpace.get(), requiredSize); SerializeBuffer serializeBuffer(cmdSpace.get(), requiredSize);
bool success = true; WireResult r1 = SerializeCmd(cmd, requiredSize, &serializeBuffer);
success &= SerializeCmd(cmd, requiredSize, &serializeBuffer); WireResult r2 = SerializeExtraSize(&serializeBuffer);
success &= SerializeExtraSize(&serializeBuffer); if (DAWN_UNLIKELY(r1 != WireResult::Success || r2 != WireResult::Success)) {
if (DAWN_UNLIKELY(!success)) {
mSerializer->OnSerializeError(); mSerializer->OnSerializeError();
return; return;
} }

View File

@ -0,0 +1,38 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNWIRE_WIRERESULT_H_
#define DAWNWIRE_WIRERESULT_H_
#include "common/Compiler.h"
namespace dawn_wire {
enum DAWN_NO_DISCARD class WireResult {
Success,
FatalError,
};
// Macro to simplify error handling, similar to DAWN_TRY but for WireResult.
#define WIRE_TRY(EXPR) \
do { \
WireResult exprResult = EXPR; \
if (DAWN_UNLIKELY(exprResult != WireResult::Success)) { \
return exprResult; \
} \
} while (0)
} // namespace dawn_wire
#endif // DAWNWIRE_WIRERESULT_H_

View File

@ -14,6 +14,7 @@
#include "dawn_wire/client/Buffer.h" #include "dawn_wire/client/Buffer.h"
#include "dawn_wire/BufferConsumer_impl.h"
#include "dawn_wire/WireCmd_autogen.h" #include "dawn_wire/WireCmd_autogen.h"
#include "dawn_wire/client/Client.h" #include "dawn_wire/client/Client.h"
#include "dawn_wire/client/Device.h" #include "dawn_wire/client/Device.h"
@ -77,11 +78,11 @@ namespace dawn_wire { namespace client {
wireClient->SerializeCommand( wireClient->SerializeCommand(
cmd, writeHandleCreateInfoLength, [&](SerializeBuffer* serializeBuffer) { cmd, writeHandleCreateInfoLength, [&](SerializeBuffer* serializeBuffer) {
if (descriptor->mappedAtCreation) { if (descriptor->mappedAtCreation) {
if (serializeBuffer->AvailableSize() != writeHandleCreateInfoLength) { char* writeHandleBuffer;
return false; WIRE_TRY(
} serializeBuffer->NextN(writeHandleCreateInfoLength, &writeHandleBuffer));
// Serialize the WriteHandle into the space after the command. // Serialize the WriteHandle into the space after the command.
writeHandle->SerializeCreate(serializeBuffer->Buffer()); writeHandle->SerializeCreate(writeHandleBuffer);
// Set the buffer state for the mapping at creation. The buffer now owns the // Set the buffer state for the mapping at creation. The buffer now owns the
// write handle.. // write handle..
@ -90,7 +91,7 @@ namespace dawn_wire { namespace client {
buffer->mMapOffset = 0; buffer->mMapOffset = 0;
buffer->mMapSize = buffer->mSize; buffer->mMapSize = buffer->mSize;
} }
return true; return WireResult::Success;
}); });
return ToAPI(buffer); return ToAPI(buffer);
} }
@ -207,22 +208,21 @@ namespace dawn_wire { namespace client {
cmd.handleCreateInfoLength = request.readHandle->SerializeCreateSize(); cmd.handleCreateInfoLength = request.readHandle->SerializeCreateSize();
client->SerializeCommand( client->SerializeCommand(
cmd, cmd.handleCreateInfoLength, [&](SerializeBuffer* serializeBuffer) { cmd, cmd.handleCreateInfoLength, [&](SerializeBuffer* serializeBuffer) {
bool success = serializeBuffer->AvailableSize() == cmd.handleCreateInfoLength; char* readHandleBuffer;
if (success) { WIRE_TRY(serializeBuffer->NextN(cmd.handleCreateInfoLength, &readHandleBuffer));
request.readHandle->SerializeCreate(serializeBuffer->Buffer()); request.readHandle->SerializeCreate(readHandleBuffer);
} return WireResult::Success;
return success;
}); });
} else { } else {
ASSERT(isWriteMode); ASSERT(isWriteMode);
cmd.handleCreateInfoLength = request.writeHandle->SerializeCreateSize(); cmd.handleCreateInfoLength = request.writeHandle->SerializeCreateSize();
client->SerializeCommand( client->SerializeCommand(
cmd, cmd.handleCreateInfoLength, [&](SerializeBuffer* serializeBuffer) { cmd, cmd.handleCreateInfoLength, [&](SerializeBuffer* serializeBuffer) {
bool success = serializeBuffer->AvailableSize() == cmd.handleCreateInfoLength; char* writeHandleBuffer;
if (success) { WIRE_TRY(
request.writeHandle->SerializeCreate(serializeBuffer->Buffer()); serializeBuffer->NextN(cmd.handleCreateInfoLength, &writeHandleBuffer));
} request.writeHandle->SerializeCreate(writeHandleBuffer);
return success; return WireResult::Success;
}); });
} }
@ -352,13 +352,13 @@ namespace dawn_wire { namespace client {
client->SerializeCommand( client->SerializeCommand(
cmd, writeFlushInfoLength, [&](SerializeBuffer* serializeBuffer) { cmd, writeFlushInfoLength, [&](SerializeBuffer* serializeBuffer) {
bool success = serializeBuffer->AvailableSize() == writeFlushInfoLength; char* writeHandleBuffer;
if (success) { WIRE_TRY(serializeBuffer->NextN(writeFlushInfoLength, &writeHandleBuffer));
// Serialize flush metadata into the space after the command.
// This closes the handle for writing. // Serialize flush metadata into the space after the command.
mWriteHandle->SerializeFlush(serializeBuffer->Buffer()); // This closes the handle for writing.
} mWriteHandle->SerializeFlush(writeHandleBuffer);
return success; return WireResult::Success;
}); });
mWriteHandle = nullptr; mWriteHandle = nullptr;

View File

@ -13,6 +13,7 @@
// limitations under the License. // limitations under the License.
#include "common/Assert.h" #include "common/Assert.h"
#include "dawn_wire/BufferConsumer_impl.h"
#include "dawn_wire/WireCmd_autogen.h" #include "dawn_wire/WireCmd_autogen.h"
#include "dawn_wire/server/Server.h" #include "dawn_wire/server/Server.h"
@ -251,12 +252,12 @@ namespace dawn_wire { namespace server {
SerializeCommand(cmd, cmd.readInitialDataInfoLength, [&](SerializeBuffer* serializeBuffer) { SerializeCommand(cmd, cmd.readInitialDataInfoLength, [&](SerializeBuffer* serializeBuffer) {
if (isSuccess) { if (isSuccess) {
if (isRead) { if (isRead) {
if (serializeBuffer->AvailableSize() != cmd.readInitialDataInfoLength) { char* readHandleBuffer;
return false; WIRE_TRY(
} serializeBuffer->NextN(cmd.readInitialDataInfoLength, &readHandleBuffer));
// Serialize the initialization message into the space after the command. // Serialize the initialization message into the space after the command.
data->readHandle->SerializeInitialData(readData, data->size, data->readHandle->SerializeInitialData(readData, data->size, readHandleBuffer);
serializeBuffer->Buffer());
// The in-flight map request returned successfully. // The in-flight map request returned successfully.
// Move the ReadHandle so it is owned by the buffer. // Move the ReadHandle so it is owned by the buffer.
bufferData->readHandle = std::move(data->readHandle); bufferData->readHandle = std::move(data->readHandle);
@ -271,7 +272,7 @@ namespace dawn_wire { namespace server {
data->size); data->size);
} }
} }
return true; return WireResult::Success;
}); });
} }