Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1/* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2016-2018 NXP
3 * Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com>
4 */
5#ifndef _LINUX_PACKING_H
6#define _LINUX_PACKING_H
7
8#include <linux/array_size.h>
9#include <linux/bitops.h>
10#include <linux/build_bug.h>
11#include <linux/minmax.h>
12#include <linux/stddef.h>
13#include <linux/types.h>
14
15#define GEN_PACKED_FIELD_STRUCT(__type) \
16 struct packed_field_ ## __type { \
17 __type startbit; \
18 __type endbit; \
19 __type offset; \
20 __type size; \
21 }
22
23/* struct packed_field_u8. Use with bit offsets < 256, buffers < 32B and
24 * unpacked structures < 256B.
25 */
26GEN_PACKED_FIELD_STRUCT(u8);
27
28/* struct packed_field_u16. Use with bit offsets < 65536, buffers < 8KB and
29 * unpacked structures < 64KB.
30 */
31GEN_PACKED_FIELD_STRUCT(u16);
32
33#define PACKED_FIELD(start, end, struct_name, struct_field) \
34{ \
35 (start), \
36 (end), \
37 offsetof(struct_name, struct_field), \
38 sizeof_field(struct_name, struct_field), \
39}
40
41#define CHECK_PACKED_FIELD_OVERLAP(fields, index1, index2) ({ \
42 typeof(&(fields)[0]) __f = (fields); \
43 typeof(__f[0]) _f1 = __f[index1]; typeof(__f[0]) _f2 = __f[index2]; \
44 const bool _ascending = __f[0].startbit < __f[1].startbit; \
45 BUILD_BUG_ON_MSG(_ascending && _f1.startbit >= _f2.startbit, \
46 __stringify(fields) " field " __stringify(index2) \
47 " breaks ascending order"); \
48 BUILD_BUG_ON_MSG(!_ascending && _f1.startbit <= _f2.startbit, \
49 __stringify(fields) " field " __stringify(index2) \
50 " breaks descending order"); \
51 BUILD_BUG_ON_MSG(max(_f1.endbit, _f2.endbit) <= \
52 min(_f1.startbit, _f2.startbit), \
53 __stringify(fields) " field " __stringify(index2) \
54 " overlaps with previous field"); \
55})
56
57#define CHECK_PACKED_FIELD(fields, index) ({ \
58 typeof(&(fields)[0]) _f = (fields); \
59 typeof(_f[0]) __f = _f[index]; \
60 BUILD_BUG_ON_MSG(__f.startbit < __f.endbit, \
61 __stringify(fields) " field " __stringify(index) \
62 " start bit must not be smaller than end bit"); \
63 BUILD_BUG_ON_MSG(__f.size != 1 && __f.size != 2 && \
64 __f.size != 4 && __f.size != 8, \
65 __stringify(fields) " field " __stringify(index) \
66 " has unsupported unpacked storage size"); \
67 BUILD_BUG_ON_MSG(__f.startbit - __f.endbit >= BITS_PER_BYTE * __f.size, \
68 __stringify(fields) " field " __stringify(index) \
69 " exceeds unpacked storage size"); \
70 __builtin_choose_expr(index != 0, \
71 CHECK_PACKED_FIELD_OVERLAP(fields, index - 1, index), \
72 1); \
73})
74
75/* Note that the packed fields may be either in ascending or descending order.
76 * Thus, we must check that both the first and last field wit within the
77 * packed buffer size.
78 */
79#define CHECK_PACKED_FIELDS_SIZE(fields, pbuflen) ({ \
80 typeof(&(fields)[0]) _f = (fields); \
81 typeof(pbuflen) _len = (pbuflen); \
82 const size_t num_fields = ARRAY_SIZE(fields); \
83 BUILD_BUG_ON_MSG(!__builtin_constant_p(_len), \
84 __stringify(fields) " pbuflen " __stringify(pbuflen) \
85 " must be a compile time constant"); \
86 BUILD_BUG_ON_MSG(_f[0].startbit >= BITS_PER_BYTE * _len, \
87 __stringify(fields) " first field exceeds packed buffer size"); \
88 BUILD_BUG_ON_MSG(_f[num_fields - 1].startbit >= BITS_PER_BYTE * _len, \
89 __stringify(fields) " last field exceeds packed buffer size"); \
90})
91
92#define QUIRK_MSB_ON_THE_RIGHT BIT(0)
93#define QUIRK_LITTLE_ENDIAN BIT(1)
94#define QUIRK_LSW32_IS_FIRST BIT(2)
95
96enum packing_op {
97 PACK,
98 UNPACK,
99};
100
101int packing(void *pbuf, u64 *uval, int startbit, int endbit, size_t pbuflen,
102 enum packing_op op, u8 quirks);
103
104int pack(void *pbuf, u64 uval, size_t startbit, size_t endbit, size_t pbuflen,
105 u8 quirks);
106
107int unpack(const void *pbuf, u64 *uval, size_t startbit, size_t endbit,
108 size_t pbuflen, u8 quirks);
109
110void pack_fields_u8(void *pbuf, size_t pbuflen, const void *ustruct,
111 const struct packed_field_u8 *fields, size_t num_fields,
112 u8 quirks);
113
114void pack_fields_u16(void *pbuf, size_t pbuflen, const void *ustruct,
115 const struct packed_field_u16 *fields, size_t num_fields,
116 u8 quirks);
117
118void unpack_fields_u8(const void *pbuf, size_t pbuflen, void *ustruct,
119 const struct packed_field_u8 *fields, size_t num_fields,
120 u8 quirks);
121
122void unpack_fields_u16(const void *pbuf, size_t pbuflen, void *ustruct,
123 const struct packed_field_u16 *fields, size_t num_fields,
124 u8 quirks);
125
126/* Do not hand-edit the following packed field check macros!
127 *
128 * They are generated using scripts/gen_packed_field_checks.c, which may be
129 * built via "make scripts_gen_packed_field_checks". If larger macro sizes are
130 * needed in the future, please use this program to re-generate the macros and
131 * insert them here.
132 */
133
134#define CHECK_PACKED_FIELDS_1(fields) \
135 CHECK_PACKED_FIELD(fields, 0)
136
137#define CHECK_PACKED_FIELDS_2(fields) do { \
138 CHECK_PACKED_FIELDS_1(fields); \
139 CHECK_PACKED_FIELD(fields, 1); \
140} while (0)
141
142#define CHECK_PACKED_FIELDS_3(fields) do { \
143 CHECK_PACKED_FIELDS_2(fields); \
144 CHECK_PACKED_FIELD(fields, 2); \
145} while (0)
146
147#define CHECK_PACKED_FIELDS_4(fields) do { \
148 CHECK_PACKED_FIELDS_3(fields); \
149 CHECK_PACKED_FIELD(fields, 3); \
150} while (0)
151
152#define CHECK_PACKED_FIELDS_5(fields) do { \
153 CHECK_PACKED_FIELDS_4(fields); \
154 CHECK_PACKED_FIELD(fields, 4); \
155} while (0)
156
157#define CHECK_PACKED_FIELDS_6(fields) do { \
158 CHECK_PACKED_FIELDS_5(fields); \
159 CHECK_PACKED_FIELD(fields, 5); \
160} while (0)
161
162#define CHECK_PACKED_FIELDS_7(fields) do { \
163 CHECK_PACKED_FIELDS_6(fields); \
164 CHECK_PACKED_FIELD(fields, 6); \
165} while (0)
166
167#define CHECK_PACKED_FIELDS_8(fields) do { \
168 CHECK_PACKED_FIELDS_7(fields); \
169 CHECK_PACKED_FIELD(fields, 7); \
170} while (0)
171
172#define CHECK_PACKED_FIELDS_9(fields) do { \
173 CHECK_PACKED_FIELDS_8(fields); \
174 CHECK_PACKED_FIELD(fields, 8); \
175} while (0)
176
177#define CHECK_PACKED_FIELDS_10(fields) do { \
178 CHECK_PACKED_FIELDS_9(fields); \
179 CHECK_PACKED_FIELD(fields, 9); \
180} while (0)
181
182#define CHECK_PACKED_FIELDS_11(fields) do { \
183 CHECK_PACKED_FIELDS_10(fields); \
184 CHECK_PACKED_FIELD(fields, 10); \
185} while (0)
186
187#define CHECK_PACKED_FIELDS_12(fields) do { \
188 CHECK_PACKED_FIELDS_11(fields); \
189 CHECK_PACKED_FIELD(fields, 11); \
190} while (0)
191
192#define CHECK_PACKED_FIELDS_13(fields) do { \
193 CHECK_PACKED_FIELDS_12(fields); \
194 CHECK_PACKED_FIELD(fields, 12); \
195} while (0)
196
197#define CHECK_PACKED_FIELDS_14(fields) do { \
198 CHECK_PACKED_FIELDS_13(fields); \
199 CHECK_PACKED_FIELD(fields, 13); \
200} while (0)
201
202#define CHECK_PACKED_FIELDS_15(fields) do { \
203 CHECK_PACKED_FIELDS_14(fields); \
204 CHECK_PACKED_FIELD(fields, 14); \
205} while (0)
206
207#define CHECK_PACKED_FIELDS_16(fields) do { \
208 CHECK_PACKED_FIELDS_15(fields); \
209 CHECK_PACKED_FIELD(fields, 15); \
210} while (0)
211
212#define CHECK_PACKED_FIELDS_17(fields) do { \
213 CHECK_PACKED_FIELDS_16(fields); \
214 CHECK_PACKED_FIELD(fields, 16); \
215} while (0)
216
217#define CHECK_PACKED_FIELDS_18(fields) do { \
218 CHECK_PACKED_FIELDS_17(fields); \
219 CHECK_PACKED_FIELD(fields, 17); \
220} while (0)
221
222#define CHECK_PACKED_FIELDS_19(fields) do { \
223 CHECK_PACKED_FIELDS_18(fields); \
224 CHECK_PACKED_FIELD(fields, 18); \
225} while (0)
226
227#define CHECK_PACKED_FIELDS_20(fields) do { \
228 CHECK_PACKED_FIELDS_19(fields); \
229 CHECK_PACKED_FIELD(fields, 19); \
230} while (0)
231
232#define CHECK_PACKED_FIELDS_21(fields) do { \
233 CHECK_PACKED_FIELDS_20(fields); \
234 CHECK_PACKED_FIELD(fields, 20); \
235} while (0)
236
237#define CHECK_PACKED_FIELDS_22(fields) do { \
238 CHECK_PACKED_FIELDS_21(fields); \
239 CHECK_PACKED_FIELD(fields, 21); \
240} while (0)
241
242#define CHECK_PACKED_FIELDS_23(fields) do { \
243 CHECK_PACKED_FIELDS_22(fields); \
244 CHECK_PACKED_FIELD(fields, 22); \
245} while (0)
246
247#define CHECK_PACKED_FIELDS_24(fields) do { \
248 CHECK_PACKED_FIELDS_23(fields); \
249 CHECK_PACKED_FIELD(fields, 23); \
250} while (0)
251
252#define CHECK_PACKED_FIELDS_25(fields) do { \
253 CHECK_PACKED_FIELDS_24(fields); \
254 CHECK_PACKED_FIELD(fields, 24); \
255} while (0)
256
257#define CHECK_PACKED_FIELDS_26(fields) do { \
258 CHECK_PACKED_FIELDS_25(fields); \
259 CHECK_PACKED_FIELD(fields, 25); \
260} while (0)
261
262#define CHECK_PACKED_FIELDS_27(fields) do { \
263 CHECK_PACKED_FIELDS_26(fields); \
264 CHECK_PACKED_FIELD(fields, 26); \
265} while (0)
266
267#define CHECK_PACKED_FIELDS_28(fields) do { \
268 CHECK_PACKED_FIELDS_27(fields); \
269 CHECK_PACKED_FIELD(fields, 27); \
270} while (0)
271
272#define CHECK_PACKED_FIELDS_29(fields) do { \
273 CHECK_PACKED_FIELDS_28(fields); \
274 CHECK_PACKED_FIELD(fields, 28); \
275} while (0)
276
277#define CHECK_PACKED_FIELDS_30(fields) do { \
278 CHECK_PACKED_FIELDS_29(fields); \
279 CHECK_PACKED_FIELD(fields, 29); \
280} while (0)
281
282#define CHECK_PACKED_FIELDS_31(fields) do { \
283 CHECK_PACKED_FIELDS_30(fields); \
284 CHECK_PACKED_FIELD(fields, 30); \
285} while (0)
286
287#define CHECK_PACKED_FIELDS_32(fields) do { \
288 CHECK_PACKED_FIELDS_31(fields); \
289 CHECK_PACKED_FIELD(fields, 31); \
290} while (0)
291
292#define CHECK_PACKED_FIELDS_33(fields) do { \
293 CHECK_PACKED_FIELDS_32(fields); \
294 CHECK_PACKED_FIELD(fields, 32); \
295} while (0)
296
297#define CHECK_PACKED_FIELDS_34(fields) do { \
298 CHECK_PACKED_FIELDS_33(fields); \
299 CHECK_PACKED_FIELD(fields, 33); \
300} while (0)
301
302#define CHECK_PACKED_FIELDS_35(fields) do { \
303 CHECK_PACKED_FIELDS_34(fields); \
304 CHECK_PACKED_FIELD(fields, 34); \
305} while (0)
306
307#define CHECK_PACKED_FIELDS_36(fields) do { \
308 CHECK_PACKED_FIELDS_35(fields); \
309 CHECK_PACKED_FIELD(fields, 35); \
310} while (0)
311
312#define CHECK_PACKED_FIELDS_37(fields) do { \
313 CHECK_PACKED_FIELDS_36(fields); \
314 CHECK_PACKED_FIELD(fields, 36); \
315} while (0)
316
317#define CHECK_PACKED_FIELDS_38(fields) do { \
318 CHECK_PACKED_FIELDS_37(fields); \
319 CHECK_PACKED_FIELD(fields, 37); \
320} while (0)
321
322#define CHECK_PACKED_FIELDS_39(fields) do { \
323 CHECK_PACKED_FIELDS_38(fields); \
324 CHECK_PACKED_FIELD(fields, 38); \
325} while (0)
326
327#define CHECK_PACKED_FIELDS_40(fields) do { \
328 CHECK_PACKED_FIELDS_39(fields); \
329 CHECK_PACKED_FIELD(fields, 39); \
330} while (0)
331
332#define CHECK_PACKED_FIELDS_41(fields) do { \
333 CHECK_PACKED_FIELDS_40(fields); \
334 CHECK_PACKED_FIELD(fields, 40); \
335} while (0)
336
337#define CHECK_PACKED_FIELDS_42(fields) do { \
338 CHECK_PACKED_FIELDS_41(fields); \
339 CHECK_PACKED_FIELD(fields, 41); \
340} while (0)
341
342#define CHECK_PACKED_FIELDS_43(fields) do { \
343 CHECK_PACKED_FIELDS_42(fields); \
344 CHECK_PACKED_FIELD(fields, 42); \
345} while (0)
346
347#define CHECK_PACKED_FIELDS_44(fields) do { \
348 CHECK_PACKED_FIELDS_43(fields); \
349 CHECK_PACKED_FIELD(fields, 43); \
350} while (0)
351
352#define CHECK_PACKED_FIELDS_45(fields) do { \
353 CHECK_PACKED_FIELDS_44(fields); \
354 CHECK_PACKED_FIELD(fields, 44); \
355} while (0)
356
357#define CHECK_PACKED_FIELDS_46(fields) do { \
358 CHECK_PACKED_FIELDS_45(fields); \
359 CHECK_PACKED_FIELD(fields, 45); \
360} while (0)
361
362#define CHECK_PACKED_FIELDS_47(fields) do { \
363 CHECK_PACKED_FIELDS_46(fields); \
364 CHECK_PACKED_FIELD(fields, 46); \
365} while (0)
366
367#define CHECK_PACKED_FIELDS_48(fields) do { \
368 CHECK_PACKED_FIELDS_47(fields); \
369 CHECK_PACKED_FIELD(fields, 47); \
370} while (0)
371
372#define CHECK_PACKED_FIELDS_49(fields) do { \
373 CHECK_PACKED_FIELDS_48(fields); \
374 CHECK_PACKED_FIELD(fields, 48); \
375} while (0)
376
377#define CHECK_PACKED_FIELDS_50(fields) do { \
378 CHECK_PACKED_FIELDS_49(fields); \
379 CHECK_PACKED_FIELD(fields, 49); \
380} while (0)
381
382#define CHECK_PACKED_FIELDS(fields) \
383 __builtin_choose_expr(ARRAY_SIZE(fields) == 1, ({ CHECK_PACKED_FIELDS_1(fields); }), \
384 __builtin_choose_expr(ARRAY_SIZE(fields) == 2, ({ CHECK_PACKED_FIELDS_2(fields); }), \
385 __builtin_choose_expr(ARRAY_SIZE(fields) == 3, ({ CHECK_PACKED_FIELDS_3(fields); }), \
386 __builtin_choose_expr(ARRAY_SIZE(fields) == 4, ({ CHECK_PACKED_FIELDS_4(fields); }), \
387 __builtin_choose_expr(ARRAY_SIZE(fields) == 5, ({ CHECK_PACKED_FIELDS_5(fields); }), \
388 __builtin_choose_expr(ARRAY_SIZE(fields) == 6, ({ CHECK_PACKED_FIELDS_6(fields); }), \
389 __builtin_choose_expr(ARRAY_SIZE(fields) == 7, ({ CHECK_PACKED_FIELDS_7(fields); }), \
390 __builtin_choose_expr(ARRAY_SIZE(fields) == 8, ({ CHECK_PACKED_FIELDS_8(fields); }), \
391 __builtin_choose_expr(ARRAY_SIZE(fields) == 9, ({ CHECK_PACKED_FIELDS_9(fields); }), \
392 __builtin_choose_expr(ARRAY_SIZE(fields) == 10, ({ CHECK_PACKED_FIELDS_10(fields); }), \
393 __builtin_choose_expr(ARRAY_SIZE(fields) == 11, ({ CHECK_PACKED_FIELDS_11(fields); }), \
394 __builtin_choose_expr(ARRAY_SIZE(fields) == 12, ({ CHECK_PACKED_FIELDS_12(fields); }), \
395 __builtin_choose_expr(ARRAY_SIZE(fields) == 13, ({ CHECK_PACKED_FIELDS_13(fields); }), \
396 __builtin_choose_expr(ARRAY_SIZE(fields) == 14, ({ CHECK_PACKED_FIELDS_14(fields); }), \
397 __builtin_choose_expr(ARRAY_SIZE(fields) == 15, ({ CHECK_PACKED_FIELDS_15(fields); }), \
398 __builtin_choose_expr(ARRAY_SIZE(fields) == 16, ({ CHECK_PACKED_FIELDS_16(fields); }), \
399 __builtin_choose_expr(ARRAY_SIZE(fields) == 17, ({ CHECK_PACKED_FIELDS_17(fields); }), \
400 __builtin_choose_expr(ARRAY_SIZE(fields) == 18, ({ CHECK_PACKED_FIELDS_18(fields); }), \
401 __builtin_choose_expr(ARRAY_SIZE(fields) == 19, ({ CHECK_PACKED_FIELDS_19(fields); }), \
402 __builtin_choose_expr(ARRAY_SIZE(fields) == 20, ({ CHECK_PACKED_FIELDS_20(fields); }), \
403 __builtin_choose_expr(ARRAY_SIZE(fields) == 21, ({ CHECK_PACKED_FIELDS_21(fields); }), \
404 __builtin_choose_expr(ARRAY_SIZE(fields) == 22, ({ CHECK_PACKED_FIELDS_22(fields); }), \
405 __builtin_choose_expr(ARRAY_SIZE(fields) == 23, ({ CHECK_PACKED_FIELDS_23(fields); }), \
406 __builtin_choose_expr(ARRAY_SIZE(fields) == 24, ({ CHECK_PACKED_FIELDS_24(fields); }), \
407 __builtin_choose_expr(ARRAY_SIZE(fields) == 25, ({ CHECK_PACKED_FIELDS_25(fields); }), \
408 __builtin_choose_expr(ARRAY_SIZE(fields) == 26, ({ CHECK_PACKED_FIELDS_26(fields); }), \
409 __builtin_choose_expr(ARRAY_SIZE(fields) == 27, ({ CHECK_PACKED_FIELDS_27(fields); }), \
410 __builtin_choose_expr(ARRAY_SIZE(fields) == 28, ({ CHECK_PACKED_FIELDS_28(fields); }), \
411 __builtin_choose_expr(ARRAY_SIZE(fields) == 29, ({ CHECK_PACKED_FIELDS_29(fields); }), \
412 __builtin_choose_expr(ARRAY_SIZE(fields) == 30, ({ CHECK_PACKED_FIELDS_30(fields); }), \
413 __builtin_choose_expr(ARRAY_SIZE(fields) == 31, ({ CHECK_PACKED_FIELDS_31(fields); }), \
414 __builtin_choose_expr(ARRAY_SIZE(fields) == 32, ({ CHECK_PACKED_FIELDS_32(fields); }), \
415 __builtin_choose_expr(ARRAY_SIZE(fields) == 33, ({ CHECK_PACKED_FIELDS_33(fields); }), \
416 __builtin_choose_expr(ARRAY_SIZE(fields) == 34, ({ CHECK_PACKED_FIELDS_34(fields); }), \
417 __builtin_choose_expr(ARRAY_SIZE(fields) == 35, ({ CHECK_PACKED_FIELDS_35(fields); }), \
418 __builtin_choose_expr(ARRAY_SIZE(fields) == 36, ({ CHECK_PACKED_FIELDS_36(fields); }), \
419 __builtin_choose_expr(ARRAY_SIZE(fields) == 37, ({ CHECK_PACKED_FIELDS_37(fields); }), \
420 __builtin_choose_expr(ARRAY_SIZE(fields) == 38, ({ CHECK_PACKED_FIELDS_38(fields); }), \
421 __builtin_choose_expr(ARRAY_SIZE(fields) == 39, ({ CHECK_PACKED_FIELDS_39(fields); }), \
422 __builtin_choose_expr(ARRAY_SIZE(fields) == 40, ({ CHECK_PACKED_FIELDS_40(fields); }), \
423 __builtin_choose_expr(ARRAY_SIZE(fields) == 41, ({ CHECK_PACKED_FIELDS_41(fields); }), \
424 __builtin_choose_expr(ARRAY_SIZE(fields) == 42, ({ CHECK_PACKED_FIELDS_42(fields); }), \
425 __builtin_choose_expr(ARRAY_SIZE(fields) == 43, ({ CHECK_PACKED_FIELDS_43(fields); }), \
426 __builtin_choose_expr(ARRAY_SIZE(fields) == 44, ({ CHECK_PACKED_FIELDS_44(fields); }), \
427 __builtin_choose_expr(ARRAY_SIZE(fields) == 45, ({ CHECK_PACKED_FIELDS_45(fields); }), \
428 __builtin_choose_expr(ARRAY_SIZE(fields) == 46, ({ CHECK_PACKED_FIELDS_46(fields); }), \
429 __builtin_choose_expr(ARRAY_SIZE(fields) == 47, ({ CHECK_PACKED_FIELDS_47(fields); }), \
430 __builtin_choose_expr(ARRAY_SIZE(fields) == 48, ({ CHECK_PACKED_FIELDS_48(fields); }), \
431 __builtin_choose_expr(ARRAY_SIZE(fields) == 49, ({ CHECK_PACKED_FIELDS_49(fields); }), \
432 __builtin_choose_expr(ARRAY_SIZE(fields) == 50, ({ CHECK_PACKED_FIELDS_50(fields); }), \
433 ({ BUILD_BUG_ON_MSG(1, "CHECK_PACKED_FIELDS() must be regenerated to support array sizes larger than 50."); }) \
434))))))))))))))))))))))))))))))))))))))))))))))))))
435
436/* End of generated content */
437
438#define pack_fields(pbuf, pbuflen, ustruct, fields, quirks) \
439 ({ \
440 CHECK_PACKED_FIELDS(fields); \
441 CHECK_PACKED_FIELDS_SIZE((fields), (pbuflen)); \
442 _Generic((fields), \
443 const struct packed_field_u8 * : pack_fields_u8, \
444 const struct packed_field_u16 * : pack_fields_u16 \
445 )((pbuf), (pbuflen), (ustruct), (fields), ARRAY_SIZE(fields), (quirks)); \
446 })
447
448#define unpack_fields(pbuf, pbuflen, ustruct, fields, quirks) \
449 ({ \
450 CHECK_PACKED_FIELDS(fields); \
451 CHECK_PACKED_FIELDS_SIZE((fields), (pbuflen)); \
452 _Generic((fields), \
453 const struct packed_field_u8 * : unpack_fields_u8, \
454 const struct packed_field_u16 * : unpack_fields_u16 \
455 )((pbuf), (pbuflen), (ustruct), (fields), ARRAY_SIZE(fields), (quirks)); \
456 })
457
458#endif