2018-07-18 09:40:26 +00:00
|
|
|
//* Copyright 2017 The Dawn Authors
|
2017-04-20 18:38:20 +00:00
|
|
|
//*
|
|
|
|
//* 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.
|
|
|
|
|
2019-01-15 20:49:53 +00:00
|
|
|
#include "dawn_wire/WireCmd_autogen.h"
|
2017-04-20 18:38:20 +00:00
|
|
|
|
2018-06-08 16:30:50 +00:00
|
|
|
#include "common/Assert.h"
|
2021-02-01 16:48:18 +00:00
|
|
|
#include "common/Log.h"
|
2019-10-20 03:01:56 +00:00
|
|
|
#include "dawn_wire/Wire.h"
|
2018-06-08 16:30:50 +00:00
|
|
|
|
2019-10-07 20:38:47 +00:00
|
|
|
#include <algorithm>
|
2018-06-06 15:36:49 +00:00
|
|
|
#include <cstring>
|
2019-01-04 09:54:10 +00:00
|
|
|
#include <limits>
|
2018-06-06 15:36:49 +00:00
|
|
|
|
2018-06-08 16:30:50 +00:00
|
|
|
//* Helper macros so that the main [de]serialization functions can be written in a generic manner.
|
|
|
|
|
|
|
|
//* Outputs an rvalue that's the number of elements a pointer member points to.
|
|
|
|
{% macro member_length(member, record_accessor) -%}
|
|
|
|
{%- if member.length == "constant" -%}
|
|
|
|
{{member.constant_length}}
|
|
|
|
{%- else -%}
|
|
|
|
{{record_accessor}}{{as_varName(member.length.name)}}
|
|
|
|
{%- endif -%}
|
|
|
|
{%- endmacro %}
|
|
|
|
|
|
|
|
//* Outputs the type that will be used on the wire for the member
|
|
|
|
{% macro member_transfer_type(member) -%}
|
|
|
|
{%- if member.type.category == "object" -%}
|
|
|
|
ObjectId
|
|
|
|
{%- elif member.type.category == "structure" -%}
|
|
|
|
{{as_cType(member.type.name)}}Transfer
|
2019-10-17 08:46:07 +00:00
|
|
|
{%- elif member.type.category == "bitmask" -%}
|
|
|
|
{{as_cType(member.type.name)}}Flags
|
2018-06-08 16:30:50 +00:00
|
|
|
{%- else -%}
|
|
|
|
{{as_cType(member.type.name)}}
|
|
|
|
{%- endif -%}
|
|
|
|
{%- endmacro %}
|
|
|
|
|
|
|
|
//* Outputs the size of one element of the type that will be used on the wire for the member
|
|
|
|
{% macro member_transfer_sizeof(member) -%}
|
|
|
|
sizeof({{member_transfer_type(member)}})
|
|
|
|
{%- endmacro %}
|
|
|
|
|
|
|
|
//* Outputs the serialization code to put `in` in `out`
|
|
|
|
{% macro serialize_member(member, in, out) %}
|
|
|
|
{%- if member.type.category == "object" -%}
|
2019-01-15 20:49:53 +00:00
|
|
|
{%- set Optional = "Optional" if member.optional else "" -%}
|
2018-11-28 17:00:33 +00:00
|
|
|
{{out}} = provider.Get{{Optional}}Id({{in}});
|
2019-01-21 08:29:01 +00:00
|
|
|
{% elif member.type.category == "structure"%}
|
2020-04-03 17:37:48 +00:00
|
|
|
{%- set Provider = ", provider" if member.type.may_have_dawn_object else "" -%}
|
2019-01-21 08:29:01 +00:00
|
|
|
{% if member.annotation == "const*const*" %}
|
|
|
|
{{as_cType(member.type.name)}}Serialize(*{{in}}, &{{out}}, buffer{{Provider}});
|
|
|
|
{% else %}
|
|
|
|
{{as_cType(member.type.name)}}Serialize({{in}}, &{{out}}, buffer{{Provider}});
|
|
|
|
{% endif %}
|
2018-06-08 16:30:50 +00:00
|
|
|
{%- else -%}
|
|
|
|
{{out}} = {{in}};
|
|
|
|
{%- endif -%}
|
|
|
|
{% endmacro %}
|
|
|
|
|
|
|
|
//* Outputs the deserialization code to put `in` in `out`
|
|
|
|
{% macro deserialize_member(member, in, out) %}
|
|
|
|
{%- if member.type.category == "object" -%}
|
2019-01-15 20:49:53 +00:00
|
|
|
{%- set Optional = "Optional" if member.optional else "" -%}
|
2018-11-28 17:00:33 +00:00
|
|
|
DESERIALIZE_TRY(resolver.Get{{Optional}}FromId({{in}}, &{{out}}));
|
2019-01-15 20:49:53 +00:00
|
|
|
{%- elif member.type.category == "structure" -%}
|
|
|
|
DESERIALIZE_TRY({{as_cType(member.type.name)}}Deserialize(&{{out}}, &{{in}}, buffer, size, allocator
|
2020-04-03 17:37:48 +00:00
|
|
|
{%- if member.type.may_have_dawn_object -%}
|
2019-01-15 20:49:53 +00:00
|
|
|
, resolver
|
|
|
|
{%- endif -%}
|
|
|
|
));
|
2018-06-08 16:30:50 +00:00
|
|
|
{%- else -%}
|
|
|
|
{{out}} = {{in}};
|
|
|
|
{%- endif -%}
|
|
|
|
{% endmacro %}
|
|
|
|
|
2020-04-03 17:37:48 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
struct WGPUChainedStructTransfer {
|
|
|
|
WGPUSType sType;
|
|
|
|
bool hasNext;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
2018-06-08 16:30:50 +00:00
|
|
|
//* The main [de]serialization macro
|
|
|
|
//* Methods are very similar to structures that have one member corresponding to each arguments.
|
|
|
|
//* This macro takes advantage of the similarity to output [de]serialization code for a record
|
|
|
|
//* that is either a structure or a method, with some special cases for each.
|
2019-04-01 21:04:17 +00:00
|
|
|
{% macro write_record_serialization_helpers(record, name, members, is_cmd=False, is_return_command=False) %}
|
2018-06-08 16:30:50 +00:00
|
|
|
{% set Return = "Return" if is_return_command else "" %}
|
2019-01-15 20:49:53 +00:00
|
|
|
{% set Cmd = "Cmd" if is_cmd else "" %}
|
2020-10-13 22:35:34 +00:00
|
|
|
{% set Inherits = " : CmdHeader" if is_cmd else "" %}
|
2018-06-08 16:30:50 +00:00
|
|
|
|
|
|
|
//* Structure for the wire format of each of the records. Members that are values
|
|
|
|
//* are embedded directly in the structure. Other members are assumed to be in the
|
|
|
|
//* memory directly following the structure in the buffer.
|
2020-10-13 22:35:34 +00:00
|
|
|
struct {{Return}}{{name}}Transfer{{Inherits}} {
|
2020-04-03 17:37:48 +00:00
|
|
|
static_assert({{[is_cmd, record.extensible, record.chained].count(True)}} <= 1,
|
|
|
|
"Record must be at most one of is_cmd, extensible, and chained.");
|
2019-01-15 20:49:53 +00:00
|
|
|
{% if is_cmd %}
|
2018-06-08 16:30:50 +00:00
|
|
|
//* Start the transfer structure with the command ID, so that casting to WireCmd gives the ID.
|
2018-07-26 13:07:57 +00:00
|
|
|
{{Return}}WireCmd commandId;
|
2020-04-03 17:37:48 +00:00
|
|
|
{% elif record.extensible %}
|
|
|
|
bool hasNextInChain;
|
|
|
|
{% elif record.chained %}
|
|
|
|
WGPUChainedStructTransfer chain;
|
2018-06-08 16:30:50 +00:00
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
//* Value types are directly in the command, objects being replaced with their IDs.
|
|
|
|
{% for member in members if member.annotation == "value" %}
|
|
|
|
{{member_transfer_type(member)}} {{as_varName(member.name)}};
|
|
|
|
{% endfor %}
|
|
|
|
|
|
|
|
//* const char* have their length embedded directly in the command.
|
|
|
|
{% for member in members if member.length == "strlen" %}
|
|
|
|
size_t {{as_varName(member.name)}}Strlen;
|
|
|
|
{% endfor %}
|
2019-02-13 10:15:38 +00:00
|
|
|
|
2019-10-02 06:35:08 +00:00
|
|
|
{% for member in members if member.optional and member.annotation != "value" and member.type.category != "object" %}
|
2019-02-13 10:15:38 +00:00
|
|
|
bool has_{{as_varName(member.name)}};
|
|
|
|
{% endfor %}
|
2018-06-08 16:30:50 +00:00
|
|
|
};
|
|
|
|
|
2020-10-13 22:35:34 +00:00
|
|
|
{% if is_cmd %}
|
|
|
|
static_assert(offsetof({{Return}}{{name}}Transfer, commandSize) == 0, "");
|
|
|
|
static_assert(offsetof({{Return}}{{name}}Transfer, commandId) == sizeof(CmdHeader), "");
|
|
|
|
{% endif %}
|
|
|
|
|
2020-04-03 17:37:48 +00:00
|
|
|
{% if record.chained %}
|
|
|
|
static_assert(offsetof({{Return}}{{name}}Transfer, chain) == 0, "");
|
|
|
|
{% endif %}
|
|
|
|
|
2018-06-08 16:30:50 +00:00
|
|
|
//* Returns the required transfer size for `record` in addition to the transfer structure.
|
2019-01-15 20:49:53 +00:00
|
|
|
DAWN_DECLARE_UNUSED size_t {{Return}}{{name}}GetExtraRequiredSize(const {{Return}}{{name}}{{Cmd}}& record) {
|
2018-07-18 11:37:54 +00:00
|
|
|
DAWN_UNUSED(record);
|
2018-06-08 16:30:50 +00:00
|
|
|
|
|
|
|
size_t result = 0;
|
|
|
|
|
2020-04-03 17:37:48 +00:00
|
|
|
//* Gather how much space will be needed for the extension chain.
|
|
|
|
{% if record.extensible %}
|
|
|
|
if (record.nextInChain != nullptr) {
|
|
|
|
result += GetChainedStructExtraRequiredSize(record.nextInChain);
|
|
|
|
}
|
|
|
|
{% endif %}
|
|
|
|
|
2018-06-08 16:30:50 +00:00
|
|
|
//* Special handling of const char* that have their length embedded directly in the command
|
|
|
|
{% for member in members if member.length == "strlen" %}
|
2019-09-27 21:25:43 +00:00
|
|
|
{% set memberName = as_varName(member.name) %}
|
|
|
|
|
|
|
|
{% if member.optional %}
|
|
|
|
bool has_{{memberName}} = record.{{memberName}} != nullptr;
|
|
|
|
if (has_{{memberName}})
|
|
|
|
{% endif %}
|
|
|
|
{
|
|
|
|
result += std::strlen(record.{{memberName}});
|
|
|
|
}
|
2018-06-08 16:30:50 +00:00
|
|
|
{% endfor %}
|
|
|
|
|
|
|
|
//* Gather how much space will be needed for pointer members.
|
2019-09-05 09:35:07 +00:00
|
|
|
{% for member in members if member.length != "strlen" and not member.skip_serialize %}
|
2019-02-13 10:15:38 +00:00
|
|
|
{% if member.type.category != "object" and member.optional %}
|
|
|
|
if (record.{{as_varName(member.name)}} != nullptr)
|
|
|
|
{% endif %}
|
2018-06-08 16:30:50 +00:00
|
|
|
{
|
2019-09-05 09:35:07 +00:00
|
|
|
{% if member.annotation != "value" %}
|
|
|
|
size_t memberLength = {{member_length(member, "record.")}};
|
|
|
|
result += memberLength * {{member_transfer_sizeof(member)}};
|
|
|
|
//* Structures might contain more pointers so we need to add their extra size as well.
|
|
|
|
{% if member.type.category == "structure" %}
|
|
|
|
for (size_t i = 0; i < memberLength; ++i) {
|
|
|
|
{% if member.annotation == "const*const*" %}
|
|
|
|
result += {{as_cType(member.type.name)}}GetExtraRequiredSize(*record.{{as_varName(member.name)}}[i]);
|
|
|
|
{% else %}
|
|
|
|
{{assert(member.annotation == "const*")}}
|
|
|
|
result += {{as_cType(member.type.name)}}GetExtraRequiredSize(record.{{as_varName(member.name)}}[i]);
|
|
|
|
{% endif %}
|
|
|
|
}
|
|
|
|
{% endif %}
|
|
|
|
{% elif member.type.category == "structure" %}
|
|
|
|
result += {{as_cType(member.type.name)}}GetExtraRequiredSize(record.{{as_varName(member.name)}});
|
2018-06-08 16:30:50 +00:00
|
|
|
{% endif %}
|
|
|
|
}
|
|
|
|
{% endfor %}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2018-09-17 22:59:08 +00:00
|
|
|
// GetExtraRequiredSize isn't used for structures that are value members of other structures
|
|
|
|
// because we assume they cannot contain pointers themselves.
|
2019-01-15 20:49:53 +00:00
|
|
|
DAWN_UNUSED_FUNC({{Return}}{{name}}GetExtraRequiredSize);
|
2018-06-08 16:30:50 +00:00
|
|
|
|
|
|
|
//* Serializes `record` into `transfer`, using `buffer` to get more space for pointed-to data
|
|
|
|
//* and `provider` to serialize objects.
|
2019-05-15 18:55:22 +00:00
|
|
|
DAWN_DECLARE_UNUSED void {{Return}}{{name}}Serialize(const {{Return}}{{name}}{{Cmd}}& record, {{Return}}{{name}}Transfer* transfer,
|
2019-01-15 20:49:53 +00:00
|
|
|
char** buffer
|
2020-04-03 17:37:48 +00:00
|
|
|
{%- if record.may_have_dawn_object -%}
|
2019-01-15 20:49:53 +00:00
|
|
|
, const ObjectIdProvider& provider
|
|
|
|
{%- endif -%}
|
|
|
|
) {
|
2018-07-18 11:37:54 +00:00
|
|
|
DAWN_UNUSED(buffer);
|
2018-06-08 16:30:50 +00:00
|
|
|
|
|
|
|
//* Handle special transfer members of methods.
|
2019-01-15 20:49:53 +00:00
|
|
|
{% if is_cmd %}
|
2018-07-26 13:07:57 +00:00
|
|
|
transfer->commandId = {{Return}}WireCmd::{{name}};
|
2018-06-08 16:30:50 +00:00
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
//* Value types are directly in the transfer record, objects being replaced with their IDs.
|
|
|
|
{% for member in members if member.annotation == "value" %}
|
|
|
|
{% set memberName = as_varName(member.name) %}
|
|
|
|
{{serialize_member(member, "record." + memberName, "transfer->" + memberName)}}
|
|
|
|
{% endfor %}
|
|
|
|
|
2020-04-03 17:37:48 +00:00
|
|
|
{% if record.extensible %}
|
|
|
|
if (record.nextInChain != nullptr) {
|
|
|
|
transfer->hasNextInChain = true;
|
|
|
|
SerializeChainedStruct(record.nextInChain, buffer, provider);
|
|
|
|
} else {
|
|
|
|
transfer->hasNextInChain = false;
|
|
|
|
}
|
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
{% if record.chained %}
|
|
|
|
//* Should be set by the root descriptor's call to SerializeChainedStruct.
|
|
|
|
ASSERT(transfer->chain.sType == {{as_cEnum(types["s type"].name, record.name)}});
|
|
|
|
ASSERT(transfer->chain.hasNext == (record.chain.next != nullptr));
|
|
|
|
{% endif %}
|
|
|
|
|
2018-06-08 16:30:50 +00:00
|
|
|
//* Special handling of const char* that have their length embedded directly in the command
|
|
|
|
{% for member in members if member.length == "strlen" %}
|
|
|
|
{% set memberName = as_varName(member.name) %}
|
2019-09-27 21:25:43 +00:00
|
|
|
|
|
|
|
{% if member.optional %}
|
2019-10-02 06:35:08 +00:00
|
|
|
bool has_{{memberName}} = record.{{memberName}} != nullptr;
|
|
|
|
transfer->has_{{memberName}} = has_{{memberName}};
|
2019-09-27 21:25:43 +00:00
|
|
|
if (has_{{memberName}})
|
|
|
|
{% endif %}
|
|
|
|
{
|
2018-06-08 16:30:50 +00:00
|
|
|
transfer->{{memberName}}Strlen = std::strlen(record.{{memberName}});
|
|
|
|
|
2018-12-05 10:13:52 +00:00
|
|
|
memcpy(*buffer, record.{{memberName}}, transfer->{{memberName}}Strlen);
|
|
|
|
*buffer += transfer->{{memberName}}Strlen;
|
2019-09-27 21:25:43 +00:00
|
|
|
}
|
2018-06-08 16:30:50 +00:00
|
|
|
{% endfor %}
|
|
|
|
|
|
|
|
//* Allocate space and write the non-value arguments in it.
|
2019-07-19 16:01:48 +00:00
|
|
|
{% for member in members if member.annotation != "value" and member.length != "strlen" and not member.skip_serialize %}
|
2018-06-08 16:30:50 +00:00
|
|
|
{% set memberName = as_varName(member.name) %}
|
2019-02-13 10:15:38 +00:00
|
|
|
|
|
|
|
{% if member.type.category != "object" and member.optional %}
|
|
|
|
bool has_{{memberName}} = record.{{memberName}} != nullptr;
|
|
|
|
transfer->has_{{memberName}} = has_{{memberName}};
|
|
|
|
if (has_{{memberName}})
|
|
|
|
{% endif %}
|
2018-06-08 16:30:50 +00:00
|
|
|
{
|
|
|
|
size_t memberLength = {{member_length(member, "record.")}};
|
2018-12-05 10:13:52 +00:00
|
|
|
auto memberBuffer = reinterpret_cast<{{member_transfer_type(member)}}*>(*buffer);
|
|
|
|
*buffer += memberLength * {{member_transfer_sizeof(member)}};
|
2019-09-05 09:35:07 +00:00
|
|
|
|
2018-06-08 16:30:50 +00:00
|
|
|
for (size_t i = 0; i < memberLength; ++i) {
|
|
|
|
{{serialize_member(member, "record." + memberName + "[i]", "memberBuffer[i]" )}}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{% endfor %}
|
|
|
|
}
|
2019-05-15 18:55:22 +00:00
|
|
|
DAWN_UNUSED_FUNC({{Return}}{{name}}Serialize);
|
2018-06-08 16:30:50 +00:00
|
|
|
|
|
|
|
//* 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
|
|
|
|
//* Ids to actual objects.
|
2019-10-07 20:38:47 +00:00
|
|
|
DAWN_DECLARE_UNUSED DeserializeResult {{Return}}{{name}}Deserialize({{Return}}{{name}}{{Cmd}}* record, const volatile {{Return}}{{name}}Transfer* transfer,
|
|
|
|
const volatile char** buffer, size_t* size, DeserializeAllocator* allocator
|
2020-04-03 17:37:48 +00:00
|
|
|
{%- if record.may_have_dawn_object -%}
|
2019-01-15 20:49:53 +00:00
|
|
|
, const ObjectIdResolver& resolver
|
|
|
|
{%- endif -%}
|
|
|
|
) {
|
2018-07-18 11:37:54 +00:00
|
|
|
DAWN_UNUSED(allocator);
|
|
|
|
DAWN_UNUSED(buffer);
|
|
|
|
DAWN_UNUSED(size);
|
2018-06-08 16:30:50 +00:00
|
|
|
|
2019-01-15 20:49:53 +00:00
|
|
|
{% if is_cmd %}
|
2018-07-26 13:07:57 +00:00
|
|
|
ASSERT(transfer->commandId == {{Return}}WireCmd::{{name}});
|
2019-01-15 20:49:53 +00:00
|
|
|
{% endif %}
|
|
|
|
|
2019-04-01 21:04:17 +00:00
|
|
|
{% if record.derived_method %}
|
|
|
|
record->selfId = transfer->self;
|
|
|
|
{% endif %}
|
|
|
|
|
2018-06-08 16:30:50 +00:00
|
|
|
//* Value types are directly in the transfer record, objects being replaced with their IDs.
|
|
|
|
{% for member in members if member.annotation == "value" %}
|
|
|
|
{% set memberName = as_varName(member.name) %}
|
|
|
|
{{deserialize_member(member, "transfer->" + memberName, "record->" + memberName)}}
|
|
|
|
{% endfor %}
|
|
|
|
|
2020-04-03 17:37:48 +00:00
|
|
|
{% if record.extensible %}
|
|
|
|
record->nextInChain = nullptr;
|
|
|
|
if (transfer->hasNextInChain) {
|
|
|
|
DESERIALIZE_TRY(DeserializeChainedStruct(&record->nextInChain, buffer, size, allocator, resolver));
|
|
|
|
}
|
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
{% if record.chained %}
|
|
|
|
//* Should be set by the root descriptor's call to DeserializeChainedStruct.
|
|
|
|
//* Don't check |record->chain.next| matches because it is not set until the
|
|
|
|
//* next iteration inside DeserializeChainedStruct.
|
|
|
|
ASSERT(record->chain.sType == {{as_cEnum(types["s type"].name, record.name)}});
|
|
|
|
ASSERT(record->chain.next == nullptr);
|
|
|
|
{% endif %}
|
|
|
|
|
2018-06-08 16:30:50 +00:00
|
|
|
//* Special handling of const char* that have their length embedded directly in the command
|
|
|
|
{% for member in members if member.length == "strlen" %}
|
|
|
|
{% set memberName = as_varName(member.name) %}
|
2019-09-27 21:25:43 +00:00
|
|
|
|
2019-10-02 06:35:08 +00:00
|
|
|
{% if member.optional %}
|
2019-10-07 20:38:47 +00:00
|
|
|
bool has_{{memberName}} = transfer->has_{{memberName}};
|
|
|
|
record->{{memberName}} = nullptr;
|
|
|
|
if (has_{{memberName}})
|
2019-10-02 06:35:08 +00:00
|
|
|
{% endif %}
|
2018-06-08 16:30:50 +00:00
|
|
|
{
|
|
|
|
size_t stringLength = transfer->{{memberName}}Strlen;
|
2019-10-07 20:38:47 +00:00
|
|
|
const volatile char* stringInBuffer = nullptr;
|
2018-06-08 16:30:50 +00:00
|
|
|
DESERIALIZE_TRY(GetPtrFromBuffer(buffer, size, stringLength, &stringInBuffer));
|
|
|
|
|
|
|
|
char* copiedString = nullptr;
|
|
|
|
DESERIALIZE_TRY(GetSpace(allocator, stringLength + 1, &copiedString));
|
2019-10-07 20:38:47 +00:00
|
|
|
std::copy(stringInBuffer, stringInBuffer + stringLength, copiedString);
|
2018-06-08 16:30:50 +00:00
|
|
|
copiedString[stringLength] = '\0';
|
|
|
|
record->{{memberName}} = copiedString;
|
|
|
|
}
|
|
|
|
{% endfor %}
|
|
|
|
|
|
|
|
//* Get extra buffer data, and copy pointed to values in extra allocated space.
|
|
|
|
{% for member in members if member.annotation != "value" and member.length != "strlen" %}
|
|
|
|
{% set memberName = as_varName(member.name) %}
|
2019-02-13 10:15:38 +00:00
|
|
|
|
|
|
|
{% if member.type.category != "object" and member.optional %}
|
|
|
|
bool has_{{memberName}} = transfer->has_{{memberName}};
|
|
|
|
record->{{memberName}} = nullptr;
|
|
|
|
if (has_{{memberName}})
|
|
|
|
{% endif %}
|
2018-06-08 16:30:50 +00:00
|
|
|
{
|
|
|
|
size_t memberLength = {{member_length(member, "record->")}};
|
2019-10-07 20:38:47 +00:00
|
|
|
auto memberBuffer = reinterpret_cast<const volatile {{member_transfer_type(member)}}*>(buffer);
|
2018-06-08 16:30:50 +00:00
|
|
|
DESERIALIZE_TRY(GetPtrFromBuffer(buffer, size, memberLength, &memberBuffer));
|
|
|
|
|
|
|
|
{{as_cType(member.type.name)}}* copiedMembers = nullptr;
|
|
|
|
DESERIALIZE_TRY(GetSpace(allocator, memberLength, &copiedMembers));
|
2019-01-21 08:29:01 +00:00
|
|
|
{% if member.annotation == "const*const*" %}
|
|
|
|
{{as_cType(member.type.name)}}** pointerArray = nullptr;
|
|
|
|
DESERIALIZE_TRY(GetSpace(allocator, memberLength, &pointerArray));
|
|
|
|
for (size_t i = 0; i < memberLength; ++i) {
|
|
|
|
pointerArray[i] = &copiedMembers[i];
|
|
|
|
}
|
|
|
|
record->{{memberName}} = pointerArray;
|
|
|
|
{% else %}
|
|
|
|
record->{{memberName}} = copiedMembers;
|
|
|
|
{% endif %}
|
2018-06-08 16:30:50 +00:00
|
|
|
|
|
|
|
for (size_t i = 0; i < memberLength; ++i) {
|
|
|
|
{{deserialize_member(member, "memberBuffer[i]", "copiedMembers[i]")}}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{% endfor %}
|
|
|
|
|
|
|
|
return DeserializeResult::Success;
|
|
|
|
}
|
2019-05-15 18:55:22 +00:00
|
|
|
DAWN_UNUSED_FUNC({{Return}}{{name}}Deserialize);
|
2018-06-08 16:30:50 +00:00
|
|
|
{% endmacro %}
|
|
|
|
|
2019-01-15 20:49:53 +00:00
|
|
|
{% macro write_command_serialization_methods(command, is_return) %}
|
|
|
|
{% set Return = "Return" if is_return else "" %}
|
|
|
|
{% set Name = Return + command.name.CamelCase() %}
|
|
|
|
{% set Cmd = Name + "Cmd" %}
|
|
|
|
|
|
|
|
size_t {{Cmd}}::GetRequiredSize() const {
|
|
|
|
size_t size = sizeof({{Name}}Transfer) + {{Name}}GetExtraRequiredSize(*this);
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2020-10-13 22:35:34 +00:00
|
|
|
void {{Cmd}}::Serialize(size_t commandSize, char* buffer
|
2020-06-19 16:49:43 +00:00
|
|
|
{%- if not is_return -%}
|
2019-01-15 20:49:53 +00:00
|
|
|
, const ObjectIdProvider& objectIdProvider
|
|
|
|
{%- endif -%}
|
|
|
|
) const {
|
|
|
|
auto transfer = reinterpret_cast<{{Name}}Transfer*>(buffer);
|
2020-10-13 22:35:34 +00:00
|
|
|
transfer->commandSize = commandSize;
|
2019-01-15 20:49:53 +00:00
|
|
|
buffer += sizeof({{Name}}Transfer);
|
|
|
|
|
|
|
|
{{Name}}Serialize(*this, transfer, &buffer
|
2020-04-03 17:37:48 +00:00
|
|
|
{%- if command.may_have_dawn_object -%}
|
2019-01-15 20:49:53 +00:00
|
|
|
, objectIdProvider
|
|
|
|
{%- endif -%}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-10-07 20:38:47 +00:00
|
|
|
DeserializeResult {{Cmd}}::Deserialize(const volatile char** buffer, size_t* size, DeserializeAllocator* allocator
|
2020-04-03 17:37:48 +00:00
|
|
|
{%- if command.may_have_dawn_object -%}
|
2019-01-15 20:49:53 +00:00
|
|
|
, const ObjectIdResolver& resolver
|
|
|
|
{%- endif -%}
|
|
|
|
) {
|
2019-10-07 20:38:47 +00:00
|
|
|
const volatile {{Name}}Transfer* transfer = nullptr;
|
2019-01-15 20:49:53 +00:00
|
|
|
DESERIALIZE_TRY(GetPtrFromBuffer(buffer, size, 1, &transfer));
|
|
|
|
|
|
|
|
return {{Name}}Deserialize(this, transfer, buffer, size, allocator
|
2020-04-03 17:37:48 +00:00
|
|
|
{%- if command.may_have_dawn_object -%}
|
2019-01-15 20:49:53 +00:00
|
|
|
, resolver
|
|
|
|
{%- endif -%}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
{% endmacro %}
|
|
|
|
|
2018-07-26 13:07:57 +00:00
|
|
|
namespace dawn_wire {
|
2018-06-06 15:36:49 +00:00
|
|
|
|
2018-07-18 09:45:17 +00:00
|
|
|
// Macro to simplify error handling, similar to DAWN_TRY but for DeserializeResult.
|
2018-06-06 15:36:49 +00:00
|
|
|
#define DESERIALIZE_TRY(EXPR) \
|
2020-04-11 03:22:33 +00:00
|
|
|
do { \
|
2018-06-06 15:36:49 +00:00
|
|
|
DeserializeResult exprResult = EXPR; \
|
|
|
|
if (exprResult != DeserializeResult::Success) { \
|
|
|
|
return exprResult; \
|
|
|
|
} \
|
2020-04-11 03:22:33 +00:00
|
|
|
} while (0)
|
2018-06-06 15:36:49 +00:00
|
|
|
|
2019-10-07 20:38:47 +00:00
|
|
|
ObjectHandle::ObjectHandle() = default;
|
2020-04-13 17:50:51 +00:00
|
|
|
ObjectHandle::ObjectHandle(ObjectId id, ObjectGeneration generation)
|
|
|
|
: id(id), generation(generation) {
|
|
|
|
}
|
2020-04-24 17:02:53 +00:00
|
|
|
|
2020-04-13 17:50:51 +00:00
|
|
|
ObjectHandle::ObjectHandle(const volatile ObjectHandle& rhs)
|
|
|
|
: id(rhs.id), generation(rhs.generation) {
|
|
|
|
}
|
2020-04-24 17:02:53 +00:00
|
|
|
ObjectHandle& ObjectHandle::operator=(const volatile ObjectHandle& rhs) {
|
|
|
|
id = rhs.id;
|
|
|
|
generation = rhs.generation;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2019-10-15 07:30:35 +00:00
|
|
|
ObjectHandle& ObjectHandle::AssignFrom(const ObjectHandle& rhs) {
|
|
|
|
id = rhs.id;
|
2020-04-13 17:50:51 +00:00
|
|
|
generation = rhs.generation;
|
2019-10-15 07:30:35 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
ObjectHandle& ObjectHandle::AssignFrom(const volatile ObjectHandle& rhs) {
|
2019-10-07 20:38:47 +00:00
|
|
|
id = rhs.id;
|
2020-04-13 17:50:51 +00:00
|
|
|
generation = rhs.generation;
|
2019-10-07 20:38:47 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2018-06-08 16:30:50 +00:00
|
|
|
namespace {
|
2018-06-06 15:36:49 +00:00
|
|
|
|
2018-06-08 16:30:50 +00:00
|
|
|
// Consumes from (buffer, size) enough memory to contain T[count] and return it in data.
|
|
|
|
// Returns FatalError if not enough memory was available
|
|
|
|
template <typename T>
|
2019-10-07 20:38:47 +00:00
|
|
|
DeserializeResult GetPtrFromBuffer(const volatile char** buffer, size_t* size, size_t count, const volatile T** data) {
|
2019-01-04 09:54:10 +00:00
|
|
|
constexpr size_t kMaxCountWithoutOverflows = std::numeric_limits<size_t>::max() / sizeof(T);
|
|
|
|
if (count > kMaxCountWithoutOverflows) {
|
|
|
|
return DeserializeResult::FatalError;
|
|
|
|
}
|
|
|
|
|
2018-06-08 16:30:50 +00:00
|
|
|
size_t totalSize = sizeof(T) * count;
|
|
|
|
if (totalSize > *size) {
|
|
|
|
return DeserializeResult::FatalError;
|
|
|
|
}
|
2018-06-06 15:36:49 +00:00
|
|
|
|
2019-10-07 20:38:47 +00:00
|
|
|
*data = reinterpret_cast<const volatile T*>(*buffer);
|
2018-06-08 16:30:50 +00:00
|
|
|
*buffer += totalSize;
|
|
|
|
*size -= totalSize;
|
2018-06-06 15:36:49 +00:00
|
|
|
|
2018-06-08 16:30:50 +00:00
|
|
|
return DeserializeResult::Success;
|
2018-06-06 15:36:49 +00:00
|
|
|
}
|
|
|
|
|
2018-06-08 16:30:50 +00:00
|
|
|
// Allocates enough space from allocator to countain T[count] and return it in out.
|
|
|
|
// Return FatalError if the allocator couldn't allocate the memory.
|
|
|
|
template <typename T>
|
|
|
|
DeserializeResult GetSpace(DeserializeAllocator* allocator, size_t count, T** out) {
|
2019-01-04 09:54:10 +00:00
|
|
|
constexpr size_t kMaxCountWithoutOverflows = std::numeric_limits<size_t>::max() / sizeof(T);
|
|
|
|
if (count > kMaxCountWithoutOverflows) {
|
|
|
|
return DeserializeResult::FatalError;
|
|
|
|
}
|
|
|
|
|
2018-06-08 16:30:50 +00:00
|
|
|
size_t totalSize = sizeof(T) * count;
|
|
|
|
*out = static_cast<T*>(allocator->GetSpace(totalSize));
|
|
|
|
if (*out == nullptr) {
|
|
|
|
return DeserializeResult::FatalError;
|
|
|
|
}
|
2018-06-06 15:36:49 +00:00
|
|
|
|
2018-06-08 16:30:50 +00:00
|
|
|
return DeserializeResult::Success;
|
|
|
|
}
|
2018-06-06 15:36:49 +00:00
|
|
|
|
2020-04-03 17:37:48 +00:00
|
|
|
size_t GetChainedStructExtraRequiredSize(const WGPUChainedStruct* chainedStruct);
|
|
|
|
void SerializeChainedStruct(WGPUChainedStruct const* chainedStruct,
|
|
|
|
char** buffer,
|
|
|
|
const ObjectIdProvider& provider);
|
|
|
|
DeserializeResult DeserializeChainedStruct(const WGPUChainedStruct** outChainNext,
|
|
|
|
const volatile char** buffer,
|
|
|
|
size_t* size,
|
|
|
|
DeserializeAllocator* allocator,
|
|
|
|
const ObjectIdResolver& resolver);
|
|
|
|
|
2019-01-15 20:49:53 +00:00
|
|
|
//* Output structure [de]serialization first because it is used by commands.
|
2018-06-08 16:30:50 +00:00
|
|
|
{% for type in by_category["structure"] %}
|
|
|
|
{% set name = as_cType(type.name) %}
|
2019-06-06 16:19:15 +00:00
|
|
|
{% if type.name.CamelCase() not in client_side_structures %}
|
|
|
|
{{write_record_serialization_helpers(type, name, type.members,
|
|
|
|
is_cmd=False)}}
|
|
|
|
{% endif %}
|
2018-06-08 16:30:50 +00:00
|
|
|
{% endfor %}
|
2018-06-06 15:36:49 +00:00
|
|
|
|
2020-04-03 17:37:48 +00:00
|
|
|
size_t GetChainedStructExtraRequiredSize(const WGPUChainedStruct* chainedStruct) {
|
|
|
|
ASSERT(chainedStruct != nullptr);
|
|
|
|
size_t result = 0;
|
|
|
|
while (chainedStruct != nullptr) {
|
|
|
|
switch (chainedStruct->sType) {
|
|
|
|
{% for sType in types["s type"].values if sType.valid and sType.name.CamelCase() not in client_side_structures %}
|
|
|
|
case {{as_cEnum(types["s type"].name, sType.name)}}: {
|
|
|
|
const auto& typedStruct = *reinterpret_cast<{{as_cType(sType.name)}} const *>(chainedStruct);
|
|
|
|
result += sizeof({{as_cType(sType.name)}}Transfer);
|
|
|
|
result += {{as_cType(sType.name)}}GetExtraRequiredSize(typedStruct);
|
|
|
|
chainedStruct = typedStruct.chain.next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
{% endfor %}
|
|
|
|
default:
|
|
|
|
// Invalid enum. Reserve space just for the transfer header (sType and hasNext).
|
|
|
|
result += sizeof(WGPUChainedStructTransfer);
|
2021-02-01 16:48:18 +00:00
|
|
|
chainedStruct = chainedStruct->next;
|
|
|
|
break;
|
2020-04-03 17:37:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SerializeChainedStruct(WGPUChainedStruct const* chainedStruct,
|
|
|
|
char** buffer,
|
|
|
|
const ObjectIdProvider& provider) {
|
|
|
|
ASSERT(chainedStruct != nullptr);
|
|
|
|
ASSERT(buffer != nullptr);
|
|
|
|
do {
|
|
|
|
switch (chainedStruct->sType) {
|
|
|
|
{% 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) %}
|
|
|
|
case {{as_cEnum(types["s type"].name, sType.name)}}: {
|
|
|
|
|
|
|
|
auto* transfer = reinterpret_cast<{{CType}}Transfer*>(*buffer);
|
|
|
|
transfer->chain.sType = chainedStruct->sType;
|
|
|
|
transfer->chain.hasNext = chainedStruct->next != nullptr;
|
|
|
|
|
|
|
|
*buffer += sizeof({{CType}}Transfer);
|
|
|
|
{{CType}}Serialize(*reinterpret_cast<{{CType}} const*>(chainedStruct), transfer, buffer
|
|
|
|
{%- if types[sType.name.get()].may_have_dawn_object -%}
|
|
|
|
, provider
|
|
|
|
{%- endif -%}
|
|
|
|
);
|
|
|
|
|
|
|
|
chainedStruct = chainedStruct->next;
|
|
|
|
} break;
|
|
|
|
{% endfor %}
|
|
|
|
default: {
|
|
|
|
// Invalid enum. Serialize just the transfer header with Invalid as the sType.
|
|
|
|
// TODO(crbug.com/dawn/369): Unknown sTypes are silently discarded.
|
2021-02-01 16:48:18 +00:00
|
|
|
if (chainedStruct->sType != WGPUSType_Invalid) {
|
|
|
|
dawn::WarningLog() << "Unknown sType " << chainedStruct->sType << " discarded.";
|
|
|
|
}
|
|
|
|
|
2020-04-03 17:37:48 +00:00
|
|
|
WGPUChainedStructTransfer* transfer = reinterpret_cast<WGPUChainedStructTransfer*>(*buffer);
|
|
|
|
transfer->sType = WGPUSType_Invalid;
|
2021-02-01 16:48:18 +00:00
|
|
|
transfer->hasNext = chainedStruct->next != nullptr;
|
2020-04-03 17:37:48 +00:00
|
|
|
|
|
|
|
*buffer += sizeof(WGPUChainedStructTransfer);
|
2021-02-01 16:48:18 +00:00
|
|
|
|
|
|
|
// Still move on in case there are valid structs after this.
|
|
|
|
chainedStruct = chainedStruct->next;
|
|
|
|
break;
|
2020-04-03 17:37:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (chainedStruct != nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
DeserializeResult DeserializeChainedStruct(const WGPUChainedStruct** outChainNext,
|
|
|
|
const volatile char** buffer,
|
|
|
|
size_t* size,
|
|
|
|
DeserializeAllocator* allocator,
|
|
|
|
const ObjectIdResolver& resolver) {
|
|
|
|
bool hasNext;
|
|
|
|
do {
|
|
|
|
if (*size < sizeof(WGPUChainedStructTransfer)) {
|
|
|
|
return DeserializeResult::FatalError;
|
|
|
|
}
|
|
|
|
WGPUSType sType =
|
|
|
|
reinterpret_cast<const volatile WGPUChainedStructTransfer*>(*buffer)->sType;
|
|
|
|
switch (sType) {
|
|
|
|
{% 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) %}
|
|
|
|
case {{as_cEnum(types["s type"].name, sType.name)}}: {
|
|
|
|
const volatile {{CType}}Transfer* transfer = nullptr;
|
|
|
|
DESERIALIZE_TRY(GetPtrFromBuffer(buffer, size, 1, &transfer));
|
|
|
|
|
|
|
|
{{CType}}* outStruct = nullptr;
|
|
|
|
DESERIALIZE_TRY(GetSpace(allocator, sizeof({{CType}}), &outStruct));
|
|
|
|
outStruct->chain.sType = sType;
|
|
|
|
outStruct->chain.next = nullptr;
|
|
|
|
|
|
|
|
*outChainNext = &outStruct->chain;
|
|
|
|
outChainNext = &outStruct->chain.next;
|
|
|
|
|
|
|
|
DESERIALIZE_TRY({{CType}}Deserialize(outStruct, transfer, buffer, size, allocator
|
|
|
|
{%- if types[sType.name.get()].may_have_dawn_object -%}
|
|
|
|
, resolver
|
|
|
|
{%- endif -%}
|
|
|
|
));
|
|
|
|
|
|
|
|
hasNext = transfer->chain.hasNext;
|
|
|
|
} break;
|
|
|
|
{% endfor %}
|
2021-02-01 16:48:18 +00:00
|
|
|
default: {
|
|
|
|
// Invalid enum. Deserialize just the transfer header with Invalid as the sType.
|
|
|
|
// TODO(crbug.com/dawn/369): Unknown sTypes are silently discarded.
|
|
|
|
if (sType != WGPUSType_Invalid) {
|
|
|
|
dawn::WarningLog() << "Unknown sType " << sType << " discarded.";
|
|
|
|
}
|
|
|
|
|
|
|
|
const volatile WGPUChainedStructTransfer* transfer = nullptr;
|
|
|
|
DESERIALIZE_TRY(GetPtrFromBuffer(buffer, size, 1, &transfer));
|
|
|
|
|
|
|
|
WGPUChainedStruct* outStruct = nullptr;
|
|
|
|
DESERIALIZE_TRY(GetSpace(allocator, sizeof(WGPUChainedStruct), &outStruct));
|
|
|
|
outStruct->sType = WGPUSType_Invalid;
|
|
|
|
outStruct->next = nullptr;
|
|
|
|
|
|
|
|
// Still move on in case there are valid structs after this.
|
|
|
|
*outChainNext = outStruct;
|
|
|
|
outChainNext = &outStruct->next;
|
|
|
|
hasNext = transfer->hasNext;
|
|
|
|
break;
|
|
|
|
}
|
2020-04-03 17:37:48 +00:00
|
|
|
}
|
|
|
|
} while (hasNext);
|
|
|
|
|
|
|
|
return DeserializeResult::Success;
|
|
|
|
}
|
|
|
|
|
2019-01-15 20:49:53 +00:00
|
|
|
//* Output [de]serialization helpers for commands
|
|
|
|
{% for command in cmd_records["command"] %}
|
|
|
|
{% set name = command.name.CamelCase() %}
|
|
|
|
{{write_record_serialization_helpers(command, name, command.members,
|
2019-04-01 21:04:17 +00:00
|
|
|
is_cmd=True)}}
|
2019-01-15 20:49:53 +00:00
|
|
|
{% endfor %}
|
2018-06-06 15:36:49 +00:00
|
|
|
|
2019-01-15 20:49:53 +00:00
|
|
|
//* Output [de]serialization helpers for return commands
|
|
|
|
{% for command in cmd_records["return command"] %}
|
|
|
|
{% set name = command.name.CamelCase() %}
|
|
|
|
{{write_record_serialization_helpers(command, name, command.members,
|
2019-04-01 21:04:17 +00:00
|
|
|
is_cmd=True, is_return_command=True)}}
|
2018-06-08 16:30:50 +00:00
|
|
|
{% endfor %}
|
|
|
|
} // anonymous namespace
|
2018-06-06 15:36:49 +00:00
|
|
|
|
2019-01-15 20:49:53 +00:00
|
|
|
{% for command in cmd_records["command"] %}
|
|
|
|
{{ write_command_serialization_methods(command, False) }}
|
|
|
|
{% endfor %}
|
2018-06-06 15:36:49 +00:00
|
|
|
|
2019-01-15 20:49:53 +00:00
|
|
|
{% for command in cmd_records["return command"] %}
|
|
|
|
{{ write_command_serialization_methods(command, True) }}
|
2017-04-20 18:43:11 +00:00
|
|
|
{% endfor %}
|
|
|
|
|
2019-10-24 22:27:27 +00:00
|
|
|
// Implementations of serialization/deserialization of WPGUDeviceProperties.
|
|
|
|
size_t SerializedWGPUDevicePropertiesSize(const WGPUDeviceProperties* deviceProperties) {
|
|
|
|
return sizeof(WGPUDeviceProperties) +
|
2019-10-21 20:04:10 +00:00
|
|
|
WGPUDevicePropertiesGetExtraRequiredSize(*deviceProperties);
|
2019-10-20 03:01:56 +00:00
|
|
|
}
|
|
|
|
|
2019-10-24 22:27:27 +00:00
|
|
|
void SerializeWGPUDeviceProperties(const WGPUDeviceProperties* deviceProperties,
|
2019-10-20 03:01:56 +00:00
|
|
|
char* serializeBuffer) {
|
2019-10-21 20:04:10 +00:00
|
|
|
size_t devicePropertiesSize = SerializedWGPUDevicePropertiesSize(deviceProperties);
|
|
|
|
WGPUDevicePropertiesTransfer* transfer =
|
|
|
|
reinterpret_cast<WGPUDevicePropertiesTransfer*>(serializeBuffer);
|
2019-10-20 03:01:56 +00:00
|
|
|
serializeBuffer += devicePropertiesSize;
|
|
|
|
|
2019-10-21 20:04:10 +00:00
|
|
|
WGPUDevicePropertiesSerialize(*deviceProperties, transfer, &serializeBuffer);
|
2019-10-20 03:01:56 +00:00
|
|
|
}
|
|
|
|
|
2019-10-24 22:27:27 +00:00
|
|
|
bool DeserializeWGPUDeviceProperties(WGPUDeviceProperties* deviceProperties,
|
2021-02-02 04:20:09 +00:00
|
|
|
const volatile char* deserializeBuffer,
|
|
|
|
size_t deserializeBufferSize) {
|
2019-10-21 20:04:10 +00:00
|
|
|
const volatile WGPUDevicePropertiesTransfer* transfer = nullptr;
|
2021-02-02 04:20:09 +00:00
|
|
|
if (GetPtrFromBuffer(&deserializeBuffer, &deserializeBufferSize, 1, &transfer) !=
|
2019-10-20 03:01:56 +00:00
|
|
|
DeserializeResult::Success) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-10-21 20:04:10 +00:00
|
|
|
return WGPUDevicePropertiesDeserialize(deviceProperties, transfer, &deserializeBuffer,
|
2021-02-02 04:20:09 +00:00
|
|
|
&deserializeBufferSize,
|
2019-10-20 03:01:56 +00:00
|
|
|
nullptr) == DeserializeResult::Success;
|
|
|
|
}
|
|
|
|
|
2018-07-26 13:07:57 +00:00
|
|
|
} // namespace dawn_wire
|