Bug 1685822 [wpt PR 27117] - [Import Maps] Add tests for rejecting multiple import...
[gecko.git] / dom / canvas / WebGLCommandQueue.h
blob8c168bfec2d6b34249a63ebe19c1cacbc78a9100
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef WEBGLCOMMANDQUEUE_H_
7 #define WEBGLCOMMANDQUEUE_H_
9 #include <type_traits>
10 #include "mozilla/FunctionTypeTraits.h"
11 #include "mozilla/dom/ProducerConsumerQueue.h"
12 #include "mozilla/ipc/IPDLParamTraits.h"
13 #include "QueueParamTraits.h"
14 #include "WebGLTypes.h"
16 // Get around a bug in Clang related to __thiscall method pointers
17 #if defined(_M_IX86)
18 # define SINK_FCN_CC __thiscall
19 #else
20 # define SINK_FCN_CC
21 #endif
23 namespace mozilla {
25 using webgl::QueueStatus;
27 namespace webgl {
29 class RangeConsumerView final : public webgl::ConsumerView<RangeConsumerView> {
30 RangedPtr<const uint8_t> mSrcItr;
31 const RangedPtr<const uint8_t> mSrcEnd;
33 public:
34 auto Remaining() const { return *MaybeAs<size_t>(mSrcEnd - mSrcItr); }
36 explicit RangeConsumerView(const Range<const uint8_t> range)
37 : ConsumerView(this, nullptr, 0),
38 mSrcItr(range.begin()),
39 mSrcEnd(range.end()) {
40 (void)Remaining(); // assert size non-negative
43 void AlignTo(const size_t alignment) {
44 const auto offset = AlignmentOffset(alignment, mSrcItr.get());
45 if (offset > Remaining()) {
46 mSrcItr = mSrcEnd;
47 return;
49 mSrcItr += offset;
52 template <typename T>
53 Maybe<Range<const T>> ReadRange(const size_t elemCount) {
54 AlignTo(alignof(T));
56 constexpr auto elemSize = sizeof(T);
57 const auto byteSizeChecked = CheckedInt<size_t>(elemCount) * elemSize;
58 MOZ_RELEASE_ASSERT(byteSizeChecked.isValid());
59 const auto& byteSize = byteSizeChecked.value();
61 const auto remaining = Remaining();
62 if (byteSize > remaining) return {};
64 const auto begin = reinterpret_cast<const T*>(mSrcItr.get());
65 mSrcItr += byteSize;
66 return Some(Range<const T>{begin, elemCount});
70 // -
72 namespace details {
74 class SizeOnlyProducerView final
75 : public webgl::ProducerView<SizeOnlyProducerView> {
76 size_t mRequiredSize = 0;
78 public:
79 SizeOnlyProducerView() : ProducerView(this, 0, nullptr) {}
81 template <typename T>
82 void WriteFromRange(const Range<const T>& src) {
83 constexpr auto alignment = alignof(T);
84 const size_t byteSize = ByteSize(src);
85 // printf_stderr("SizeOnlyProducerView: @%zu +%zu\n", alignment, byteSize);
87 const auto offset = AlignmentOffset(alignment, mRequiredSize);
88 mRequiredSize += offset;
90 mRequiredSize += byteSize;
93 const auto& RequiredSize() const { return mRequiredSize; }
96 // -
98 class RangeProducerView final : public webgl::ProducerView<RangeProducerView> {
99 const RangedPtr<uint8_t> mDestBegin;
100 const RangedPtr<uint8_t> mDestEnd;
101 RangedPtr<uint8_t> mDestItr;
103 public:
104 auto Remaining() const { return *MaybeAs<size_t>(mDestEnd - mDestItr); }
106 explicit RangeProducerView(const Range<uint8_t> range)
107 : ProducerView(this, 0, nullptr),
108 mDestBegin(range.begin()),
109 mDestEnd(range.end()),
110 mDestItr(mDestBegin) {
111 (void)Remaining(); // assert size non-negative
114 template <typename T>
115 void WriteFromRange(const Range<const T>& src) {
116 constexpr auto alignment = alignof(T);
117 const size_t byteSize = ByteSize(src);
118 // printf_stderr("RangeProducerView: @%zu +%zu\n", alignment, byteSize);
120 const auto offset = AlignmentOffset(alignment, mDestItr.get());
121 mDestItr += offset;
123 MOZ_ASSERT(byteSize <= Remaining());
124 if (byteSize) {
125 memcpy(mDestItr.get(), src.begin().get(), byteSize);
127 mDestItr += byteSize;
131 // -
133 template <typename ProducerViewT>
134 inline void Serialize(ProducerViewT&) {}
136 template <typename ProducerViewT, typename Arg, typename... Args>
137 inline void Serialize(ProducerViewT& view, const Arg& arg,
138 const Args&... args) {
139 MOZ_ALWAYS_TRUE(view.WriteParam(arg) == QueueStatus::kSuccess);
140 Serialize(view, args...);
143 } // namespace details
145 // -
147 template <typename... Args>
148 size_t SerializedSize(const Args&... args) {
149 webgl::details::SizeOnlyProducerView sizeView;
150 webgl::details::Serialize(sizeView, args...);
151 return sizeView.RequiredSize();
154 template <typename... Args>
155 void Serialize(Range<uint8_t> dest, const Args&... args) {
156 webgl::details::RangeProducerView view(dest);
157 webgl::details::Serialize(view, args...);
160 // -
162 inline bool Deserialize(RangeConsumerView& view) { return true; }
164 template <typename Arg, typename... Args>
165 inline bool Deserialize(RangeConsumerView& view, Arg& arg, Args&... args) {
166 if (!webgl::QueueParamTraits<Arg>::Read(view, &arg)) return false;
167 return Deserialize(view, args...);
170 } // namespace webgl
172 // -
174 using mozilla::ipc::IPDLParamTraits;
176 enum CommandResult { kSuccess, kTimeExpired, kQueueEmpty, kError };
178 enum CommandSyncType { ASYNC, SYNC };
181 * A CommandSource is obtained from a CommandQueue. Use it by inserting a
182 * command (represented by type Command) using InsertCommand, which also
183 * needs all parameters to the command. They are then serialized and sent
184 * to the CommandSink, which must understand the Command+Args combination
185 * to execute it.
187 template <typename Command, typename _Source>
188 class CommandSource {
189 using Source = _Source;
191 public:
192 explicit CommandSource(UniquePtr<Source>&& aSource)
193 : mSource(std::move(aSource)) {
194 MOZ_ASSERT(mSource);
197 template <typename... Args>
198 QueueStatus InsertCommand(Command aCommand, Args&&... aArgs) {
199 return this->mSource->TryWaitInsert(Nothing() /* wait forever */, aCommand,
200 aArgs...);
203 QueueStatus InsertCommand(Command aCommand) {
204 return this->mSource->TryWaitInsert(Nothing() /* wait forever */, aCommand);
207 template <typename... Args>
208 QueueStatus RunCommand(Command aCommand, Args&&... aArgs) {
209 return InsertCommand(aCommand, std::forward<Args>(aArgs)...);
212 // For IPDL:
213 CommandSource() = default;
215 protected:
216 friend struct IPDLParamTraits<mozilla::CommandSource<Command, Source>>;
218 UniquePtr<Source> mSource;
222 * A CommandSink is obtained from a CommandQueue. It executes commands that
223 * originated in its CommandSource. Use this class by calling one of the
224 * Process methods, which will autonomously deserialize, dispatch and
225 * post-process the execution. This class handles deserialization -- dispatch
226 * and processing are to be provided by a subclass in its implementation of the
227 * pure-virtual DispatchCommand method. DispatchCommand implementations can
228 * easily run functions and methods using arguments taken from the command
229 * queue by calling the Dispatch methods in this class.
231 template <typename Command, typename _Sink>
232 class CommandSink {
233 using Sink = _Sink;
235 public:
236 explicit CommandSink(UniquePtr<Sink>&& aSink) : mSink(std::move(aSink)) {
237 MOZ_ASSERT(mSink);
241 * Attempts to process the next command in the queue, if one is available.
243 CommandResult ProcessOne(const Maybe<TimeDuration>& aTimeout) {
244 Command command;
245 QueueStatus status = (aTimeout.isNothing() || aTimeout.value())
246 ? this->mSink->TryWaitRemove(aTimeout, command)
247 : this->mSink->TryRemove(command);
249 if (status == QueueStatus::kSuccess) {
250 if (DispatchCommand(command)) {
251 return CommandResult::kSuccess;
253 return CommandResult::kError;
256 if (status == QueueStatus::kNotReady) {
257 return CommandResult::kQueueEmpty;
260 if (status == QueueStatus::kOOMError) {
261 ReportOOM();
263 return CommandResult::kError;
266 CommandResult ProcessOneNow() { return ProcessOne(Some(TimeDuration(0))); }
269 * Drains the queue until the queue is empty or an error occurs, whichever
270 * comes first.
271 * Returns the result of the last attempt to process a command, which will
272 * be either QueueEmpty or Error.
274 CommandResult ProcessAll() {
275 CommandResult result;
276 do {
277 result = ProcessOneNow();
278 } while (result == CommandResult::kSuccess);
279 return result;
283 * Drains the queue until aDuration expires, the queue is empty, or an error
284 * occurs, whichever comes first.
285 * Returns the result of the last attempt to process a command.
287 CommandResult ProcessUpToDuration(TimeDuration aDuration) {
288 TimeStamp start = TimeStamp::Now();
289 TimeStamp now = start;
290 CommandResult result;
292 do {
293 result = ProcessOne(Some(aDuration - (now - start)));
294 now = TimeStamp::Now();
295 } while ((result == CommandResult::kSuccess) &&
296 ((now - start) < aDuration));
297 return result;
300 // For IPDL:
301 CommandSink() = default;
303 // non-void return value, non-const method variant
304 template <typename T, typename ReturnType, typename... Args>
305 bool DispatchAsyncMethod(T& aObj, ReturnType (T::*aMethod)(Args...)) {
306 std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
307 if (!ReadArgs(args)) {
308 return false;
310 CallMethod(aObj, aMethod, args, std::index_sequence_for<Args...>{});
311 return true;
314 // non-void return value, const method variant
315 template <typename T, typename ReturnType, typename... Args>
316 bool DispatchAsyncMethod(const T& aObj,
317 ReturnType (T::*aMethod)(Args...) const) {
318 std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
319 if (!ReadArgs(args)) {
320 return false;
322 CallMethod(aObj, aMethod, args, std::index_sequence_for<Args...>{});
323 return true;
326 // void return value, non-const method variant
327 template <typename T, typename... Args>
328 bool DispatchAsyncMethod(T* aObj, void (T::*aMethod)(Args...)) {
329 std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
330 if (!ReadArgs(args)) {
331 return false;
334 CallVoidMethod(aObj, aMethod, args, std::index_sequence_for<Args...>{});
335 return true;
338 // void return value, const method variant
339 template <typename T, typename... Args>
340 bool DispatchAsyncMethod(const T* aObj, void (T::*aMethod)(Args...) const) {
341 std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
342 if (!ReadArgs(args)) {
343 return false;
346 CallVoidMethod(aObj, aMethod, args, std::index_sequence_for<Args...>{});
347 return true;
350 protected:
351 friend struct IPDLParamTraits<mozilla::CommandSink<Command, Sink>>;
354 * Implementations will usually be something like a big switch statement
355 * that calls one of the Dispatch methods in this class.
357 virtual bool DispatchCommand(Command command) = 0;
360 * Implementations can override this to detect out-of-memory during
361 * deserialization.
363 virtual void ReportOOM() {}
365 template <typename... Args, size_t... Indices>
366 QueueStatus CallTryRemove(std::tuple<Args...>& aArgs,
367 std::index_sequence<Indices...>) {
368 QueueStatus status = mSink->TryRemove(std::get<Indices>(aArgs)...);
369 // The CommandQueue inserts the command and the args together as an atomic
370 // operation. We already read the command so the args must also be
371 // available.
372 MOZ_ASSERT(status != QueueStatus::kNotReady);
373 return status;
376 QueueStatus CallTryRemove(std::tuple<>& aArgs,
377 std::make_integer_sequence<size_t, 0>) {
378 return QueueStatus::kSuccess;
381 template <typename T, typename MethodType, typename... Args,
382 size_t... Indices,
383 typename ReturnType =
384 typename mozilla::FunctionTypeTraits<MethodType>::ReturnType>
385 ReturnType CallMethod(T& aObj, MethodType aMethod, std::tuple<Args...>& aArgs,
386 std::index_sequence<Indices...>) {
387 return (aObj.*aMethod)(std::forward<Args>(std::get<Indices>(aArgs))...);
390 template <typename T, typename MethodType, typename... Args,
391 size_t... Indices>
392 void CallVoidMethod(T& aObj, MethodType aMethod, std::tuple<Args...>& aArgs,
393 std::index_sequence<Indices...>) {
394 (aObj.*aMethod)(std::forward<Args>(std::get<Indices>(aArgs))...);
397 template <typename... Args>
398 bool ReadArgs(std::tuple<Args...>& aArgs) {
399 QueueStatus status =
400 CallTryRemove(aArgs, std::index_sequence_for<Args...>{});
401 return IsSuccess(status);
404 UniquePtr<Sink> mSink;
407 enum SyncResponse : uint8_t { RESPONSE_NAK, RESPONSE_ACK };
410 * This is the Source for a SyncCommandSink. It takes an extra queue,
411 * the ResponseQueue, and uses it to receive synchronous responses from
412 * the sink. The ResponseQueue is a regular queue, not a CommandQueue.
414 template <typename Command, typename _Source, typename _ResponseQueue>
415 class SyncCommandSource : public CommandSource<Command, _Source> {
416 public:
417 using BaseType = CommandSource<Command, _Source>;
418 using Source = _Source;
419 using ResponseQueue = _ResponseQueue;
420 using ResponseSink = typename ResponseQueue::Consumer;
422 SyncCommandSource(UniquePtr<Source>&& aSource,
423 UniquePtr<ResponseSink>&& aResponseSink)
424 : CommandSource<Command, Source>(std::move(aSource)),
425 mResponseSink(std::move(aResponseSink)) {}
427 template <typename... Args>
428 QueueStatus RunAsyncCommand(Command aCommand, Args&&... aArgs) {
429 return this->RunCommand(aCommand, std::forward<Args>(aArgs)...);
432 template <typename... Args>
433 QueueStatus RunVoidSyncCommand(Command aCommand, Args&&... aArgs) {
434 QueueStatus status =
435 RunAsyncCommand(aCommand, std::forward<Args>(aArgs)...);
436 return IsSuccess(status) ? this->ReadSyncResponse() : status;
439 template <typename ResultType, typename... Args>
440 QueueStatus RunSyncCommand(Command aCommand, ResultType& aReturn,
441 Args&&... aArgs) {
442 QueueStatus status =
443 RunVoidSyncCommand(aCommand, std::forward<Args>(aArgs)...);
444 return IsSuccess(status) ? this->ReadResult(aReturn) : status;
447 // for IPDL:
448 SyncCommandSource() = default;
449 friend struct mozilla::ipc::IPDLParamTraits<
450 SyncCommandSource<Command, Source, ResponseQueue>>;
452 protected:
453 QueueStatus ReadSyncResponse() {
454 SyncResponse response;
455 QueueStatus status =
456 mResponseSink->TryWaitRemove(Nothing() /* wait forever */, response);
457 MOZ_ASSERT(status != QueueStatus::kNotReady);
459 if (IsSuccess(status) && response != RESPONSE_ACK) {
460 return QueueStatus::kFatalError;
462 return status;
465 template <typename T>
466 QueueStatus ReadResult(T& aResult) {
467 QueueStatus status = mResponseSink->TryRemove(aResult);
468 // The Sink posts the response code and result as an atomic transaction. We
469 // already read the response code so the result must be available.
470 MOZ_ASSERT(status != QueueStatus::kNotReady);
471 return status;
474 UniquePtr<ResponseSink> mResponseSink;
478 * This is the Sink for a SyncCommandSource. It takes an extra queue, the
479 * ResponseQueue, and uses it to issue synchronous responses to the client.
480 * Subclasses can use the DispatchSync methods in this class in their
481 * DispatchCommand implementations.
482 * The ResponseQueue is not a CommandQueue.
484 template <typename Command, typename _Sink, typename _ResponseQueue>
485 class SyncCommandSink : public CommandSink<Command, _Sink> {
486 using BaseType = CommandSink<Command, _Sink>;
487 using ResponseQueue = _ResponseQueue;
488 using Sink = _Sink;
489 using ResponseSource = typename ResponseQueue::Producer;
491 public:
492 SyncCommandSink(UniquePtr<Sink>&& aSink,
493 UniquePtr<ResponseSource>&& aResponseSource)
494 : CommandSink<Command, Sink>(std::move(aSink)),
495 mResponseSource(std::move(aResponseSource)) {
496 MOZ_ASSERT(mResponseSource);
499 // for IPDL:
500 SyncCommandSink() = default;
501 friend struct mozilla::ipc::IPDLParamTraits<
502 SyncCommandSink<Command, Sink, ResponseQueue>>;
504 // Places RESPONSE_ACK and the typed return value, or RESPONSE_NAK, in
505 // the response queue,
506 // __cdecl/__thiscall non-const method variant.
507 template <typename T, typename ReturnType, typename... Args>
508 bool DispatchSyncMethod(T& aObj,
509 ReturnType SINK_FCN_CC (T::*aMethod)(Args...)) {
510 std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
511 if (!BaseType::ReadArgs(args)) {
512 WriteNAK();
513 return false;
516 ReturnType response = BaseType::CallMethod(
517 aObj, aMethod, args, std::index_sequence_for<Args...>{});
519 return WriteACK(response);
522 // __cdecl/__thiscall const method variant.
523 template <typename T, typename ReturnType, typename... Args>
524 bool DispatchSyncMethod(const T& aObj,
525 ReturnType SINK_FCN_CC (T::*aMethod)(Args...) const) {
526 std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
527 if (!BaseType::ReadArgs(args)) {
528 WriteNAK();
529 return false;
532 ReturnType response = BaseType::CallMethod(
533 aObj, aMethod, args, std::index_sequence_for<Args...>{});
535 return WriteACK(response);
538 #if defined(_M_IX86)
539 // __stdcall non-const method variant.
540 template <typename T, typename ReturnType, typename... Args>
541 bool DispatchSyncMethod(T& aObj,
542 ReturnType __stdcall (T::*aMethod)(Args...)) {
543 std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
544 if (!BaseType::ReadArgs(args)) {
545 WriteNAK();
546 return false;
549 ReturnType response = BaseType::CallMethod(
550 aObj, aMethod, args, std::index_sequence_for<Args...>{});
552 return WriteACK(response);
555 // __stdcall const method variant.
556 template <typename T, typename ReturnType, typename... Args>
557 bool DispatchSyncMethod(const T& aObj,
558 ReturnType __stdcall (T::*aMethod)(Args...) const) {
559 std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
560 if (!BaseType::ReadArgs(args)) {
561 WriteNAK();
562 return false;
565 ReturnType response = BaseType::CallMethod(
566 aObj, aMethod, args, std::index_sequence_for<Args...>{});
568 return WriteACK(response);
570 #endif
572 // __cdecl/__thiscall non-const void method variant
573 template <typename T, typename... Args>
574 bool DispatchSyncMethod(T& aObj, void SINK_FCN_CC (T::*aMethod)(Args...)) {
575 std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
576 if (!BaseType::ReadArgs(args)) {
577 WriteNAK();
578 return false;
581 BaseType::CallVoidMethod(aObj, aMethod, args,
582 std::index_sequence_for<Args...>{});
583 return WriteACK();
586 // __cdecl/__thiscall const void method variant
587 template <typename T, typename... Args>
588 bool DispatchSyncMethod(const T& aObj,
589 void SINK_FCN_CC (T::*aMethod)(Args...) const) {
590 std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
591 if (!BaseType::ReadArgs(args)) {
592 WriteNAK();
593 return false;
596 BaseType::CallVoidMethod(aObj, aMethod, args,
597 std::index_sequence_for<Args...>{});
598 return WriteACK();
601 #if defined(_M_IX86)
602 // __stdcall non-const void method variant
603 template <typename T, typename... Args>
604 bool DispatchSyncMethod(T& aObj, void __stdcall (T::*aMethod)(Args...)) {
605 std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
606 if (!BaseType::ReadArgs(args)) {
607 WriteNAK();
608 return false;
611 BaseType::CallVoidMethod(aObj, aMethod, args,
612 std::index_sequence_for<Args...>{});
613 return WriteACK();
616 // __stdcall const void method variant
617 template <typename T, typename... Args>
618 bool DispatchSyncMethod(const T& aObj,
619 void __stdcall (T::*aMethod)(Args...) const) {
620 std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> args;
621 if (!BaseType::ReadArgs(args)) {
622 WriteNAK();
623 return false;
626 BaseType::CallVoidMethod(aObj, aMethod, args,
627 std::index_sequence_for<Args...>{});
628 return WriteACK();
630 #endif
632 protected:
633 template <typename... Args>
634 bool WriteArgs(const Args&... aArgs) {
635 return IsSuccess(mResponseSource->TryInsert(aArgs...));
638 template <typename... Args>
639 bool WriteACK(const Args&... aArgs) {
640 SyncResponse ack = RESPONSE_ACK;
641 return WriteArgs(ack, aArgs...);
644 bool WriteNAK() {
645 SyncResponse nak = RESPONSE_NAK;
646 return WriteArgs(nak);
649 UniquePtr<ResponseSource> mResponseSource;
652 // The MethodDispatcher setup uses a CommandSink to read parameters, call the
653 // given method using the given synchronization protocol, and provide
654 // compile-time lookup of the ID by class method.
655 // To use this system, first define a dispatcher subclass of
656 // EmptyMethodDispatcher. This class must be parameterized by command ID.
658 // Example:
659 // template <size_t id=0> class MyDispatcher
660 // : public EmptyMethodDispatcher<MyDispatcher> {};
662 // Then, for each command handled, specialize this to subclass MethodDispatcher.
663 // The subclass must define the Method. It may optionally define isSync for
664 // synchronous methods.
666 // Example:
667 // template <>
668 // class MyDispatcher<0>
669 // : public MethodDispatcher<MyDispatcher, 0,
670 // decltype(&MyClass::MyMethod), MyClass::MyMethod,
671 // CommandSyncType::ASYNC> {};
673 // The method may then be called from the source and run on the sink.
675 // Example:
676 // int result = Run<MyClass::MyMethod>(param1, std::move(param2));
678 template <template <size_t> typename Derived>
679 class EmptyMethodDispatcher {
680 public:
681 template <typename ObjectT>
682 static MOZ_ALWAYS_INLINE bool DispatchCommand(ObjectT&, const size_t,
683 webgl::RangeConsumerView&) {
684 MOZ_CRASH("Illegal ID in DispatchCommand");
686 static MOZ_ALWAYS_INLINE CommandSyncType SyncType(size_t) {
687 MOZ_CRASH("Illegal ID in SyncType");
691 // -
693 template <typename ReturnT, typename ObjectT, typename... Args>
694 std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> ArgsTuple(
695 ReturnT (ObjectT::*)(Args... args)) {
696 return std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...>{};
699 template <typename ReturnT, typename ObjectT, typename... Args>
700 std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...> ArgsTuple(
701 ReturnT (ObjectT::*)(Args... args) const) {
702 return std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...>{};
705 // Derived type must be parameterized by the ID.
706 template <template <size_t> typename Derived, size_t ID, typename MethodType,
707 MethodType method, CommandSyncType syncType>
708 class MethodDispatcher {
709 static constexpr size_t kId = ID;
710 using DerivedType = Derived<ID>;
711 using NextDispatcher = Derived<ID + 1>;
713 public:
714 template <typename ObjectT>
715 static MOZ_ALWAYS_INLINE bool DispatchCommand(
716 ObjectT& obj, const size_t id, webgl::RangeConsumerView& view) {
717 if (id == kId) {
718 auto argsTuple = ArgsTuple(method);
720 return std::apply(
721 [&](auto&... args) {
722 if (!webgl::Deserialize(view, args...)) return false;
723 (obj.*method)(args...);
724 return true;
726 argsTuple);
728 return Derived<kId + 1>::DispatchCommand(obj, id, view);
731 static MOZ_ALWAYS_INLINE CommandSyncType SyncType(size_t aId) {
732 return (aId == kId) ? syncType : NextDispatcher::SyncType(kId);
735 static constexpr CommandSyncType SyncType() { return syncType; }
736 static constexpr size_t Id() { return kId; }
737 static constexpr MethodType Method() { return method; }
740 namespace ipc {
741 template <typename T>
742 struct IPDLParamTraits;
744 template <typename Command, typename Source>
745 struct IPDLParamTraits<mozilla::CommandSource<Command, Source>> {
746 public:
747 typedef mozilla::CommandSource<Command, Source> paramType;
749 static void Write(IPC::Message* aMsg, IProtocol* aActor,
750 const paramType& aParam) {
751 WriteIPDLParam(aMsg, aActor, aParam.mSource);
754 static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
755 IProtocol* aActor, paramType* aResult) {
756 return ReadIPDLParam(aMsg, aIter, aActor, &aResult->mSource);
760 template <typename Command, typename Sink>
761 struct IPDLParamTraits<mozilla::CommandSink<Command, Sink>> {
762 public:
763 typedef mozilla::CommandSink<Command, Sink> paramType;
765 static void Write(IPC::Message* aMsg, IProtocol* aActor,
766 const paramType& aParam) {
767 WriteIPDLParam(aMsg, aActor, aParam.mSink);
770 static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
771 IProtocol* aActor, paramType* aResult) {
772 return ReadIPDLParam(aMsg, aIter, aActor, &aResult->mSink);
776 template <typename Command, typename Source, typename ResponseQueue>
777 struct IPDLParamTraits<
778 mozilla::SyncCommandSource<Command, Source, ResponseQueue>>
779 : public IPDLParamTraits<mozilla::CommandSource<Command, Source>> {
780 public:
781 typedef mozilla::SyncCommandSource<Command, Source, ResponseQueue> paramType;
782 typedef typename paramType::BaseType paramBaseType;
784 static void Write(IPC::Message* aMsg, IProtocol* aActor,
785 const paramType& aParam) {
786 WriteIPDLParam(aMsg, aActor, static_cast<const paramBaseType&>(aParam));
787 WriteIPDLParam(aMsg, aActor, aParam.mResponseSink);
790 static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
791 IProtocol* aActor, paramType* aParam) {
792 bool result =
793 ReadIPDLParam(aMsg, aIter, aActor, static_cast<paramBaseType*>(aParam));
794 return result && ReadIPDLParam(aMsg, aIter, aActor, &aParam->mResponseSink);
798 template <typename Command, typename Sink, typename ResponseQueue>
799 struct IPDLParamTraits<mozilla::SyncCommandSink<Command, Sink, ResponseQueue>>
800 : public IPDLParamTraits<mozilla::CommandSink<Command, Sink>> {
801 public:
802 typedef mozilla::SyncCommandSink<Command, Sink, ResponseQueue> paramType;
803 typedef typename paramType::BaseType paramBaseType;
805 static void Write(IPC::Message* aMsg, IProtocol* aActor,
806 const paramType& aParam) {
807 WriteIPDLParam(aMsg, aActor, static_cast<const paramBaseType&>(aParam));
808 WriteIPDLParam(aMsg, aActor, aParam.mResponseSource);
811 static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
812 IProtocol* aActor, paramType* aParam) {
813 bool result =
814 ReadIPDLParam(aMsg, aIter, aActor, static_cast<paramBaseType*>(aParam));
815 return result &&
816 ReadIPDLParam(aMsg, aIter, aActor, &aParam->mResponseSource);
820 } // namespace ipc
822 } // namespace mozilla
824 #endif // WEBGLCOMMANDQUEUE_H_