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_
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
18 # define SINK_FCN_CC __thiscall
25 using webgl::QueueStatus
;
29 class RangeConsumerView final
: public webgl::ConsumerView
<RangeConsumerView
> {
30 RangedPtr
<const uint8_t> mSrcItr
;
31 const RangedPtr
<const uint8_t> mSrcEnd
;
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()) {
53 Maybe
<Range
<const T
>> ReadRange(const size_t elemCount
) {
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());
66 return Some(Range
<const T
>{begin
, elemCount
});
74 class SizeOnlyProducerView final
75 : public webgl::ProducerView
<SizeOnlyProducerView
> {
76 size_t mRequiredSize
= 0;
79 SizeOnlyProducerView() : ProducerView(this, 0, nullptr) {}
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
; }
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
;
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());
123 MOZ_ASSERT(byteSize
<= Remaining());
125 memcpy(mDestItr
.get(), src
.begin().get(), byteSize
);
127 mDestItr
+= byteSize
;
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
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
...);
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
...);
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
187 template <typename Command
, typename _Source
>
188 class CommandSource
{
189 using Source
= _Source
;
192 explicit CommandSource(UniquePtr
<Source
>&& aSource
)
193 : mSource(std::move(aSource
)) {
197 template <typename
... Args
>
198 QueueStatus
InsertCommand(Command aCommand
, Args
&&... aArgs
) {
199 return this->mSource
->TryWaitInsert(Nothing() /* wait forever */, aCommand
,
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
)...);
213 CommandSource() = default;
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
>
236 explicit CommandSink(UniquePtr
<Sink
>&& aSink
) : mSink(std::move(aSink
)) {
241 * Attempts to process the next command in the queue, if one is available.
243 CommandResult
ProcessOne(const Maybe
<TimeDuration
>& aTimeout
) {
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
) {
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
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
;
277 result
= ProcessOneNow();
278 } while (result
== CommandResult::kSuccess
);
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
;
293 result
= ProcessOne(Some(aDuration
- (now
- start
)));
294 now
= TimeStamp::Now();
295 } while ((result
== CommandResult::kSuccess
) &&
296 ((now
- start
) < aDuration
));
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
)) {
310 CallMethod(aObj
, aMethod
, args
, std::index_sequence_for
<Args
...>{});
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
)) {
322 CallMethod(aObj
, aMethod
, args
, std::index_sequence_for
<Args
...>{});
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
)) {
334 CallVoidMethod(aObj
, aMethod
, args
, std::index_sequence_for
<Args
...>{});
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
)) {
346 CallVoidMethod(aObj
, aMethod
, args
, std::index_sequence_for
<Args
...>{});
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
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
372 MOZ_ASSERT(status
!= QueueStatus::kNotReady
);
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
,
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
,
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
) {
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
> {
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
) {
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
,
443 RunVoidSyncCommand(aCommand
, std::forward
<Args
>(aArgs
)...);
444 return IsSuccess(status
) ? this->ReadResult(aReturn
) : status
;
448 SyncCommandSource() = default;
449 friend struct mozilla::ipc::IPDLParamTraits
<
450 SyncCommandSource
<Command
, Source
, ResponseQueue
>>;
453 QueueStatus
ReadSyncResponse() {
454 SyncResponse response
;
456 mResponseSink
->TryWaitRemove(Nothing() /* wait forever */, response
);
457 MOZ_ASSERT(status
!= QueueStatus::kNotReady
);
459 if (IsSuccess(status
) && response
!= RESPONSE_ACK
) {
460 return QueueStatus::kFatalError
;
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
);
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
;
489 using ResponseSource
= typename
ResponseQueue::Producer
;
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
);
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
)) {
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
)) {
532 ReturnType response
= BaseType::CallMethod(
533 aObj
, aMethod
, args
, std::index_sequence_for
<Args
...>{});
535 return WriteACK(response
);
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
)) {
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
)) {
565 ReturnType response
= BaseType::CallMethod(
566 aObj
, aMethod
, args
, std::index_sequence_for
<Args
...>{});
568 return WriteACK(response
);
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
)) {
581 BaseType::CallVoidMethod(aObj
, aMethod
, args
,
582 std::index_sequence_for
<Args
...>{});
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
)) {
596 BaseType::CallVoidMethod(aObj
, aMethod
, args
,
597 std::index_sequence_for
<Args
...>{});
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
)) {
611 BaseType::CallVoidMethod(aObj
, aMethod
, args
,
612 std::index_sequence_for
<Args
...>{});
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
)) {
626 BaseType::CallVoidMethod(aObj
, aMethod
, args
,
627 std::index_sequence_for
<Args
...>{});
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
...);
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.
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.
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.
676 // int result = Run<MyClass::MyMethod>(param1, std::move(param2));
678 template <template <size_t> typename Derived
>
679 class EmptyMethodDispatcher
{
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");
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>;
714 template <typename ObjectT
>
715 static MOZ_ALWAYS_INLINE
bool DispatchCommand(
716 ObjectT
& obj
, const size_t id
, webgl::RangeConsumerView
& view
) {
718 auto argsTuple
= ArgsTuple(method
);
722 if (!webgl::Deserialize(view
, args
...)) return false;
723 (obj
.*method
)(args
...);
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
; }
741 template <typename T
>
742 struct IPDLParamTraits
;
744 template <typename Command
, typename Source
>
745 struct IPDLParamTraits
<mozilla::CommandSource
<Command
, Source
>> {
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
>> {
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
>> {
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
) {
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
>> {
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
) {
814 ReadIPDLParam(aMsg
, aIter
, aActor
, static_cast<paramBaseType
*>(aParam
));
816 ReadIPDLParam(aMsg
, aIter
, aActor
, &aParam
->mResponseSource
);
822 } // namespace mozilla
824 #endif // WEBGLCOMMANDQUEUE_H_