1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
// Take a look at the license at the top of the repository in the LICENSE file.

use glib::{
    prelude::*,
    translate::{from_glib, ToGlibPtr},
    FlagsClass,
};

bitflags_serde_impl!(crate::BinFlags);
bitflags_serde_impl!(crate::BufferCopyFlags);
bitflags_serde_impl!(crate::BufferFlags);
bitflags_serde_impl!(crate::BufferPoolAcquireFlags);
bitflags_serde_impl!(crate::ClockFlags);

impl serde::Serialize for crate::DebugColorFlags {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        serializer.serialize_str(&format!(
            "{}+{}{}{}",
            match *self & Self::from_bits(0b111).expect("Failed to create value from fg-color mask")
            {
                Self::FG_BLACK => "fg-black",
                Self::FG_RED => "fg-red",
                Self::FG_GREEN => "fg-green",
                Self::FG_YELLOW => "fg-yellow",
                Self::FG_BLUE => "fg-blue",
                Self::FG_MAGENTA => "fg-magenta",
                Self::FG_CYAN => "fg-cyan",
                Self::FG_WHITE => "fg-white",
                _ => unreachable!(),
            },
            match *self
                & Self::from_bits(0b111_0000).expect("Failed to create value from bg-color mask")
            {
                Self::BG_BLACK => "bg-black",
                Self::BG_RED => "bg-red",
                Self::BG_GREEN => "bg-green",
                Self::BG_YELLOW => "bg-yellow",
                Self::BG_BLUE => "bg-blue",
                Self::BG_MAGENTA => "bg-magenta",
                Self::BG_CYAN => "bg-cyan",
                Self::BG_WHITE => "bg-white",
                _ => unreachable!(),
            },
            if self.contains(Self::BOLD) {
                "+bold"
            } else {
                ""
            },
            if self.contains(Self::UNDERLINE) {
                "+underline"
            } else {
                ""
            }
        ))
    }
}

bitflags_deserialize_impl!(crate::DebugColorFlags);
bitflags_serialize_impl!(crate::DebugGraphDetails, by_ones_decreasing);
bitflags_deserialize_impl!(crate::DebugGraphDetails);
bitflags_serde_impl!(crate::ElementFlags);
bitflags_serde_impl!(crate::EventTypeFlags);
bitflags_serde_impl!(crate::GapFlags, "v1_20");
bitflags_serde_impl!(crate::MemoryFlags);
bitflags_serde_impl!(crate::MetaFlags);
bitflags_serde_impl!(crate::ObjectFlags);
bitflags_serde_impl!(crate::PadFlags);
bitflags_serde_impl!(crate::PadLinkCheck);
bitflags_serde_impl!(crate::PadProbeType);
bitflags_serde_impl!(crate::ParseFlags);
bitflags_serde_impl!(crate::PluginAPIFlags, "v1_18");
bitflags_serde_impl!(crate::PluginDependencyFlags);
bitflags_serde_impl!(crate::PluginFlags);
bitflags_serde_impl!(crate::SchedulingFlags);
bitflags_serde_impl!(crate::SeekFlags);
bitflags_serde_impl!(crate::SegmentFlags);
bitflags_serde_impl!(crate::SerializeFlags, "v1_20");
bitflags_serde_impl!(crate::StackTraceFlags);
bitflags_serde_impl!(crate::StreamFlags);
bitflags_serde_impl!(crate::StreamType);

#[cfg(test)]
mod tests {
    macro_rules! check_serialize {
        ($flags:expr, $expected:expr) => {
            let actual = serde_json::to_string(&$flags).unwrap();
            assert_eq!(actual, $expected);
        };
    }

    macro_rules! check_deserialize {
        ($ty:ty, $expected:expr, $json:expr) => {
            let actual: $ty = serde_json::from_str(&$json).unwrap();
            assert_eq!(actual, $expected);
        };
    }

    macro_rules! check_roundtrip {
        ($ty:ty, $flags:expr) => {
            let json = serde_json::to_string(&$flags).unwrap();
            let deserialized: $ty = serde_json::from_str(&json).unwrap();
            assert_eq!(deserialized, $flags);
        };
    }

