]>
Commit | Line | Data |
---|---|---|
18fa3ebc PB |
1 | /* |
2 | * Forward Visitor | |
3 | * | |
4 | * Copyright (C) 2021 Red Hat, Inc. | |
5 | * | |
6 | * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. | |
7 | * See the COPYING.LIB file in the top-level directory. | |
8 | * | |
9 | */ | |
10 | ||
11 | #include "qemu/osdep.h" | |
12 | #include "qapi/compat-policy.h" | |
13 | #include "qapi/error.h" | |
14 | #include "qapi/forward-visitor.h" | |
15 | #include "qapi/visitor-impl.h" | |
16 | #include "qemu/queue.h" | |
17 | #include "qapi/qmp/qjson.h" | |
18 | #include "qapi/qmp/qbool.h" | |
19 | #include "qapi/qmp/qdict.h" | |
20 | #include "qapi/qmp/qerror.h" | |
21 | #include "qapi/qmp/qlist.h" | |
22 | #include "qapi/qmp/qnull.h" | |
23 | #include "qapi/qmp/qnum.h" | |
24 | #include "qapi/qmp/qstring.h" | |
25 | #include "qemu/cutils.h" | |
18fa3ebc PB |
26 | |
27 | struct ForwardFieldVisitor { | |
28 | Visitor visitor; | |
29 | ||
30 | Visitor *target; | |
31 | char *from; | |
32 | char *to; | |
33 | ||
34 | int depth; | |
35 | }; | |
36 | ||
37 | static ForwardFieldVisitor *to_ffv(Visitor *v) | |
38 | { | |
39 | return container_of(v, ForwardFieldVisitor, visitor); | |
40 | } | |
41 | ||
42 | static bool forward_field_translate_name(ForwardFieldVisitor *v, const char **name, | |
43 | Error **errp) | |
44 | { | |
45 | if (v->depth) { | |
46 | return true; | |
47 | } | |
48 | if (g_str_equal(*name, v->from)) { | |
49 | *name = v->to; | |
50 | return true; | |
51 | } | |
52 | error_setg(errp, QERR_MISSING_PARAMETER, *name); | |
53 | return false; | |
54 | } | |
55 | ||
56 | static bool forward_field_check_struct(Visitor *v, Error **errp) | |
57 | { | |
58 | ForwardFieldVisitor *ffv = to_ffv(v); | |
59 | ||
60 | return visit_check_struct(ffv->target, errp); | |
61 | } | |
62 | ||
63 | static bool forward_field_start_struct(Visitor *v, const char *name, void **obj, | |
64 | size_t size, Error **errp) | |
65 | { | |
66 | ForwardFieldVisitor *ffv = to_ffv(v); | |
67 | ||
68 | if (!forward_field_translate_name(ffv, &name, errp)) { | |
69 | return false; | |
70 | } | |
71 | if (!visit_start_struct(ffv->target, name, obj, size, errp)) { | |
72 | return false; | |
73 | } | |
74 | ffv->depth++; | |
75 | return true; | |
76 | } | |
77 | ||
78 | static void forward_field_end_struct(Visitor *v, void **obj) | |
79 | { | |
80 | ForwardFieldVisitor *ffv = to_ffv(v); | |
81 | ||
82 | assert(ffv->depth); | |
83 | ffv->depth--; | |
84 | visit_end_struct(ffv->target, obj); | |
85 | } | |
86 | ||
87 | static bool forward_field_start_list(Visitor *v, const char *name, | |
88 | GenericList **list, size_t size, | |
89 | Error **errp) | |
90 | { | |
91 | ForwardFieldVisitor *ffv = to_ffv(v); | |
92 | ||
93 | if (!forward_field_translate_name(ffv, &name, errp)) { | |
94 | return false; | |
95 | } | |
96 | ffv->depth++; | |
97 | return visit_start_list(ffv->target, name, list, size, errp); | |
98 | } | |
99 | ||
100 | static GenericList *forward_field_next_list(Visitor *v, GenericList *tail, | |
101 | size_t size) | |
102 | { | |
103 | ForwardFieldVisitor *ffv = to_ffv(v); | |
104 | ||
105 | assert(ffv->depth); | |
106 | return visit_next_list(ffv->target, tail, size); | |
107 | } | |
108 | ||
109 | static bool forward_field_check_list(Visitor *v, Error **errp) | |
110 | { | |
111 | ForwardFieldVisitor *ffv = to_ffv(v); | |
112 | ||
113 | assert(ffv->depth); | |
114 | return visit_check_list(ffv->target, errp); | |
115 | } | |
116 | ||
117 | static void forward_field_end_list(Visitor *v, void **obj) | |
118 | { | |
119 | ForwardFieldVisitor *ffv = to_ffv(v); | |
120 | ||
121 | assert(ffv->depth); | |
122 | ffv->depth--; | |
123 | visit_end_list(ffv->target, obj); | |
124 | } | |
125 | ||
126 | static bool forward_field_start_alternate(Visitor *v, const char *name, | |
127 | GenericAlternate **obj, size_t size, | |
128 | Error **errp) | |
129 | { | |
130 | ForwardFieldVisitor *ffv = to_ffv(v); | |
131 | ||
132 | if (!forward_field_translate_name(ffv, &name, errp)) { | |
133 | return false; | |
134 | } | |
135 | /* | |
136 | * The name passed to start_alternate is used also in the visit_type_* calls | |
137 | * that retrieve the alternate's content; so, do not increase depth here. | |
138 | */ | |
139 | return visit_start_alternate(ffv->target, name, obj, size, errp); | |
140 | } | |
141 | ||
142 | static void forward_field_end_alternate(Visitor *v, void **obj) | |
143 | { | |
144 | ForwardFieldVisitor *ffv = to_ffv(v); | |
145 | ||
146 | visit_end_alternate(ffv->target, obj); | |
147 | } | |
148 | ||
149 | static bool forward_field_type_int64(Visitor *v, const char *name, int64_t *obj, | |
150 | Error **errp) | |
151 | { | |
152 | ForwardFieldVisitor *ffv = to_ffv(v); | |
153 | ||
154 | if (!forward_field_translate_name(ffv, &name, errp)) { | |
155 | return false; | |
156 | } | |
157 | return visit_type_int64(ffv->target, name, obj, errp); | |
158 | } | |
159 | ||
160 | static bool forward_field_type_uint64(Visitor *v, const char *name, | |
161 | uint64_t *obj, Error **errp) | |
162 | { | |
163 | ForwardFieldVisitor *ffv = to_ffv(v); | |
164 | ||
165 | if (!forward_field_translate_name(ffv, &name, errp)) { | |
166 | return false; | |
167 | } | |
168 | return visit_type_uint64(ffv->target, name, obj, errp); | |
169 | } | |
170 | ||
171 | static bool forward_field_type_bool(Visitor *v, const char *name, bool *obj, | |
172 | Error **errp) | |
173 | { | |
174 | ForwardFieldVisitor *ffv = to_ffv(v); | |
175 | ||
176 | if (!forward_field_translate_name(ffv, &name, errp)) { | |
177 | return false; | |
178 | } | |
179 | return visit_type_bool(ffv->target, name, obj, errp); | |
180 | } | |
181 | ||
182 | static bool forward_field_type_str(Visitor *v, const char *name, char **obj, | |
183 | Error **errp) | |
184 | { | |
185 | ForwardFieldVisitor *ffv = to_ffv(v); | |
186 | ||
187 | if (!forward_field_translate_name(ffv, &name, errp)) { | |
188 | return false; | |
189 | } | |
190 | return visit_type_str(ffv->target, name, obj, errp); | |
191 | } | |
192 | ||
193 | static bool forward_field_type_size(Visitor *v, const char *name, uint64_t *obj, | |
194 | Error **errp) | |
195 | { | |
196 | ForwardFieldVisitor *ffv = to_ffv(v); | |
197 | ||
198 | if (!forward_field_translate_name(ffv, &name, errp)) { | |
199 | return false; | |
200 | } | |
201 | return visit_type_size(ffv->target, name, obj, errp); | |
202 | } | |
203 | ||
204 | static bool forward_field_type_number(Visitor *v, const char *name, double *obj, | |
205 | Error **errp) | |
206 | { | |
207 | ForwardFieldVisitor *ffv = to_ffv(v); | |
208 | ||
209 | if (!forward_field_translate_name(ffv, &name, errp)) { | |
210 | return false; | |
211 | } | |
212 | return visit_type_number(ffv->target, name, obj, errp); | |
213 | } | |
214 | ||
215 | static bool forward_field_type_any(Visitor *v, const char *name, QObject **obj, | |
216 | Error **errp) | |
217 | { | |
218 | ForwardFieldVisitor *ffv = to_ffv(v); | |
219 | ||
220 | if (!forward_field_translate_name(ffv, &name, errp)) { | |
221 | return false; | |
222 | } | |
223 | return visit_type_any(ffv->target, name, obj, errp); | |
224 | } | |
225 | ||
226 | static bool forward_field_type_null(Visitor *v, const char *name, | |
227 | QNull **obj, Error **errp) | |
228 | { | |
229 | ForwardFieldVisitor *ffv = to_ffv(v); | |
230 | ||
231 | if (!forward_field_translate_name(ffv, &name, errp)) { | |
232 | return false; | |
233 | } | |
234 | return visit_type_null(ffv->target, name, obj, errp); | |
235 | } | |
236 | ||
237 | static void forward_field_optional(Visitor *v, const char *name, bool *present) | |
238 | { | |
239 | ForwardFieldVisitor *ffv = to_ffv(v); | |
240 | ||
241 | if (!forward_field_translate_name(ffv, &name, NULL)) { | |
242 | *present = false; | |
243 | return; | |
244 | } | |
245 | visit_optional(ffv->target, name, present); | |
246 | } | |
247 | ||
a1307285 MA |
248 | static bool forward_field_policy_reject(Visitor *v, const char *name, |
249 | unsigned special_features, | |
250 | Error **errp) | |
18fa3ebc PB |
251 | { |
252 | ForwardFieldVisitor *ffv = to_ffv(v); | |
253 | ||
254 | if (!forward_field_translate_name(ffv, &name, errp)) { | |
a1307285 | 255 | return true; |
18fa3ebc | 256 | } |
a1307285 | 257 | return visit_policy_reject(ffv->target, name, special_features, errp); |
18fa3ebc PB |
258 | } |
259 | ||
a1307285 MA |
260 | static bool forward_field_policy_skip(Visitor *v, const char *name, |
261 | unsigned special_features) | |
18fa3ebc PB |
262 | { |
263 | ForwardFieldVisitor *ffv = to_ffv(v); | |
264 | ||
265 | if (!forward_field_translate_name(ffv, &name, NULL)) { | |
a1307285 | 266 | return true; |
18fa3ebc | 267 | } |
a1307285 | 268 | return visit_policy_skip(ffv->target, name, special_features); |
18fa3ebc PB |
269 | } |
270 | ||
271 | static void forward_field_complete(Visitor *v, void *opaque) | |
272 | { | |
273 | /* | |
274 | * Do nothing, the complete method will be called in due time | |
275 | * on the target visitor. | |
276 | */ | |
277 | } | |
278 | ||
279 | static void forward_field_free(Visitor *v) | |
280 | { | |
281 | ForwardFieldVisitor *ffv = to_ffv(v); | |
282 | ||
283 | g_free(ffv->from); | |
284 | g_free(ffv->to); | |
285 | g_free(ffv); | |
286 | } | |
287 | ||
288 | Visitor *visitor_forward_field(Visitor *target, const char *from, const char *to) | |
289 | { | |
290 | ForwardFieldVisitor *v = g_new0(ForwardFieldVisitor, 1); | |
291 | ||
292 | /* | |
293 | * Clone and dealloc visitors don't use a name for the toplevel | |
294 | * visit, so they make no sense here. | |
295 | */ | |
296 | assert(target->type == VISITOR_OUTPUT || target->type == VISITOR_INPUT); | |
297 | ||
298 | v->visitor.type = target->type; | |
299 | v->visitor.start_struct = forward_field_start_struct; | |
300 | v->visitor.check_struct = forward_field_check_struct; | |
301 | v->visitor.end_struct = forward_field_end_struct; | |
302 | v->visitor.start_list = forward_field_start_list; | |
303 | v->visitor.next_list = forward_field_next_list; | |
304 | v->visitor.check_list = forward_field_check_list; | |
305 | v->visitor.end_list = forward_field_end_list; | |
306 | v->visitor.start_alternate = forward_field_start_alternate; | |
307 | v->visitor.end_alternate = forward_field_end_alternate; | |
308 | v->visitor.type_int64 = forward_field_type_int64; | |
309 | v->visitor.type_uint64 = forward_field_type_uint64; | |
310 | v->visitor.type_size = forward_field_type_size; | |
311 | v->visitor.type_bool = forward_field_type_bool; | |
312 | v->visitor.type_str = forward_field_type_str; | |
313 | v->visitor.type_number = forward_field_type_number; | |
314 | v->visitor.type_any = forward_field_type_any; | |
315 | v->visitor.type_null = forward_field_type_null; | |
316 | v->visitor.optional = forward_field_optional; | |
a1307285 MA |
317 | v->visitor.policy_reject = forward_field_policy_reject; |
318 | v->visitor.policy_skip = forward_field_policy_skip; | |
18fa3ebc PB |
319 | v->visitor.complete = forward_field_complete; |
320 | v->visitor.free = forward_field_free; | |
321 | ||
322 | v->target = target; | |
323 | v->from = g_strdup(from); | |
324 | v->to = g_strdup(to); | |
325 | ||
326 | return &v->visitor; | |
327 | } |