1 /// Flag enum to string conversion, flag get/sets, and mask interactions.
2 module tern.state;
3 
4 import tern.traits;
5 
6 public:
7 static:
8 pure:
9 /**
10  * Generates a string representation of a value based on its flag members.
11  *
12  * Params:
13  *  val = The value for which to generate the string representation.
14  *
15  * Returns:
16  *  A string representing the flag members set in the value.
17  */
18 string toString(T)(T val)
19 {
20     foreach (string member; Children!T)
21     {
22         if (val.hasFlag(__traits(getMember, T, member)))
23         {
24             string str;
25             foreach (m; Children!T)
26             {
27                 if (val.hasFlag(__traits(getMember, T, m)))
28                     str ~= m~" | ";
29             }
30             return str[0 .. $-3];
31         }
32     }
33     return Children!T[0];
34 }
35 
36 @nogc:
37 /**
38  * Checks if a value has a specific flag set.
39  *
40  * Params:
41  *  value = The value to check for the flag.
42  *  flag = The flag to check within the value.
43  *
44  * Returns:
45  *  A boolean indicating whether the flag is set in the value.
46  */
47 bool hasFlag(T)(T value, T flag)
48 {
49     return (value & flag) != 0;
50 }
51 
52 /**
53  * Checks if a value's masked portion matches a specific flag.
54  *
55  * Params:
56  *  value = The value to check for the flag match.
57  *  mask = The mask to apply to the value.
58  *  flag = The flag to match within the masked value.
59  *
60  * Returns:
61  *  A boolean indicating whether the flag matches the masked value.
62  */
63 bool hasFlagMasked(T)(T value, T mask, T flag)
64 {
65     return (value & mask) == flag;
66 }
67 
68 /**
69  * Sets or clears a flag in a value based on the provided state.
70  *
71  * Params:
72  *  value = Reference to the value where the flag will be modified.
73  *  flag = The flag to set or clear.
74  *  state = A boolean indicating whether to set or clear the flag.
75  */
76 void setFlag(T)(ref T value, T flag, bool state)
77 {
78     value = cast(T)(state ? (value | flag) : (value & ~flag));
79 }
80 
81 /**
82  * Toggles a flag in a value.
83  *
84  * Params:
85  *  value = Reference to the value where the flag will be toggled.
86  *  flag = The flag to toggle.
87  */
88 void toggleFlag(T)(ref T value, T flag)
89 {
90     value = cast(T)(value ^ flag);
91 }
92 
93 /**
94  * Sets a flag in a masked value based on the provided state.
95  *
96  * Params:
97  *  value = Reference to the value where the flag will be modified.
98  *  mask = The mask to apply to the value.
99  *  flag = The flag to set or clear.
100  *  state = A boolean indicating whether to set or clear the flag.
101  */
102 void setFlagMasked(T)(ref T value, T mask, T flag, bool state)
103 {
104     value = cast(T)(state ? (value & mask) | flag : (value & mask) & ~flag);
105 }
106 
107 /**
108  * Toggles a flag within a masked value.
109  *
110  * Params:
111  *  value = Reference to the value where the flag will be toggled.
112  *  mask = The mask to apply to the value.
113  *  flag = The flag to toggle within the masked value.
114  */
115 void toggleFlagMasked(T)(ref T value, T mask, T flag)
116 {
117     value = cast(T)((value & mask) ^ flag);
118 }
119 
120 /**
121  * Clears a mask from the provided value.
122  *
123  * Params:
124  *  value = The value from which the mask will be cleared.
125  *  mask = The mask to clear from the value.
126  *
127  * Returns:
128  *  The value after clearing the specified mask.
129  */
130 T clearMask(T)(T value, T mask)
131 {
132     return cast(T)(value & ~mask);
133 }