    #[test]
    fn test_serialize() {
        crate::init().unwrap();

        check_serialize!(crate::BinFlags::empty(), "\"\"");
        check_serialize!(crate::BinFlags::all(), "\"no-resync+streams-aware\"");
        check_serialize!(
            crate::BufferCopyFlags::all(),
            "\"flags+timestamps+meta+memory+merge+deep\""
        );
        check_serialize!(
            crate::BufferFlags::all(),
            concat!(
                "\"live+decode-only+discont+resync+corrupted+marker+header+gap",
                "+droppable+delta-unit+tag-memory+sync-after+non-droppable\""
            )
        );
        check_serialize!(
            crate::BufferPoolAcquireFlags::all(),
            "\"key-unit+dontwait+discont\""
        );
        check_serialize!(
            crate::ClockFlags::all(),
            concat!(
                "\"can-do-single-sync+can-do-single-async",
                "+can-do-periodic-sync+can-do-periodic-async",
                "+can-set-resolution+can-set-master+needs-startup-sync\""
            )
        );

        check_serialize!(
            crate::DebugColorFlags::all(),
            "\"fg-white+bg-white+bold+underline\""
        );
        check_serialize!(
            crate::DebugColorFlags::FG_MAGENTA | crate::DebugColorFlags::BOLD,
            "\"fg-magenta+bg-black+bold\""
        );
        check_serialize!(
            crate::DebugColorFlags::FG_RED
                | crate::DebugColorFlags::FG_BLUE
                | crate::DebugColorFlags::BG_BLACK,
            "\"fg-magenta+bg-black\""
        );

        check_serialize!(crate::DebugGraphDetails::all(), "\"verbose\"");
        check_serialize!(
            crate::DebugGraphDetails::MEDIA_TYPE
                | crate::DebugGraphDetails::CAPS_DETAILS
                | crate::DebugGraphDetails::NON_DEFAULT_PARAMS
                | crate::DebugGraphDetails::STATES
                | crate::DebugGraphDetails::FULL_PARAMS
                | crate::DebugGraphDetails::ALL,
            "\"all+full-params\""
        );
        check_serialize!(
            crate::DebugGraphDetails::MEDIA_TYPE
                | crate::DebugGraphDetails::CAPS_DETAILS
                | crate::DebugGraphDetails::NON_DEFAULT_PARAMS
                | crate::DebugGraphDetails::STATES
                | crate::DebugGraphDetails::FULL_PARAMS,
            "\"all+full-params\""
        );

        check_serialize!(
            crate::ElementFlags::all(),
            "\"locked-state+sink+source+provide-clock+require-clock+indexable\""
        );
        check_serialize!(
            crate::EventTypeFlags::all(),
            "\"upstream+downstream+serialized+sticky+sticky-multi\""
        );
        #[cfg(feature = "v1_20")]
        check_serialize!(crate::GapFlags::all(), "\"data\"");
        check_serialize!(
            crate::MemoryFlags::all(),
            concat!(
                "\"readonly+no-share+zero-prefixed+zero-padded",
                "+physically-contiguous+not-mappable\""
            )
        );
        check_serialize!(crate::MetaFlags::all(), "\"readonly+pooled+locked\"");
        check_serialize!(crate::ObjectFlags::all(), "\"may-be-leaked+constructed\"");
        check_serialize!(
            crate::PadFlags::all(),
            concat!(
                "\"blocked+flushing+eos+blocking+need-parent+need-reconfigure",
                "+pending-events+fixed-caps+proxy-caps+proxy-allocation",
                "+proxy-scheduling+accept-intersect+accept-template\""
            )
        );
        check_serialize!(
            crate::PadLinkCheck::all(),
            "\"hierarchy+template-caps+caps+no-reconfigure\""
        );
        check_serialize!(
            crate::PadProbeType::all(),
            concat!(
                "\"idle+block+buffer+buffer-list+event-downstream",
                "+event-upstream+event-flush+query-downstream+query-upstream",
                "+push+pull\""
            )
        );
        check_serialize!(
            crate::ParseFlags::all(),
            "\"fatal-errors+no-single-element-bins+place-in-bin\""
        );
        #[cfg(feature = "v1_18")]
        check_serialize!(crate::PluginAPIFlags::all(), "\"members\"");
        check_serialize!(
            crate::PluginDependencyFlags::all(),
            concat!(
                "\"recurse+paths-are-default-only+file-name-is-suffix",
                "+file-name-is-prefix+paths-are-relative-to-exe\""
            )
        );
        check_serialize!(crate::PluginFlags::all(), "\"cached+blacklisted\"");
        check_serialize!(
            crate::SchedulingFlags::all(),
            "\"seekable+sequential+bandwidth-limited\""
        );
        #[cfg(feature = "v1_18")]
        check_serialize!(
            crate::SeekFlags::all(),
            concat!(
                "\"flush+accurate+key-unit+segment+trickmode+snap-before",
                "+snap-after+trickmode-key-units+trickmode-no-audio",
                "+trickmode-forward-predicted+instant-rate-change\""
            )
        );
        #[cfg(feature = "v1_18")]
        check_serialize!(
            crate::SegmentFlags::all(),
            concat!(
                "\"reset+trickmode+segment+trickmode-key-units",
                "+trickmode-forward-predicted+trickmode-no-audio\""
            )
        );
        #[cfg(feature = "v1_20")]
        check_serialize!(crate::SerializeFlags::all(), "\"backward-compat\"");
        check_serialize!(crate::StackTraceFlags::all(), "\"full\"");
        check_serialize!(crate::StreamFlags::all(), "\"sparse+select+unselect\"");
        check_serialize!(
            crate::StreamType::all(),
            "\"unknown+audio+video+container+text\""
        );
    }

