| ... | ... | @@ -2096,30 +2096,38 @@ const Type = enum { |
| 2096 | 2096 | NotOk, |
| 2097 | 2097 | }; |
| 2098 | 2098 | |
| 2099 | | // Enums are sum types, and can hold more complex data of different types. |
| 2100 | | const ComplexType = enum { |
| 2101 | | Ok: u8, |
| 2102 | | NotOk: void, |
| 2103 | | }; |
| 2104 | | |
| 2105 | 2099 | // Declare a specific instance of the enum variant. |
| 2106 | | const c = ComplexType.Ok { 0 }; |
| 2100 | const c = Type.Ok; |
| 2107 | 2101 | |
| 2108 | | // The ordinal value of a simple enum with no data members can be |
| 2109 | | // retrieved by a simple cast. |
| 2110 | | // The value starts from 0, counting up for each member. |
| 2111 | | const Value = enum { |
| 2102 | // If you want access to the ordinal value of an enum, you |
| 2103 | // can specify the tag type. |
| 2104 | const Value = enum(u2) { |
| 2112 | 2105 | Zero, |
| 2113 | 2106 | One, |
| 2114 | 2107 | Two, |
| 2115 | 2108 | }; |
| 2109 | |
| 2110 | // Now you can cast between u2 and Value. |
| 2111 | // The ordinal value starts from 0, counting up for each member. |
| 2116 | 2112 | test "enum ordinal value" { |
| 2117 | | assert(usize(Value.Zero) == 0); |
| 2118 | | assert(usize(Value.One) == 1); |
| 2119 | | assert(usize(Value.Two) == 2); |
| 2113 | assert(u2(Value.Zero) == 0); |
| 2114 | assert(u2(Value.One) == 1); |
| 2115 | assert(u2(Value.Two) == 2); |
| 2120 | 2116 | } |
| 2121 | 2117 | |
| 2122 | | // Enums can have methods, the same as structs. |
| 2118 | // You can override the ordinal value for an enum. |
| 2119 | const Value2 = enum(u32) { |
| 2120 | Hundred = 100, |
| 2121 | Thousand = 1000, |
| 2122 | Million = 1000000, |
| 2123 | }; |
| 2124 | test "set enum ordinal value" { |
| 2125 | assert(u32(Value2.Hundred) == 100); |
| 2126 | assert(u32(Value2.Thousand) == 1000); |
| 2127 | assert(u32(Value2.Million) == 1000000); |
| 2128 | } |
| 2129 | |
| 2130 | // Enums can have methods, the same as structs and unions. |
| 2123 | 2131 | // Enum methods are not special, they are only namespaced |
| 2124 | 2132 | // functions that you can call with dot syntax. |
| 2125 | 2133 | const Suit = enum { |
| ... | ... | @@ -2128,26 +2136,120 @@ const Suit = enum { |
| 2128 | 2136 | Diamonds, |
| 2129 | 2137 | Hearts, |
| 2130 | 2138 | |
| 2131 | | pub fn ordinal(self: &const Suit) -> u8 { |
| 2132 | | u8(*self) |
| 2139 | pub fn isClubs(self: Suit) -> bool { |
| 2140 | return self == Suit.Clubs; |
| 2133 | 2141 | } |
| 2134 | 2142 | }; |
| 2135 | 2143 | test "enum method" { |
| 2136 | 2144 | const p = Suit.Spades; |
| 2137 | | assert(p.ordinal() == 1); |
| 2145 | assert(!p.isClubs()); |
| 2138 | 2146 | } |
| 2139 | 2147 | |
| 2140 | 2148 | // An enum variant of different types can be switched upon. |
| 2141 | | // The associated data can be retrieved using `|...|` syntax. |
| 2142 | | // |
| 2143 | | // A void type is not required on a tag-only member. |
| 2144 | 2149 | const Foo = enum { |
| 2150 | String, |
| 2151 | Number, |
| 2152 | None, |
| 2153 | }; |
| 2154 | test "enum variant switch" { |
| 2155 | const p = Foo.Number; |
| 2156 | const what_is_it = switch (p) { |
| 2157 | Foo.String => "this is a string", |
| 2158 | Foo.Number => "this is a number", |
| 2159 | Foo.None => "this is a none", |
| 2160 | }; |
| 2161 | assert(mem.eql(u8, what_is_it, "this is a number")); |
| 2162 | } |
| 2163 | |
| 2164 | // @TagType can be used to access the integer tag type of an enum. |
| 2165 | const Small = enum { |
| 2166 | One, |
| 2167 | Two, |
| 2168 | Three, |
| 2169 | Four, |
| 2170 | }; |
| 2171 | test "@TagType" { |
| 2172 | assert(@TagType(Small) == u2); |
| 2173 | } |
| 2174 | |
| 2175 | // @memberCount tells how many fields an enum has: |
| 2176 | test "@memberCount" { |
| 2177 | assert(@memberCount(Small) == 4); |
| 2178 | } |
| 2179 | |
| 2180 | // @memberName tells the name of a field in an enum: |
| 2181 | test "@memberName" { |
| 2182 | assert(mem.eql(u8, @memberName(Small, 1), "Two")); |
| 2183 | } |
| 2184 | |
| 2185 | // @tagName gives a []const u8 representation of an enum value: |
| 2186 | test "@tagName" { |
| 2187 | assert(mem.eql(u8, @tagName(Small.Three), "Three")); |
| 2188 | }</code></pre> |
| 2189 | <p>TODO extern enum</p> |
| 2190 | <p>TODO packed enum</p> |
| 2191 | <pre><code class="sh">$ zig test enum.zig |
| 2192 | Test 1/8 enum ordinal value...OK |
| 2193 | Test 2/8 set enum ordinal value...OK |
| 2194 | Test 3/8 enum method...OK |
| 2195 | Test 4/8 enum variant switch...OK |
| 2196 | Test 5/8 @TagType...OK |
| 2197 | Test 6/8 @memberCount...OK |
| 2198 | Test 7/8 @memberName...OK |
| 2199 | Test 8/8 @tagName...OK</code></pre> |
| 2200 | <p>See also:</p> |
| 2201 | <ul> |
| 2202 | <li><a href="#builtin-memberName">@memberName</a></li> |
| 2203 | <li><a href="#builtin-memberCount">@memberCount</a></li> |
| 2204 | <li><a href="#builtin-tagName">@tagName</a></li> |
| 2205 | </ul> |
| 2206 | <h2 id="union">union</h2> |
| 2207 | <pre><code class="zig">const assert = @import("std").debug.assert; |
| 2208 | const mem = @import("std").mem; |
| 2209 | |
| 2210 | // A union has only 1 active field at a time. |
| 2211 | const Payload = union { |
| 2212 | Int: i64, |
| 2213 | Float: f64, |
| 2214 | Bool: bool, |
| 2215 | }; |
| 2216 | test "simple union" { |
| 2217 | var payload = Payload {.Int = 1234}; |
| 2218 | // payload.Float = 12.34; // ERROR! field not active |
| 2219 | assert(payload.Int == 1234); |
| 2220 | // You can activate another field by assigning the entire union. |
| 2221 | payload = Payload {.Float = 12.34}; |
| 2222 | assert(payload.Float == 12.34); |
| 2223 | } |
| 2224 | |
| 2225 | // Unions can be given an enum tag type: |
| 2226 | const ComplexTypeTag = enum { Ok, NotOk }; |
| 2227 | const ComplexType = union(ComplexTypeTag) { |
| 2228 | Ok: u8, |
| 2229 | NotOk: void, |
| 2230 | }; |
| 2231 | |
| 2232 | // Declare a specific instance of the union variant. |
| 2233 | test "declare union value" { |
| 2234 | const c = ComplexType { .Ok = 0 }; |
| 2235 | assert(ComplexTypeTag(c) == ComplexTypeTag.Ok); |
| 2236 | } |
| 2237 | |
| 2238 | // @TagType can be used to access the enum tag type of a union. |
| 2239 | test "@TagType" { |
| 2240 | assert(@TagType(ComplexType) == ComplexTypeTag); |
| 2241 | } |
| 2242 | |
| 2243 | // Unions can be made to infer the enum tag type. |
| 2244 | const Foo = union(enum) { |
| 2145 | 2245 | String: []const u8, |
| 2146 | 2246 | Number: u64, |
| 2247 | |
| 2248 | // void can be omitted when inferring enum tag type. |
| 2147 | 2249 | None, |
| 2148 | 2250 | }; |
| 2149 | | test "enum variant switch" { |
| 2150 | | const p = Foo.Number { 54 }; |
| 2251 | test "union variant switch" { |
| 2252 | const p = Foo { .Number = 54 }; |
| 2151 | 2253 | const what_is_it = switch (p) { |
| 2152 | 2254 | // Capture by reference |
| 2153 | 2255 | Foo.String =&gt; |*x| { |
| ... | ... | @@ -2156,6 +2258,7 @@ test "enum variant switch" { |
| 2156 | 2258 | |
| 2157 | 2259 | // Capture by value |
| 2158 | 2260 | Foo.Number =&gt; |x| { |
| 2261 | assert(x == 54); |
| 2159 | 2262 | "this is a number" |
| 2160 | 2263 | }, |
| 2161 | 2264 | |
| ... | ... | @@ -2163,38 +2266,50 @@ test "enum variant switch" { |
| 2163 | 2266 | "this is a none" |
| 2164 | 2267 | } |
| 2165 | 2268 | }; |
| 2269 | assert(mem.eql(u8, what_is_it, "this is a number")); |
| 2166 | 2270 | } |
| 2167 | 2271 | |
| 2168 | | // The @memberName and @memberCount builtin functions can be used to |
| 2169 | | // the string representation and number of members respectively. |
| 2170 | | const BuiltinType = enum { |
| 2171 | | A: f32, |
| 2172 | | B: u32, |
| 2173 | | C, |
| 2272 | // TODO union methods |
| 2273 | |
| 2274 | |
| 2275 | const Small = union { |
| 2276 | A: i32, |
| 2277 | B: bool, |
| 2278 | C: u8, |
| 2174 | 2279 | }; |
| 2175 | 2280 | |
| 2176 | | test "enum builtins" { |
| 2177 | | assert(mem.eql(u8, @memberName(BuiltinType.A { 0 }), "A")); |
| 2178 | | assert(mem.eql(u8, @memberName(BuiltinType.C), "C")); |
| 2179 | | assert(@memberCount(BuiltinType) == 3); |
| 2281 | // @memberCount tells how many fields a union has: |
| 2282 | test "@memberCount" { |
| 2283 | assert(@memberCount(Small) == 3); |
| 2284 | } |
| 2285 | |
| 2286 | // @memberName tells the name of a field in an enum: |
| 2287 | test "@memberName" { |
| 2288 | assert(mem.eql(u8, @memberName(Small, 1), "B")); |
| 2289 | } |
| 2290 | |
| 2291 | // @tagName gives a []const u8 representation of an enum value, |
| 2292 | // but only if the union has an enum tag type. |
| 2293 | const Small2 = union(enum) { |
| 2294 | A: i32, |
| 2295 | B: bool, |
| 2296 | C: u8, |
| 2297 | }; |
| 2298 | test "@tagName" { |
| 2299 | assert(mem.eql(u8, @tagName(Small2.C), "C")); |
| 2180 | 2300 | }</code></pre> |
| 2181 | | <pre><code class="sh">$ zig test enum.zig |
| 2182 | | Test 1/4 enum ordinal value...OK |
| 2183 | | Test 2/4 enum method...OK |
| 2184 | | Test 3/4 enum variant switch...OK |
| 2185 | | Test 4/4 enum builtins...OK</code></pre> |
| 2186 | | <p> |
| 2187 | | Enums are generated as a struct with a tag field and union field. Zig |
| 2301 | <pre><code class="sh">$ zig test union.zig |
| 2302 | Test 1/7 simple union...OK |
| 2303 | Test 2/7 declare union value...OK |
| 2304 | Test 3/7 @TagType...OK |
| 2305 | Test 4/7 union variant switch...OK |
| 2306 | Test 5/7 @memberCount...OK |
| 2307 | Test 6/7 @memberName...OK |
| 2308 | Test 7/7 @tagName...OK</code></pre> |
| 2309 | <p> |
| 2310 | Unions with an enum tag are generated as a struct with a tag field and union field. Zig |
| 2188 | 2311 | sorts the order of the tag and union field by the largest alignment. |
| 2189 | 2312 | </p> |
| 2190 | | <p>See also:</p> |
| 2191 | | <ul> |
| 2192 | | <li><a href="#builtin-memberName">@memberName</a></li> |
| 2193 | | <li><a href="#builtin-memberCount">@memberCount</a></li> |
| 2194 | | <li><a href="#builtin-tagName">@tagName</a></li> |
| 2195 | | </ul> |
| 2196 | | <h2 id="union">union</h2> |
| 2197 | | <p>TODO union documentation</p> |
| 2198 | 2313 | <h2 id="switch">switch</h2> |
| 2199 | 2314 | <pre><code class="zig">const assert = @import("std").debug.assert; |
| 2200 | 2315 | const builtin = @import("builtin"); |