1 module ddbus.attributes;
2 
3 import std.meta : allSatisfy;
4 import std.traits : getUDAs;
5 import std.typecons : BitFlags, Flag;
6 
7 /++
8   Flags for use with dbusMarshaling UDA
9 
10   Default is to include public fields only
11 +/
12 enum MarshalingFlag : ubyte {
13   /++
14     Automatically include private fields
15   +/
16   includePrivateFields = 1 << 0,
17 
18   /++
19     Only include fields with explicit `@Yes.DBusMarshal`. This overrides any
20     `include` flags.
21   +/
22   manualOnly = 1 << 7
23 }
24 
25 /++
26   UDA for specifying DBus marshaling options on structs
27 +/
28 auto dbusMarshaling(Args)(Args args...)
29     if (allSatisfy!(isMarshalingFlag, Args)) {
30   return BitFlags!MarshalingFlag(args);
31 }
32 
33 package(ddbus) template isAllowedField(alias field) {
34   private enum flags = marshalingFlags!(__traits(parent, field));
35   private alias getUDAs!(field, Flag!"DBusMarshal") UDAs;
36 
37   static if (UDAs.length != 0) {
38     static assert(UDAs.length == 1,
39         "Only one UDA of type Flag!\"DBusMarshal\" allowed on struct field.");
40 
41     static assert(is(typeof(UDAs[0]) == Flag!"DBusMarshal"),
42         "Did you intend to add UDA Yes.DBusMarshal or No.DBusMarshal?");
43 
44     enum isAllowedField = cast(bool) UDAs[0];
45   } else static if (!(flags & MarshalingFlag.manualOnly)) {
46     static if (__traits(getProtection, field) == "public") {
47       enum isAllowedField = true;
48     } else static if (cast(bool)(flags & MarshalingFlag.includePrivateFields)) {
49       enum isAllowedField = true;
50     } else {
51       enum isAllowedField = false;
52     }
53   } else {
54     enum isAllowedField = false;
55   }
56 }
57 
58 private template isMarshalingFlag(T) {
59   enum isMarshalingFlag = is(T == MarshalingFlag);
60 }
61 
62 private template marshalingFlags(S)
63     if (is(S == struct)) {
64   private alias getUDAs!(S, BitFlags!MarshalingFlag) UDAs;
65 
66   static if (UDAs.length == 0) {
67     enum marshalingFlags = BitFlags!MarshalingFlag.init;
68   } else {
69     static assert(UDAs.length == 1, "Only one @dbusMarshaling UDA allowed on type.");
70     static assert(is(typeof(UDAs[0]) == BitFlags!MarshalingFlag),
71         "Huh? Did you intend to use @dbusMarshaling UDA?");
72     enum marshalingFlags = UDAs[0];
73   }
74 }