    #[test]
    fn test_deserialize() {
        crate::init().unwrap();

        check_deserialize!(crate::BinFlags, crate::BinFlags::empty(), "\"\"");
        check_deserialize!(
            crate::BinFlags,
            crate::BinFlags::all(),
            "\"no-resync+streams-aware\""
        );
        check_deserialize!(
            crate::BufferCopyFlags,
            crate::BufferCopyFlags::all(),
            "\"flags+timestamps+meta+memory+merge+deep\""
        );
        check_deserialize!(
            crate::BufferFlags,
            crate::BufferFlags::all(),
            concat!(
                "\"live+decode-only+discont+resync+corrupted+marker+header+gap",
                "+droppable+delta-unit+tag-memory+sync-after+non-droppable\""
            )
        );
        check_deserialize!(
            crate::BufferPoolAcquireFlags,
            crate::BufferPoolAcquireFlags::all(),
            "\"key-unit+dontwait+discont\""
        );
        check_deserialize!(
            crate::ClockFlags,
            crate::ClockFlags::all(),
            concat!(
                "\"can-do-single-sync+can-do-single-async",
                "+can-do-periodic-sync+can-do-periodic-async",
                "+can-set-resolution+can-set-master+needs-startup-sync\""
            )
        );

        check_deserialize!(
            crate::DebugColorFlags,
            crate::DebugColorFlags::all(),
            "\"fg-white+bg-white+bold+underline\""
        );
        check_deserialize!(
            crate::DebugColorFlags,
            crate::DebugColorFlags::FG_MAGENTA | crate::DebugColorFlags::BOLD,
            "\"fg-magenta+bg-black+bold\""
        );
        check_deserialize!(
            crate::DebugColorFlags,
            crate::DebugColorFlags::FG_RED
                | crate::DebugColorFlags::FG_BLUE
                | crate::DebugColorFlags::BG_BLACK,
            "\"fg-magenta+bg-black\""
        );

        check_deserialize!(
            crate::DebugGraphDetails,
            crate::DebugGraphDetails::all(),
            "\"verbose\""
        );
        check_deserialize!(
            crate::DebugGraphDetails,
            crate::DebugGraphDetails::MEDIA_TYPE
                | crate::DebugGraphDetails::CAPS_DETAILS
                | crate::DebugGraphDetails::NON_DEFAULT_PARAMS
                | crate::DebugGraphDetails::STATES
                | crate::DebugGraphDetails::FULL_PARAMS
                | crate::DebugGraphDetails::ALL,
            "\"all+full-params\""
        );
        check_deserialize!(
            crate::DebugGraphDetails,
            crate::DebugGraphDetails::MEDIA_TYPE
                | crate::DebugGraphDetails::CAPS_DETAILS
                | crate::DebugGraphDetails::NON_DEFAULT_PARAMS
                | crate::DebugGraphDetails::STATES
                | crate::DebugGraphDetails::FULL_PARAMS,
            "\"all+full-params\""
        );

        check_deserialize!(
            crate::ElementFlags,
            crate::ElementFlags::all(),
            "\"locked-state+sink+source+provide-clock+require-clock+indexable\""
        );
        check_deserialize!(
            crate::EventTypeFlags,
            crate::EventTypeFlags::all(),
            "\"upstream+downstream+serialized+sticky+sticky-multi\""
        );
        #[cfg(feature = "v1_20")]
        check_deserialize!(crate::GapFlags, crate::GapFlags::all(), "\"data\"");
        check_deserialize!(
            crate::MemoryFlags,
            crate::MemoryFlags::all(),
            concat!(
                "\"readonly+no-share+zero-prefixed+zero-padded",
                "+physically-contiguous+not-mappable\""
            )
        );
        check_deserialize!(
            crate::MetaFlags,
            crate::MetaFlags::all(),
            "\"readonly+pooled+locked\""
        );
        check_deserialize!(
            crate::ObjectFlags,
            crate::ObjectFlags::all(),
            "\"may-be-leaked+constructed\""
        );
        check_deserialize!(
            crate::PadFlags,
            crate::PadFlags::all(),
            concat!(
                "\"blocked+flushing+eos+blocking+need-parent+need-reconfigure",
                "+pending-events+fixed-caps+proxy-caps+proxy-allocation",
                "+proxy-scheduling+accept-intersect+accept-template\""
            )
        );
        check_deserialize!(
            crate::PadLinkCheck,
            crate::PadLinkCheck::all(),
            "\"hierarchy+template-caps+caps+no-reconfigure\""
        );
        check_deserialize!(
            crate::PadProbeType,
            crate::PadProbeType::all(),
            concat!(
                "\"idle+block+buffer+buffer-list+event-downstream",
                "+event-upstream+event-flush+query-downstream+query-upstream",
                "+push+pull\""
            )
        );
        check_deserialize!(
            crate::ParseFlags,
            crate::ParseFlags::all(),
            "\"fatal-errors+no-single-element-bins+place-in-bin\""
        );
        #[cfg(feature = "v1_18")]
        check_deserialize!(
            crate::PluginAPIFlags,
            crate::PluginAPIFlags::all(),
            "\"members\""
        );
        check_deserialize!(
            crate::PluginDependencyFlags,
            crate::PluginDependencyFlags::all(),
            concat!(
                "\"recurse+paths-are-default-only+file-name-is-suffix",
                "+file-name-is-prefix+paths-are-relative-to-exe\""
            )
        );
        check_deserialize!(
            crate::PluginFlags,
            crate::PluginFlags::all(),
            "\"cached+blacklisted\""
        );
        check_deserialize!(
            crate::SchedulingFlags,
            crate::SchedulingFlags::all(),
            "\"seekable+sequential+bandwidth-limited\""
        );
        #[cfg(feature = "v1_18")]
        check_deserialize!(
            crate::SeekFlags,
            crate::SeekFlags::all(),
            concat!(
                "\"flush+accurate+key-unit+segment+trickmode+snap-before",
                "+snap-after+trickmode-key-units+trickmode-no-audio",
                "+trickmode-forward-predicted+instant-rate-change\""
            )
        );
        #[cfg(feature = "v1_18")]
        check_deserialize!(
            crate::SegmentFlags,
            crate::SegmentFlags::all(),
            concat!(
                "\"reset+trickmode+segment+trickmode-key-units",
                "+trickmode-forward-predicted+trickmode-no-audio\""
            )
        );
        #[cfg(feature = "v1_20")]
        check_deserialize!(
            crate::SerializeFlags,
            crate::SerializeFlags::all(),
            "\"backward-compat\""
        );
        check_deserialize!(
            crate::StackTraceFlags,
            crate::StackTraceFlags::all(),
            "\"full\""
        );
        check_deserialize!(
            crate::StreamFlags,
            crate::StreamFlags::all(),
            "\"sparse+select+unselect\""
        );
        check_deserialize!(
            crate::StreamType,
            crate::StreamType::all(),
            "\"unknown+audio+video+container+text\""
        );
    }

