xref: /qemu/qapi/qapi-forward-visitor.c (revision a976a99a)
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"
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 
248 static bool forward_field_policy_reject(Visitor *v, const char *name,
249                                         unsigned special_features,
250                                         Error **errp)
251 {
252     ForwardFieldVisitor *ffv = to_ffv(v);
253 
254     if (!forward_field_translate_name(ffv, &name, errp)) {
255         return true;
256     }
257     return visit_policy_reject(ffv->target, name, special_features, errp);
258 }
259 
260 static bool forward_field_policy_skip(Visitor *v, const char *name,
261                                       unsigned special_features)
262 {
263     ForwardFieldVisitor *ffv = to_ffv(v);
264 
265     if (!forward_field_translate_name(ffv, &name, NULL)) {
266         return true;
267     }
268     return visit_policy_skip(ffv->target, name, special_features);
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;
317     v->visitor.policy_reject = forward_field_policy_reject;
318     v->visitor.policy_skip = forward_field_policy_skip;
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 }
328