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