    #[test]
    fn test_serde_roundtrip() {
        crate::init().unwrap();

        check_roundtrip!(crate::BinFlags, crate::BinFlags::empty());
        check_roundtrip!(crate::BinFlags, crate::BinFlags::all());
        check_roundtrip!(crate::BufferCopyFlags, crate::BufferCopyFlags::all());
        check_roundtrip!(crate::BufferFlags, crate::BufferFlags::all());
        check_roundtrip!(
            crate::BufferPoolAcquireFlags,
            crate::BufferPoolAcquireFlags::all()
        );
        check_roundtrip!(crate::ClockFlags, crate::ClockFlags::all());

        check_roundtrip!(crate::DebugColorFlags, crate::DebugColorFlags::all());
        check_roundtrip!(
            crate::DebugColorFlags,
            crate::DebugColorFlags::FG_MAGENTA | crate::DebugColorFlags::BOLD
        );
        check_roundtrip!(
            crate::DebugColorFlags,
            crate::DebugColorFlags::FG_RED
                | crate::DebugColorFlags::FG_BLUE
                | crate::DebugColorFlags::BG_BLACK
        );

        check_roundtrip!(crate::DebugGraphDetails, crate::DebugGraphDetails::all());
        check_roundtrip!(
            crate::DebugGraphDetails,
            crate::DebugGraphDetails::MEDIA_TYPE
                | crate::DebugGraphDetails::CAPS_DETAILS
                | crate::DebugGraphDetails::NON_DEFAULT_PARAMS
                | crate::DebugGraphDetails::STATES
                | crate::DebugGraphDetails::FULL_PARAMS
                | crate::DebugGraphDetails::ALL
        );
        check_roundtrip!(
            crate::DebugGraphDetails,
            crate::DebugGraphDetails::MEDIA_TYPE
                | crate::DebugGraphDetails::CAPS_DETAILS
                | crate::DebugGraphDetails::NON_DEFAULT_PARAMS
                | crate::DebugGraphDetails::STATES
                | crate::DebugGraphDetails::FULL_PARAMS
        );

        check_roundtrip!(crate::ElementFlags, crate::ElementFlags::all());
        check_roundtrip!(crate::EventTypeFlags, crate::EventTypeFlags::all());
        #[cfg(feature = "v1_20")]
        check_roundtrip!(crate::GapFlags, crate::GapFlags::all());
        check_roundtrip!(crate::MemoryFlags, crate::MemoryFlags::all());
        check_roundtrip!(crate::MetaFlags, crate::MetaFlags::all());
        check_roundtrip!(crate::ObjectFlags, crate::ObjectFlags::all());
        check_roundtrip!(crate::PadFlags, crate::PadFlags::all());
        check_roundtrip!(crate::PadLinkCheck, crate::PadLinkCheck::all());
        check_roundtrip!(crate::PadProbeType, crate::PadProbeType::all());
        check_roundtrip!(crate::ParseFlags, crate::ParseFlags::all());
        #[cfg(feature = "v1_18")]
        check_roundtrip!(crate::PluginAPIFlags, crate::PluginAPIFlags::all());
        check_roundtrip!(
            crate::PluginDependencyFlags,
            crate::PluginDependencyFlags::all()
        );
        check_roundtrip!(crate::PluginFlags, crate::PluginFlags::all());
        check_roundtrip!(crate::SchedulingFlags, crate::SchedulingFlags::all());
        #[cfg(feature = "v1_18")]
        check_roundtrip!(crate::SeekFlags, crate::SeekFlags::all());
        #[cfg(feature = "v1_18")]
        check_roundtrip!(crate::SegmentFlags, crate::SegmentFlags::all());
        #[cfg(feature = "v1_20")]
        check_roundtrip!(crate::SerializeFlags, crate::SerializeFlags::all());
        check_roundtrip!(crate::StackTraceFlags, crate::StackTraceFlags::all());
        check_roundtrip!(crate::StreamFlags, crate::StreamFlags::all());
        check_roundtrip!(crate::StreamType, crate::StreamType::all());
    }
}