1 /* RPC call and callback templates
2 Copyright (C) 2014-2023 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>. */
20 #ifndef CC1_PLUGIN_RPC_HH
21 #define CC1_PLUGIN_RPC_HH
24 #include "connection.hh"
29 // The plugin API may contain some "const" method parameters.
30 // However, when unmarshalling we cannot unmarshall into a const
31 // object; and furthermore we want to be able to deallocate pointers
32 // when finished with them. This wrapper class lets us properly
33 // remove the "const" and handle deallocation from pointer types.
36 class argument_wrapper
40 argument_wrapper () { }
41 ~argument_wrapper () { }
43 argument_wrapper (const argument_wrapper
&) = delete;
44 argument_wrapper
&operator= (const argument_wrapper
&) = delete;
46 T
get () const { return m_object
; }
48 status
unmarshall (connection
*conn
)
50 return ::cc1_plugin::unmarshall (conn
, &m_object
);
58 // Specialization for any kind of pointer.
60 class argument_wrapper
<T
*>
63 argument_wrapper () = default;
64 ~argument_wrapper () = default;
66 argument_wrapper (const argument_wrapper
&) = delete;
67 argument_wrapper
&operator= (const argument_wrapper
&) = delete;
69 typedef typename
std::remove_const
<T
>::type type
;
71 const type
*get () const
73 return m_object
.get ();
76 status
unmarshall (connection
*conn
)
79 if (!::cc1_plugin::unmarshall (conn
, &ptr
))
87 unique_ptr
<type
> m_object
;
90 // There are two kinds of template functions here: "call" and
93 // The "call" template is used for making a remote procedure call.
94 // It starts a query ('Q') packet, marshalls its arguments, waits
95 // for a result, and finally reads and returns the result via an
98 // The "invoker" template is used when receiving a remote procedure
99 // call. This template function is suitable for use with the
100 // "callbacks" and "connection" classes. It decodes incoming
101 // arguments, passes them to the wrapped function, and finally
102 // marshalls a reply packet.
104 template<typename R
, typename
... Arg
>
106 call (connection
*conn
, const char *method
, R
*result
, Arg
... args
)
108 if (!conn
->send ('Q'))
110 if (!marshall (conn
, method
))
112 if (!marshall (conn
, (int) sizeof... (Arg
)))
114 if (!marshall (conn
, args
...))
116 if (!conn
->wait_for_result ())
118 if (!unmarshall (conn
, result
))
123 // The base case -- just return OK.
124 template<int I
, typename
... T
>
125 typename
std::enable_if
<I
== sizeof... (T
), status
>::type
126 unmarshall (connection
*, std::tuple
<T
...> &)
131 // Unmarshall this argument, then unmarshall all subsequent args.
132 template<int I
, typename
... T
>
133 typename
std::enable_if
<I
< sizeof... (T
), status
>::type
134 unmarshall (connection
*conn
, std::tuple
<T
...> &value
)
136 if (!std::get
<I
> (value
).unmarshall (conn
))
138 return unmarshall
<I
+ 1, T
...> (conn
, value
);
141 // Wrap a static function that is suitable for use as a callback.
142 // This is a template function inside a template class to work
143 // around limitations with multiple variadic packs.
144 template<typename R
, typename
... Arg
>
147 // Base case -- we can call the function.
148 template<int I
, R
func (connection
*, Arg
...), typename
... T
>
149 static typename
std::enable_if
<I
== sizeof... (Arg
), R
>::type
150 call (connection
*conn
, const std::tuple
<argument_wrapper
<Arg
>...> &,
153 return func (conn
, args
...);
156 // Unpack one argument and continue the recursion.
157 template<int I
, R
func (connection
*, Arg
...), typename
... T
>
158 static typename
std::enable_if
<I
< sizeof... (Arg
), R
>::type
159 call (connection
*conn
, const std::tuple
<argument_wrapper
<Arg
>...> &value
,
162 return call
<I
+ 1, func
> (conn
, value
, args
...,
163 std::get
<I
> (value
).get ());
168 // A callback function that reads arguments from the connection,
169 // calls the wrapped function, and then sends the result back on
171 template<R
func (connection
*, Arg
...)>
173 invoke (connection
*conn
)
175 if (!unmarshall_check (conn
, sizeof... (Arg
)))
177 std::tuple
<argument_wrapper
<Arg
>...> wrapped
;
178 if (!unmarshall
<0> (conn
, wrapped
))
181 R result
= call
<0, func
> (conn
, wrapped
);
183 if (!conn
->send ('R'))
185 return marshall (conn
, result
);
190 #endif // CC1_PLUGIN_RPC_HH