blob: 2a33d5b777e438f46524687575ce29b43cf7d1f4 [file] [log] [blame]
// Copyright 2021 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{% set impl_dir = metadata.impl_dir + "/" if metadata.impl_dir else "" %}
{% set namespace_name = Name(metadata.native_namespace) %}
{% set native_namespace = namespace_name.namespace_case() %}
{% set native_dir = impl_dir + namespace_name.Dirs() %}
#include "{{native_dir}}/ChainUtils.h"
#include <tuple>
#include <utility>
namespace {{native_namespace}} {
{% set namespace = metadata.namespace %}
// Returns true iff the chain's SType matches the extension, false otherwise. If the SType was
// not already matched, sets the unpacked result accordingly. Otherwise, stores the duplicated
// SType in 'duplicate'.
template <typename Root, typename UnpackedPtrT, typename Ext>
bool UnpackExtension(typename UnpackedPtrT::TupleType& unpacked,
typename UnpackedPtrT::BitsetType& bitset,
typename UnpackedPtrT::ChainType chain, bool* duplicate) {
DAWN_ASSERT(chain != nullptr);
if (chain->sType == STypeFor<Ext>) {
auto& member = std::get<Ext>(unpacked);
if (member != nullptr && duplicate) {
*duplicate = true;
} else {
member = reinterpret_cast<Ext>(chain);
bitset.set(detail::UnpackedPtrIndexOf<UnpackedPtrT, Ext>);
}
return true;
}
return false;
}
// Tries to match all possible extensions, returning true iff one of the allowed extensions were
// matched, false otherwise. If the SType was not already matched, sets the unpacked result
// accordingly. Otherwise, stores the duplicated SType in 'duplicate'.
template <typename Root, typename UnpackedPtrT, typename AdditionalExts>
struct AdditionalExtensionUnpacker;
template <typename Root, typename UnpackedPtrT, typename... Exts>
struct AdditionalExtensionUnpacker<Root, UnpackedPtrT, detail::AdditionalExtensionsList<Exts...>> {
static bool Unpack(typename UnpackedPtrT::TupleType& unpacked,
typename UnpackedPtrT::BitsetType& bitset,
typename UnpackedPtrT::ChainType chain,
bool* duplicate) {
return ((UnpackExtension<Root, UnpackedPtrT, Exts>(unpacked, bitset, chain, duplicate)) ||
...);
}
};
//
// UnpackedPtr chain helpers.
//
{% for type in by_category["structure"] %}
{% if not type.extensible %}
{% continue %}
{% endif %}
{% set T = as_cppType(type.name) %}
{% set UnpackedPtrT = "UnpackedPtr<" + T + ">" %}
template <>
{{UnpackedPtrT}} Unpack<{{T}}>(typename {{UnpackedPtrT}}::PtrType chain) {
{{UnpackedPtrT}} result(chain);
for (typename {{UnpackedPtrT}}::ChainType next = chain->nextInChain;
next != nullptr;
next = next->nextInChain) {
switch (next->sType) {
{% for extension in type.extensions %}
{% set Ext = as_cppType(extension.name) %}
case STypeFor<{{Ext}}>: {
using ExtPtrType =
typename detail::PtrTypeFor<{{UnpackedPtrT}}, {{Ext}}>::Type;
std::get<ExtPtrType>(result.mUnpacked) =
static_cast<ExtPtrType>(next);
result.mBitset.set(
detail::UnpackedPtrIndexOf<{{UnpackedPtrT}}, ExtPtrType>
);
break;
}
{% endfor %}
default: {
using Unpacker =
AdditionalExtensionUnpacker<
{{T}},
{{UnpackedPtrT}},
detail::AdditionalExtensions<{{T}}>::List>;
Unpacker::Unpack(result.mUnpacked, result.mBitset, next, nullptr);
break;
}
}
}
return result;
}
template <>
ResultOrError<{{UnpackedPtrT}}> ValidateAndUnpack<{{T}}>(
typename {{UnpackedPtrT}}::PtrType chain) {
{{UnpackedPtrT}} result(chain);
for (typename {{UnpackedPtrT}}::ChainType next = chain->nextInChain;
next != nullptr;
next = next->nextInChain) {
bool duplicate = false;
switch (next->sType) {
{% for extension in type.extensions %}
{% set Ext = as_cppType(extension.name) %}
case STypeFor<{{Ext}}>: {
using ExtPtrType =
typename detail::PtrTypeFor<{{UnpackedPtrT}}, {{Ext}}>::Type;
auto& member = std::get<ExtPtrType>(result.mUnpacked);
if (member != nullptr) {
duplicate = true;
} else {
member = static_cast<ExtPtrType>(next);
result.mBitset.set(
detail::UnpackedPtrIndexOf<{{UnpackedPtrT}}, ExtPtrType>
);
}
break;
}
{% endfor %}
default: {
using Unpacker =
AdditionalExtensionUnpacker<
{{T}},
{{UnpackedPtrT}},
detail::AdditionalExtensions<{{T}}>::List>;
if (!Unpacker::Unpack(result.mUnpacked,
result.mBitset,
next,
&duplicate)) {
return DAWN_VALIDATION_ERROR(
"Unexpected chained struct of type %s found on %s chain.",
next->sType, "{{T}}"
);
}
break;
}
}
if (duplicate) {
return DAWN_VALIDATION_ERROR(
"Duplicate chained struct of type %s found on %s chain.",
next->sType, "{{T}}"
);
}
}
return result;
}
{% endfor %}
} // namespace {{native_namespace}}