diff --git a/docs/COMPARISON-TABLES.md b/docs/COMPARISON-TABLES.md index 47177e973..8fc3b8da2 100644 --- a/docs/COMPARISON-TABLES.md +++ b/docs/COMPARISON-TABLES.md @@ -204,7 +204,7 @@ the source list at the end. | Declared numeric bounds | `\| min, max` in the type; bits on the type wire, clamp and count on the table wire (SPEC §4.3, §4) | — | — | | Fixed point | `fixed(I,F)`, `ufixed(I,F)`, exact round trip on both wires (SPEC §4.3; SPEC-TABLES §3, §16.2) | — | — | | Constants | `const`, typed or inferred, exported to every language, usable in bounds and extents | — | — | -| Enums | implicit `None = 0`, dense from 1, `Max`; on the table wire a value rides as the hash of its name (§3) | explicit values on a declared integer type; `bit_flags` (FB-schema) | 32-bit values, first must be 0, aliases, reserved values, open or closed per edition (PB-enum) | +| Enums | implicit `None = 0`, dense from 1, `Count` and `Max`; on the table wire a value rides as the hash of its name (§3) | explicit values on a declared integer type; `bit_flags` (FB-schema) | 32-bit values, first must be 0, aliases, reserved values, open or closed per edition (PB-enum) | | Flags | `flags`, up to 64 bits, `uint64` storage everywhere, `.Count`; rides as a mask (§3) | `enum (bit_flags)` | — | | Inline struct | a `type` nested by value; a whole fixed table is a plain struct (§2.2, §6.1) | `struct`: scalars and structs only, inline, unversioned (FB-internals) | — ; every message is length-delimited (PB-encoding) | | Nested composites | tables nest by value; a by-value cycle is refused naming it (§2) | tables by offset; depth bounded by the verifier's `max_depth` (FB-cpp) | unlimited nesting; parser recursion limit 100 (PB-limits) | diff --git a/docs/SPEC.md b/docs/SPEC.md index cd879bdbe..a176d8202 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -452,13 +452,20 @@ FloatExpr = float expression over float literals, int literals and const names the reserved values above the last variant are wire-legal and name no slot. It works on the generated tag set too (a union's `Type.Max` — §4.8); generated sets resolve in - constant expressions and nowhere else. **Flags + constant expressions and nowhere else. +- **Declared-count references:** **`.Count`** in any integer expression names + the DECLARED variant count of an enum or a flags declaration — one word + meaning one thing in both. `E.Count` excludes an enum's implicit `None`; + `F.Count` counts the named bits. Under `| max = K` headroom the count and + the extent part — an enum's `Max` is the widened extent and a flags + declaration's wire width is K, while `Count` stays the count — and without + headroom `E.Count` equals `E.Max`. `[..E.Count]T` is therefore a counted + array over the declared variants, where `[E.Max]T` is the keyed array with + one slot per admitted ordinal. **Flags have `F.Count`, not `F.Max`** — a flags declaration is a set of independent bits, not a range with a top, so max-of-what is exactly the confusion `.Max` would invite and the compiler refuses it naming the - split. `F.Count` is the DECLARED variant count; under `| max = K` headroom - the wire width is K while `Count` stays the count — the one case the two - numbers diverge. `Max` and `Count` after `.` are contextual, like + split. `Max` and `Count` after `.` are contextual, like attribute keys; the lexer keeps maximal munch, so `..` still wins over `.`. - **Constants are platform-uniform.** A schema has no platform conditionals. @@ -711,7 +718,8 @@ a language rule — the language does not enforce entry 0's meaning. enum and the generated `Type` tag enums — carries its extent as a member named `Max` in the target's own convention: `E::Max` (C++), `E.Max` (C#), `EMax` (Go), `E::MAX` (Rust), `E.Max` (JS), `E_MAX` -(C). Its value is the enum's max — the same number `E.Max` names in schema +(C), `E.max` (Dart and Java), `E.max/0` (Elixir). Its value is the enum's +max — the same number `E.Max` names in schema expressions (§4.2): the highest wire-legal value, which under the sentinel-zero convention is the count of real variants when no `max` headroom widens it. Application code states ranges and asserts directly @@ -721,6 +729,20 @@ constant that re-derives it. `Max` is therefore a reserved variant name — declaring a variant named `Max` is refused at check time, exactly as `None` is. +**The declared count is exported too.** Every declared enum carries its +**`Count`** beside its `Max`: the number of DECLARED variants, excluding the +implicit `None`. It is the same number `E.Count` names in schema expressions +(§4.2), it equals `Max` when no `| max = K` headroom widens the enum, and it +is below `Max` when one does — which is the whole reason it is exported. All +nine targets spell it their own way, the spelling each already uses for a +flags declaration's `Count`: `E::Count` (C++), `E.Count` (C#), `ECount` +(Go), `E::COUNT` (Rust), `E.Count` (JS), `E_COUNT` (C), `E.count` (Dart and +Java), `E.count/0` (Elixir). `Count` is a reserved variant name for the same +reason `Max` is, and it is a claimed name under §4.6 — a declaration whose +generated symbol would collide with an enum's `Count` is refused, naming the +enum. The generated `Type` tag enums carry `Max` alone: a tag set +takes no headroom, so its count and its extent are one number. + ### 4.3 Field types and their wire encodings **The wire model — normative:** @@ -912,7 +934,8 @@ All compile errors with positions: and no unit declares `ProtocolId`. The checker likewise refuses user names that collide with per-declaration generated symbols (`Write*`/`Read*`/`New*`, `*MaxBits`/`*MaxBytes`, companion length/count - names, a union's generated tag surface). Diagnostics name the generated + names, an enum's `Max` and `Count`, a flags declaration's `Count`, a + union's generated tag surface). Diagnostics name the generated artifact that claims the name. - Enum `| max = K` below the variant count. - **Duplicate field names anywhere in one type — including across branch diff --git a/docs/USAGE.md b/docs/USAGE.md index 84a399961..95e8925a2 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -112,11 +112,14 @@ zero-initialized enum field is therefore the null, in band, and you never need a separate has-flag beside it: ```cpp -enum class ShipType : uint8_t { None = 0, Fighter = 1, Corvette = 2, Bomber = 3, Max = 3 }; +enum class ShipType : uint8_t { None = 0, Fighter = 1, Corvette = 2, Bomber = 3, Count = 3, Max = 3 }; ``` On the wire it costs `bitsRequired(variant count)` — 2 bits here, for four -values. Declaring `enum E | max = 15` (its variant list on the next line) reserves +values. `None` is one of those values, so an enum whose declared variant +count is a power of two pays one bit for it: four declared variants are five +wire values and cost 3 bits, not 2. Declaring `enum E | max = 15` (its variant +list on the next line) reserves headroom so you can add variants later without moving the field width. @@ -131,6 +134,22 @@ carries it too, so ranges and asserts reference the enum directly instead of a hand-declared count constant. `Max` is consequently reserved as a variant name, like `None`. +The `Count` member beside it is the **declared variant count**, `None` +excluded — `ShipType::Count` (C++), `ShipType.Count` (C#), `ShipTypeCount` +(Go), `ShipType::COUNT` (Rust), `ShipType.Count` (JS), `SHIP_TYPE_COUNT` (C), +`ShipType.count` (Dart and Java), `ShipType.count/0` (Elixir), and +`E.Count` in schema expressions. Without headroom `Count` and `Max` are the +same number; under `| max = 15` they are 3 and 15, and that difference is +what the two words are for. `Count` is a reserved variant name too. + +**Two loop rules, and they are the whole story:** + +- A loop over the **declared variants** runs from `1` to `Count` inclusive. +- A loop over **every ordinal**, `None` included, runs from `0` to `Max` + inclusive. +- **Size storage and keyed arrays by `Max`** — the extent is what has to fit, + headroom and all. + Every target also generates a **debug/log name function**, and the spelling is each target's own: `EnumName(value)` in C++ (overloaded per enum), `EnumNameShipType` in C#/Go/JS, `enumNameShipType` in Dart/Java, and @@ -156,7 +175,8 @@ inline constexpr int64_t CapabilitiesCount = 3; ``` The declared variant count is exported as `Count` and usable in schema -expressions as `Capabilities.Count`. Flags have no `.Max` — the variants are +expressions as `Capabilities.Count` — the same word an enum carries, meaning +the same thing. Flags have no `.Max` — the variants are independent bits, not a range with a top; the compiler refuses `.Max` on a flags type and names `.Count` instead. diff --git a/generated/bench/c/Bench.h b/generated/bench/c/Bench.h index 96af6193f..64bc4902c 100644 --- a/generated/bench/c/Bench.h +++ b/generated/bench/c/Bench.h @@ -103,6 +103,7 @@ typedef uint8_t MixedWeapon; #define MIXED_WEAPON_TURRET 13 #define MIXED_WEAPON_DRONE 14 #define MIXED_WEAPON_REPAIR 15 +#define MIXED_WEAPON_COUNT 15 #define MIXED_WEAPON_MAX 15 /* Debug/log name for any MixedWeapon value, out-of-set included. */ diff --git a/generated/bench/c/RealWorld.h b/generated/bench/c/RealWorld.h index b4dfa7967..5cdd37539 100644 --- a/generated/bench/c/RealWorld.h +++ b/generated/bench/c/RealWorld.h @@ -38,6 +38,7 @@ typedef uint8_t PacketMode; #define PACKET_MODE_COMBAT 3 #define PACKET_MODE_DOCKED 4 #define PACKET_MODE_WARPING 5 +#define PACKET_MODE_COUNT 5 #define PACKET_MODE_MAX 5 /* Debug/log name for any PacketMode value, out-of-set included. */ diff --git a/generated/bench/cpp/Bench.h b/generated/bench/cpp/Bench.h index 547b3ca59..829b5f74b 100644 --- a/generated/bench/cpp/Bench.h +++ b/generated/bench/cpp/Bench.h @@ -85,6 +85,7 @@ enum class MixedWeapon : uint8_t { Turret = 13, Drone = 14, Repair = 15, + Count = 15, // the declared variant count (SPEC §4.2) Max = 15, // the exported extent (SPEC §4.2) }; diff --git a/generated/bench/cpp/RealWorld.h b/generated/bench/cpp/RealWorld.h index 5f6c9534b..b675a4b01 100644 --- a/generated/bench/cpp/RealWorld.h +++ b/generated/bench/cpp/RealWorld.h @@ -22,6 +22,7 @@ enum class PacketMode : uint8_t { Combat = 3, Docked = 4, Warping = 5, + Count = 5, // the declared variant count (SPEC §4.2) Max = 5, // the exported extent (SPEC §4.2) }; diff --git a/generated/bench/cs/Bench.cs b/generated/bench/cs/Bench.cs index bb3e51998..8db7c4f77 100644 --- a/generated/bench/cs/Bench.cs +++ b/generated/bench/cs/Bench.cs @@ -83,6 +83,7 @@ public enum MixedWeapon : byte Turret = 13, Drone = 14, Repair = 15, + Count = 15, // the declared variant count (SPEC §4.2) Max = 15, // the exported extent (SPEC §4.2) } diff --git a/generated/bench/cs/realworld/RealWorld.cs b/generated/bench/cs/realworld/RealWorld.cs index 80dd1a787..43175c97c 100644 --- a/generated/bench/cs/realworld/RealWorld.cs +++ b/generated/bench/cs/realworld/RealWorld.cs @@ -26,6 +26,7 @@ public enum PacketMode : byte Combat = 3, Docked = 4, Warping = 5, + Count = 5, // the declared variant count (SPEC §4.2) Max = 5, // the exported extent (SPEC §4.2) } diff --git a/generated/bench/dart/Bench.dart b/generated/bench/dart/Bench.dart index e7dcbf39c..e6871a25d 100644 --- a/generated/bench/dart/Bench.dart +++ b/generated/bench/dart/Bench.dart @@ -777,6 +777,7 @@ abstract final class MixedWeapon { static const int turret = 13; static const int drone = 14; static const int repair = 15; + static const int count = 15; // the declared variant count (SPEC §4.2) static const int max = 15; // the exported extent (SPEC §4.2) } diff --git a/generated/bench/dart/realworld/RealWorld.dart b/generated/bench/dart/realworld/RealWorld.dart index ae579894b..10b70f03f 100644 --- a/generated/bench/dart/realworld/RealWorld.dart +++ b/generated/bench/dart/realworld/RealWorld.dart @@ -109,6 +109,7 @@ abstract final class PacketMode { static const int combat = 3; static const int docked = 4; static const int warping = 5; + static const int count = 5; // the declared variant count (SPEC §4.2) static const int max = 5; // the exported extent (SPEC §4.2) } diff --git a/generated/bench/elixir/Bench.ex b/generated/bench/elixir/Bench.ex index 643e07a33..52f21a1ca 100644 --- a/generated/bench/elixir/Bench.ex +++ b/generated/bench/elixir/Bench.ex @@ -89,6 +89,8 @@ defmodule Bench.MixedWeapon do def turret, do: 13 def drone, do: 14 def repair, do: 15 + # the declared variant count (SPEC §4.2) + def count, do: 15 # the exported extent (SPEC §4.2) def max, do: 15 end diff --git a/generated/bench/elixir/realworld/RealWorld.ex b/generated/bench/elixir/realworld/RealWorld.ex index baef53732..5fe5c4c8c 100644 --- a/generated/bench/elixir/realworld/RealWorld.ex +++ b/generated/bench/elixir/realworld/RealWorld.ex @@ -40,6 +40,8 @@ defmodule Realworld.PacketMode do def combat, do: 3 def docked, do: 4 def warping, do: 5 + # the declared variant count (SPEC §4.2) + def count, do: 5 # the exported extent (SPEC §4.2) def max, do: 5 end diff --git a/generated/bench/go/Bench.go b/generated/bench/go/Bench.go index 514f1eaf0..4a5bbdf77 100644 --- a/generated/bench/go/Bench.go +++ b/generated/bench/go/Bench.go @@ -359,6 +359,7 @@ const ( MixedWeaponTurret MixedWeapon = 13 MixedWeaponDrone MixedWeapon = 14 MixedWeaponRepair MixedWeapon = 15 + MixedWeaponCount MixedWeapon = 15 // the declared variant count (SPEC §4.2) MixedWeaponMax MixedWeapon = 15 // the exported extent (SPEC §4.2) ) diff --git a/generated/bench/go/realworld/RealWorld.go b/generated/bench/go/realworld/RealWorld.go index 532cf2600..ac8820cac 100644 --- a/generated/bench/go/realworld/RealWorld.go +++ b/generated/bench/go/realworld/RealWorld.go @@ -32,6 +32,7 @@ const ( PacketModeCombat PacketMode = 3 PacketModeDocked PacketMode = 4 PacketModeWarping PacketMode = 5 + PacketModeCount PacketMode = 5 // the declared variant count (SPEC §4.2) PacketModeMax PacketMode = 5 // the exported extent (SPEC §4.2) ) diff --git a/generated/bench/java/Bench.java b/generated/bench/java/Bench.java index 9cf6a6612..ee4d2a17e 100644 --- a/generated/bench/java/Bench.java +++ b/generated/bench/java/Bench.java @@ -1049,6 +1049,8 @@ private MixedWeapon() {} public static final byte turret = 13; public static final byte drone = 14; public static final byte repair = 15; + // the declared variant count (SPEC §4.2) + public static final byte count = 15; // the exported extent (SPEC §4.2) public static final byte max = 15; } diff --git a/generated/bench/java/realworld/RealWorld.java b/generated/bench/java/realworld/RealWorld.java index 33dcfb30d..b0dbe913b 100644 --- a/generated/bench/java/realworld/RealWorld.java +++ b/generated/bench/java/realworld/RealWorld.java @@ -54,6 +54,8 @@ private PacketMode() {} public static final byte combat = 3; public static final byte docked = 4; public static final byte warping = 5; + // the declared variant count (SPEC §4.2) + public static final byte count = 5; // the exported extent (SPEC §4.2) public static final byte max = 5; } diff --git a/generated/bench/js/Bench.js b/generated/bench/js/Bench.js index d0e0d91c1..c4593e8da 100644 --- a/generated/bench/js/Bench.js +++ b/generated/bench/js/Bench.js @@ -456,6 +456,7 @@ export const MixedWeapon = Object.freeze({ Turret: 13, Drone: 14, Repair: 15, + Count: 15, // the declared variant count (SPEC §4.2) Max: 15, // the exported extent (SPEC §4.2) }); diff --git a/generated/bench/js/realworld/RealWorld.js b/generated/bench/js/realworld/RealWorld.js index e481dc600..5f6c1c584 100644 --- a/generated/bench/js/realworld/RealWorld.js +++ b/generated/bench/js/realworld/RealWorld.js @@ -34,6 +34,7 @@ export const PacketMode = Object.freeze({ Combat: 3, Docked: 4, Warping: 5, + Count: 5, // the declared variant count (SPEC §4.2) Max: 5, // the exported extent (SPEC §4.2) }); diff --git a/generated/bench/rust-realworld/src/realworld.rs b/generated/bench/rust-realworld/src/realworld.rs index 3fea7c8e2..0bc45d941 100644 --- a/generated/bench/rust-realworld/src/realworld.rs +++ b/generated/bench/rust-realworld/src/realworld.rs @@ -47,6 +47,7 @@ impl PacketMode { pub const COMBAT: PacketMode = PacketMode(3); pub const DOCKED: PacketMode = PacketMode(4); pub const WARPING: PacketMode = PacketMode(5); + pub const COUNT: PacketMode = PacketMode(5); // the declared variant count (SPEC §4.2) pub const MAX: PacketMode = PacketMode(5); // the exported extent (SPEC §4.2) } diff --git a/generated/bench/rust/src/bench.rs b/generated/bench/rust/src/bench.rs index 075a9af1b..7fb0e5138 100644 --- a/generated/bench/rust/src/bench.rs +++ b/generated/bench/rust/src/bench.rs @@ -459,6 +459,7 @@ impl MixedWeapon { pub const TURRET: MixedWeapon = MixedWeapon(13); pub const DRONE: MixedWeapon = MixedWeapon(14); pub const REPAIR: MixedWeapon = MixedWeapon(15); + pub const COUNT: MixedWeapon = MixedWeapon(15); // the declared variant count (SPEC §4.2) pub const MAX: MixedWeapon = MixedWeapon(15); // the exported extent (SPEC §4.2) } diff --git a/generated/bench/tables/c/BenchTable.h b/generated/bench/tables/c/BenchTable.h index 9bb2ca028..685f5e556 100644 --- a/generated/bench/tables/c/BenchTable.h +++ b/generated/bench/tables/c/BenchTable.h @@ -47,6 +47,7 @@ typedef uint8_t TableWeapon; #define TABLE_WEAPON_TURRET 13 #define TABLE_WEAPON_DRONE 14 #define TABLE_WEAPON_REPAIR 15 +#define TABLE_WEAPON_COUNT 15 #define TABLE_WEAPON_MAX 15 /* Debug/log name for any TableWeapon value, out-of-set included. */ diff --git a/generated/bench/tables/cpp/BenchTable.h b/generated/bench/tables/cpp/BenchTable.h index 4e145dc1c..796a7ba06 100644 --- a/generated/bench/tables/cpp/BenchTable.h +++ b/generated/bench/tables/cpp/BenchTable.h @@ -32,6 +32,7 @@ enum class TableWeapon : uint8_t { Turret = 13, Drone = 14, Repair = 15, + Count = 15, // the declared variant count (SPEC §4.2) Max = 15, // the exported extent (SPEC §4.2) }; diff --git a/generated/bench/tables/cs/BenchTable.cs b/generated/bench/tables/cs/BenchTable.cs index dd9c8f62e..fb0086bde 100644 --- a/generated/bench/tables/cs/BenchTable.cs +++ b/generated/bench/tables/cs/BenchTable.cs @@ -37,6 +37,7 @@ public enum TableWeapon : byte Turret = 13, Drone = 14, Repair = 15, + Count = 15, // the declared variant count (SPEC §4.2) Max = 15, // the exported extent (SPEC §4.2) } diff --git a/generated/bench/tables/dart/BenchTable.dart b/generated/bench/tables/dart/BenchTable.dart index 869e492ad..f0c6998a6 100644 --- a/generated/bench/tables/dart/BenchTable.dart +++ b/generated/bench/tables/dart/BenchTable.dart @@ -56,6 +56,7 @@ abstract final class TableWeapon { static const int turret = 13; static const int drone = 14; static const int repair = 15; + static const int count = 15; // the declared variant count (SPEC §4.2) static const int max = 15; // the exported extent (SPEC §4.2) } diff --git a/generated/bench/tables/elixir/BenchTable.ex b/generated/bench/tables/elixir/BenchTable.ex index 975e2d200..839b83aac 100644 --- a/generated/bench/tables/elixir/BenchTable.ex +++ b/generated/bench/tables/elixir/BenchTable.ex @@ -50,6 +50,8 @@ defmodule Benchtable.TableWeapon do def turret, do: 13 def drone, do: 14 def repair, do: 15 + # the declared variant count (SPEC §4.2) + def count, do: 15 # the exported extent (SPEC §4.2) def max, do: 15 end diff --git a/generated/bench/tables/go/BenchTable.go b/generated/bench/tables/go/BenchTable.go index 2fbcb95a0..e0396667a 100644 --- a/generated/bench/tables/go/BenchTable.go +++ b/generated/bench/tables/go/BenchTable.go @@ -41,6 +41,7 @@ const ( TableWeaponTurret TableWeapon = 13 TableWeaponDrone TableWeapon = 14 TableWeaponRepair TableWeapon = 15 + TableWeaponCount TableWeapon = 15 // the declared variant count (SPEC §4.2) TableWeaponMax TableWeapon = 15 // the exported extent (SPEC §4.2) ) diff --git a/generated/bench/tables/java/BenchTable.java b/generated/bench/tables/java/BenchTable.java index 95f5f2349..6c383e646 100644 --- a/generated/bench/tables/java/BenchTable.java +++ b/generated/bench/tables/java/BenchTable.java @@ -64,6 +64,8 @@ private TableWeapon() {} public static final byte turret = 13; public static final byte drone = 14; public static final byte repair = 15; + // the declared variant count (SPEC §4.2) + public static final byte count = 15; // the exported extent (SPEC §4.2) public static final byte max = 15; } diff --git a/generated/bench/tables/js/BenchTable.js b/generated/bench/tables/js/BenchTable.js index 13ac46250..6c470e5e3 100644 --- a/generated/bench/tables/js/BenchTable.js +++ b/generated/bench/tables/js/BenchTable.js @@ -43,6 +43,7 @@ export const TableWeapon = Object.freeze({ Turret: 13, Drone: 14, Repair: 15, + Count: 15, // the declared variant count (SPEC §4.2) Max: 15, // the exported extent (SPEC §4.2) }); diff --git a/generated/bench/tables/rust/src/benchtable.rs b/generated/bench/tables/rust/src/benchtable.rs index f50983d71..86d4bbe5b 100644 --- a/generated/bench/tables/rust/src/benchtable.rs +++ b/generated/bench/tables/rust/src/benchtable.rs @@ -57,6 +57,7 @@ impl TableWeapon { pub const TURRET: TableWeapon = TableWeapon(13); pub const DRONE: TableWeapon = TableWeapon(14); pub const REPAIR: TableWeapon = TableWeapon(15); + pub const COUNT: TableWeapon = TableWeapon(15); // the declared variant count (SPEC §4.2) pub const MAX: TableWeapon = TableWeapon(15); // the exported extent (SPEC §4.2) } diff --git a/generated/c-ludicrous/Ludicrous.h b/generated/c-ludicrous/Ludicrous.h index 4ad9d97de..6b52ce62e 100644 --- a/generated/c-ludicrous/Ludicrous.h +++ b/generated/c-ludicrous/Ludicrous.h @@ -38,6 +38,7 @@ typedef uint8_t DriveMode; #define DRIVE_MODE_CRUISE 1 #define DRIVE_MODE_WARP 2 #define DRIVE_MODE_LUDICROUS 3 +#define DRIVE_MODE_COUNT 3 #define DRIVE_MODE_MAX 3 /* Debug/log name for any DriveMode value, out-of-set included. */ diff --git a/generated/c/Enums.h b/generated/c/Enums.h index 6f3442d90..195e8f6b1 100644 --- a/generated/c/Enums.h +++ b/generated/c/Enums.h @@ -30,6 +30,7 @@ typedef uint8_t Team; #define TEAM_NONE 0 #define TEAM_RED 1 #define TEAM_BLUE 2 +#define TEAM_COUNT 2 #define TEAM_MAX 2 /* Debug/log name for any Team value, out-of-set included. */ @@ -56,6 +57,7 @@ typedef uint8_t ShipType; #define SHIP_TYPE_BOMBER 3 #define SHIP_TYPE_DESTROYER 4 #define SHIP_TYPE_CARRIER 5 +#define SHIP_TYPE_COUNT 5 #define SHIP_TYPE_MAX 5 /* Debug/log name for any ShipType value, out-of-set included. */ @@ -83,6 +85,7 @@ typedef uint8_t MissileType; #define MISSILE_TYPE_HEATSEEKER 1 #define MISSILE_TYPE_TORPEDO 2 #define MISSILE_TYPE_NUKE 3 +#define MISSILE_TYPE_COUNT 3 #define MISSILE_TYPE_MAX 3 /* Debug/log name for any MissileType value, out-of-set included. */ @@ -111,6 +114,7 @@ typedef uint8_t PropType; #define PROP_TYPE_SPHERE 4 #define PROP_TYPE_BLACK_HOLE 5 #define PROP_TYPE_DYSON_PANEL 6 +#define PROP_TYPE_COUNT 6 #define PROP_TYPE_MAX 6 /* Debug/log name for any PropType value, out-of-set included. */ @@ -136,6 +140,7 @@ static SCHEMA_UNUSED const char * enum_name_prop_type( PropType value ) values wire-legal, which a C enum cannot hold honestly. */ typedef uint8_t Pending; #define PENDING_NONE 0 +#define PENDING_COUNT 0 #define PENDING_MAX 0 /* Debug/log name for any Pending value, out-of-set included. */ diff --git a/generated/c/Wire.h b/generated/c/Wire.h index 12e50b4ce..ba7481ce8 100644 --- a/generated/c/Wire.h +++ b/generated/c/Wire.h @@ -37,6 +37,7 @@ typedef uint8_t Weapon; #define WEAPON_LASER 1 #define WEAPON_MISSILE 2 #define WEAPON_RAILGUN 3 +#define WEAPON_COUNT 3 #define WEAPON_MAX 15 /* Debug/log name for any Weapon value, out-of-set included. */ diff --git a/generated/cpp/Enums.h b/generated/cpp/Enums.h index c5edf6869..7efbf3994 100644 --- a/generated/cpp/Enums.h +++ b/generated/cpp/Enums.h @@ -15,6 +15,7 @@ enum class Team : uint8_t { None = 0, Red = 1, Blue = 2, + Count = 2, // the declared variant count (SPEC §4.2) Max = 2, // the exported extent (SPEC §4.2) }; @@ -38,6 +39,7 @@ enum class ShipType : uint8_t { Bomber = 3, Destroyer = 4, Carrier = 5, + Count = 5, // the declared variant count (SPEC §4.2) Max = 5, // the exported extent (SPEC §4.2) }; @@ -62,6 +64,7 @@ enum class MissileType : uint8_t { Heatseeker = 1, Torpedo = 2, Nuke = 3, + Count = 3, // the declared variant count (SPEC §4.2) Max = 3, // the exported extent (SPEC §4.2) }; @@ -87,6 +90,7 @@ enum class PropType : uint8_t { Sphere = 4, BlackHole = 5, DysonPanel = 6, + Count = 6, // the declared variant count (SPEC §4.2) Max = 6, // the exported extent (SPEC §4.2) }; @@ -109,6 +113,7 @@ inline const char * EnumName( PropType value ) // enum Pending — None = 0 implicit, variants dense from 1, wire range [0, 0] (SPEC §4.2) enum class Pending : uint8_t { None = 0, + Count = 0, // the declared variant count (SPEC §4.2) Max = 0, // the exported extent (SPEC §4.2) }; diff --git a/generated/cpp/Wire.h b/generated/cpp/Wire.h index 3af7d3ddf..c45be4d67 100644 --- a/generated/cpp/Wire.h +++ b/generated/cpp/Wire.h @@ -22,6 +22,7 @@ enum class Weapon : uint8_t { Laser = 1, Missile = 2, Railgun = 3, + Count = 3, // the declared variant count (SPEC §4.2) Max = 15, // the exported extent (SPEC §4.2) }; diff --git a/generated/cpp/ludicrous/Ludicrous.h b/generated/cpp/ludicrous/Ludicrous.h index 40d94ed07..df1f42bb9 100644 --- a/generated/cpp/ludicrous/Ludicrous.h +++ b/generated/cpp/ludicrous/Ludicrous.h @@ -23,6 +23,7 @@ enum class DriveMode : uint8_t { Cruise = 1, Warp = 2, Ludicrous = 3, + Count = 3, // the declared variant count (SPEC §4.2) Max = 3, // the exported extent (SPEC §4.2) }; diff --git a/generated/cs-ludicrous/Ludicrous.cs b/generated/cs-ludicrous/Ludicrous.cs index 209b724a8..0b964fd80 100644 --- a/generated/cs-ludicrous/Ludicrous.cs +++ b/generated/cs-ludicrous/Ludicrous.cs @@ -25,6 +25,7 @@ public enum DriveMode : byte Cruise = 1, Warp = 2, Ludicrous = 3, + Count = 3, // the declared variant count (SPEC §4.2) Max = 3, // the exported extent (SPEC §4.2) } diff --git a/generated/cs/Enums.cs b/generated/cs/Enums.cs index 5e1f8664f..299b655a4 100644 --- a/generated/cs/Enums.cs +++ b/generated/cs/Enums.cs @@ -15,6 +15,7 @@ public enum Team : byte None = 0, Red = 1, Blue = 2, + Count = 2, // the declared variant count (SPEC §4.2) Max = 2, // the exported extent (SPEC §4.2) } @@ -29,6 +30,7 @@ public enum ShipType : byte Bomber = 3, Destroyer = 4, Carrier = 5, + Count = 5, // the declared variant count (SPEC §4.2) Max = 5, // the exported extent (SPEC §4.2) } @@ -41,6 +43,7 @@ public enum MissileType : byte Heatseeker = 1, Torpedo = 2, Nuke = 3, + Count = 3, // the declared variant count (SPEC §4.2) Max = 3, // the exported extent (SPEC §4.2) } @@ -56,6 +59,7 @@ public enum PropType : byte Sphere = 4, BlackHole = 5, DysonPanel = 6, + Count = 6, // the declared variant count (SPEC §4.2) Max = 6, // the exported extent (SPEC §4.2) } @@ -65,6 +69,7 @@ public enum PropType : byte public enum Pending : byte { None = 0, + Count = 0, // the declared variant count (SPEC §4.2) Max = 0, // the exported extent (SPEC §4.2) } diff --git a/generated/cs/Wire.cs b/generated/cs/Wire.cs index 116d9e650..df7a4d101 100644 --- a/generated/cs/Wire.cs +++ b/generated/cs/Wire.cs @@ -20,6 +20,7 @@ public enum Weapon : byte Laser = 1, Missile = 2, Railgun = 3, + Count = 3, // the declared variant count (SPEC §4.2) Max = 15, // the exported extent (SPEC §4.2) } diff --git a/generated/dart-ludicrous/Ludicrous.dart b/generated/dart-ludicrous/Ludicrous.dart index 13873a5c3..448c0490f 100644 --- a/generated/dart-ludicrous/Ludicrous.dart +++ b/generated/dart-ludicrous/Ludicrous.dart @@ -47,6 +47,7 @@ abstract final class DriveMode { static const int cruise = 1; static const int warp = 2; static const int ludicrous = 3; + static const int count = 3; // the declared variant count (SPEC §4.2) static const int max = 3; // the exported extent (SPEC §4.2) } diff --git a/generated/dart/Enums.dart b/generated/dart/Enums.dart index 50de5ef18..9fa13de93 100644 --- a/generated/dart/Enums.dart +++ b/generated/dart/Enums.dart @@ -19,6 +19,7 @@ abstract final class Team { static const int none = 0; static const int red = 1; static const int blue = 2; + static const int count = 2; // the declared variant count (SPEC §4.2) static const int max = 2; // the exported extent (SPEC §4.2) } @@ -48,6 +49,7 @@ abstract final class ShipType { static const int bomber = 3; static const int destroyer = 4; static const int carrier = 5; + static const int count = 5; // the declared variant count (SPEC §4.2) static const int max = 5; // the exported extent (SPEC §4.2) } @@ -81,6 +83,7 @@ abstract final class MissileType { static const int heatseeker = 1; static const int torpedo = 2; static const int nuke = 3; + static const int count = 3; // the declared variant count (SPEC §4.2) static const int max = 3; // the exported extent (SPEC §4.2) } @@ -113,6 +116,7 @@ abstract final class PropType { static const int sphere = 4; static const int blackHole = 5; static const int dysonPanel = 6; + static const int count = 6; // the declared variant count (SPEC §4.2) static const int max = 6; // the exported extent (SPEC §4.2) } @@ -145,6 +149,7 @@ String enumNamePropType(int value) { // headroom values have no Dart enum member to be abstract final class Pending { static const int none = 0; + static const int count = 0; // the declared variant count (SPEC §4.2) static const int max = 0; // the exported extent (SPEC §4.2) } diff --git a/generated/dart/Wire.dart b/generated/dart/Wire.dart index 44137c792..cd2917b9e 100644 --- a/generated/dart/Wire.dart +++ b/generated/dart/Wire.dart @@ -95,6 +95,7 @@ abstract final class Weapon { static const int laser = 1; static const int missile = 2; static const int railgun = 3; + static const int count = 3; // the declared variant count (SPEC §4.2) static const int max = 15; // the exported extent (SPEC §4.2) } diff --git a/generated/elixir-ludicrous/Ludicrous.ex b/generated/elixir-ludicrous/Ludicrous.ex index 0cee0e7c7..54d8f9fd8 100644 --- a/generated/elixir-ludicrous/Ludicrous.ex +++ b/generated/elixir-ludicrous/Ludicrous.ex @@ -38,6 +38,8 @@ defmodule Ludicrous.DriveMode do def cruise, do: 1 def warp, do: 2 def ludicrous, do: 3 + # the declared variant count (SPEC §4.2) + def count, do: 3 # the exported extent (SPEC §4.2) def max, do: 3 end diff --git a/generated/elixir/Enums.ex b/generated/elixir/Enums.ex index 1532f3f30..fbba6b378 100644 --- a/generated/elixir/Enums.ex +++ b/generated/elixir/Enums.ex @@ -12,6 +12,8 @@ defmodule Example.Team do def none, do: 0 def red, do: 1 def blue, do: 2 + # the declared variant count (SPEC §4.2) + def count, do: 2 # the exported extent (SPEC §4.2) def max, do: 2 end @@ -27,6 +29,8 @@ defmodule Example.ShipType do def bomber, do: 3 def destroyer, do: 4 def carrier, do: 5 + # the declared variant count (SPEC §4.2) + def count, do: 5 # the exported extent (SPEC §4.2) def max, do: 5 end @@ -40,6 +44,8 @@ defmodule Example.MissileType do def heatseeker, do: 1 def torpedo, do: 2 def nuke, do: 3 + # the declared variant count (SPEC §4.2) + def count, do: 3 # the exported extent (SPEC §4.2) def max, do: 3 end @@ -56,6 +62,8 @@ defmodule Example.PropType do def sphere, do: 4 def black_hole, do: 5 def dyson_panel, do: 6 + # the declared variant count (SPEC §4.2) + def count, do: 6 # the exported extent (SPEC §4.2) def max, do: 6 end @@ -66,6 +74,8 @@ end # | max = ... headroom values have no richer Elixir value to be defmodule Example.Pending do def none, do: 0 + # the declared variant count (SPEC §4.2) + def count, do: 0 # the exported extent (SPEC §4.2) def max, do: 0 end diff --git a/generated/elixir/Wire.ex b/generated/elixir/Wire.ex index 16ab11553..3393b8781 100644 --- a/generated/elixir/Wire.ex +++ b/generated/elixir/Wire.ex @@ -13,6 +13,8 @@ defmodule Example.Weapon do def laser, do: 1 def missile, do: 2 def railgun, do: 3 + # the declared variant count (SPEC §4.2) + def count, do: 3 # the exported extent (SPEC §4.2) def max, do: 15 end diff --git a/generated/go-ludicrous/Ludicrous.go b/generated/go-ludicrous/Ludicrous.go index 892046a78..e1a5259b6 100644 --- a/generated/go-ludicrous/Ludicrous.go +++ b/generated/go-ludicrous/Ludicrous.go @@ -30,6 +30,7 @@ const ( DriveModeCruise DriveMode = 1 DriveModeWarp DriveMode = 2 DriveModeLudicrous DriveMode = 3 + DriveModeCount DriveMode = 3 // the declared variant count (SPEC §4.2) DriveModeMax DriveMode = 3 // the exported extent (SPEC §4.2) ) diff --git a/generated/go/Enums.go b/generated/go/Enums.go index dd4c07e76..78dc79031 100644 --- a/generated/go/Enums.go +++ b/generated/go/Enums.go @@ -14,10 +14,11 @@ import ( type Team uint8 const ( - TeamNone Team = 0 - TeamRed Team = 1 - TeamBlue Team = 2 - TeamMax Team = 2 // the exported extent (SPEC §4.2) + TeamNone Team = 0 + TeamRed Team = 1 + TeamBlue Team = 2 + TeamCount Team = 2 // the declared variant count (SPEC §4.2) + TeamMax Team = 2 // the exported extent (SPEC §4.2) ) // EnumNameTeam: debug/log/tooling name for any Team wire value — @@ -44,6 +45,7 @@ const ( ShipTypeBomber ShipType = 3 ShipTypeDestroyer ShipType = 4 ShipTypeCarrier ShipType = 5 + ShipTypeCount ShipType = 5 // the declared variant count (SPEC §4.2) ShipTypeMax ShipType = 5 // the exported extent (SPEC §4.2) ) @@ -75,6 +77,7 @@ const ( MissileTypeHeatseeker MissileType = 1 MissileTypeTorpedo MissileType = 2 MissileTypeNuke MissileType = 3 + MissileTypeCount MissileType = 3 // the declared variant count (SPEC §4.2) MissileTypeMax MissileType = 3 // the exported extent (SPEC §4.2) ) @@ -105,6 +108,7 @@ const ( PropTypeSphere PropType = 4 PropTypeBlackHole PropType = 5 PropTypeDysonPanel PropType = 6 + PropTypeCount PropType = 6 // the declared variant count (SPEC §4.2) PropTypeMax PropType = 6 // the exported extent (SPEC §4.2) ) @@ -134,8 +138,9 @@ func EnumNamePropType(value uint64) string { type Pending uint8 const ( - PendingNone Pending = 0 - PendingMax Pending = 0 // the exported extent (SPEC §4.2) + PendingNone Pending = 0 + PendingCount Pending = 0 // the declared variant count (SPEC §4.2) + PendingMax Pending = 0 // the exported extent (SPEC §4.2) ) // EnumNamePending: debug/log/tooling name for any Pending wire value — diff --git a/generated/go/Wire.go b/generated/go/Wire.go index f081af11e..4d99c775f 100644 --- a/generated/go/Wire.go +++ b/generated/go/Wire.go @@ -29,6 +29,7 @@ const ( WeaponLaser Weapon = 1 WeaponMissile Weapon = 2 WeaponRailgun Weapon = 3 + WeaponCount Weapon = 3 // the declared variant count (SPEC §4.2) WeaponMax Weapon = 15 // the exported extent (SPEC §4.2) ) diff --git a/generated/java-ludicrous/Ludicrous.java b/generated/java-ludicrous/Ludicrous.java index 2947d5a28..897cb4a39 100644 --- a/generated/java-ludicrous/Ludicrous.java +++ b/generated/java-ludicrous/Ludicrous.java @@ -54,6 +54,8 @@ private DriveMode() {} public static final byte cruise = 1; public static final byte warp = 2; public static final byte ludicrous = 3; + // the declared variant count (SPEC §4.2) + public static final byte count = 3; // the exported extent (SPEC §4.2) public static final byte max = 3; } diff --git a/generated/java/Enums.java b/generated/java/Enums.java index ae28335b7..c2d99d07d 100644 --- a/generated/java/Enums.java +++ b/generated/java/Enums.java @@ -22,6 +22,8 @@ private Team() {} public static final byte none = 0; public static final byte red = 1; public static final byte blue = 2; + // the declared variant count (SPEC §4.2) + public static final byte count = 2; // the exported extent (SPEC §4.2) public static final byte max = 2; } @@ -54,6 +56,8 @@ private ShipType() {} public static final byte bomber = 3; public static final byte destroyer = 4; public static final byte carrier = 5; + // the declared variant count (SPEC §4.2) + public static final byte count = 5; // the exported extent (SPEC §4.2) public static final byte max = 5; } @@ -93,6 +97,8 @@ private MissileType() {} public static final byte heatseeker = 1; public static final byte torpedo = 2; public static final byte nuke = 3; + // the declared variant count (SPEC §4.2) + public static final byte count = 3; // the exported extent (SPEC §4.2) public static final byte max = 3; } @@ -129,6 +135,8 @@ private PropType() {} public static final byte sphere = 4; public static final byte blackHole = 5; public static final byte dysonPanel = 6; + // the declared variant count (SPEC §4.2) + public static final byte count = 6; // the exported extent (SPEC §4.2) public static final byte max = 6; } @@ -168,6 +176,8 @@ public static final class Pending { private Pending() {} public static final byte none = 0; + // the declared variant count (SPEC §4.2) + public static final byte count = 0; // the exported extent (SPEC §4.2) public static final byte max = 0; } diff --git a/generated/java/Wire.java b/generated/java/Wire.java index 61550a14b..79d7b7a94 100644 --- a/generated/java/Wire.java +++ b/generated/java/Wire.java @@ -37,6 +37,8 @@ private Weapon() {} public static final byte laser = 1; public static final byte missile = 2; public static final byte railgun = 3; + // the declared variant count (SPEC §4.2) + public static final byte count = 3; // the exported extent (SPEC §4.2) public static final byte max = 15; } diff --git a/generated/js-ludicrous/Ludicrous.js b/generated/js-ludicrous/Ludicrous.js index e2fe24022..7f8957b0f 100644 --- a/generated/js-ludicrous/Ludicrous.js +++ b/generated/js-ludicrous/Ludicrous.js @@ -34,6 +34,7 @@ export const DriveMode = Object.freeze({ Cruise: 1, Warp: 2, Ludicrous: 3, + Count: 3, // the declared variant count (SPEC §4.2) Max: 3, // the exported extent (SPEC §4.2) }); diff --git a/generated/js/Enums.js b/generated/js/Enums.js index 57e6027e9..8537cf651 100644 --- a/generated/js/Enums.js +++ b/generated/js/Enums.js @@ -11,6 +11,7 @@ export const Team = Object.freeze({ None: 0, Red: 1, Blue: 2, + Count: 2, // the declared variant count (SPEC §4.2) Max: 2, // the exported extent (SPEC §4.2) }); @@ -39,6 +40,7 @@ export const ShipType = Object.freeze({ Bomber: 3, Destroyer: 4, Carrier: 5, + Count: 5, // the declared variant count (SPEC §4.2) Max: 5, // the exported extent (SPEC §4.2) }); @@ -71,6 +73,7 @@ export const MissileType = Object.freeze({ Heatseeker: 1, Torpedo: 2, Nuke: 3, + Count: 3, // the declared variant count (SPEC §4.2) Max: 3, // the exported extent (SPEC §4.2) }); @@ -102,6 +105,7 @@ export const PropType = Object.freeze({ Sphere: 4, BlackHole: 5, DysonPanel: 6, + Count: 6, // the declared variant count (SPEC §4.2) Max: 6, // the exported extent (SPEC §4.2) }); @@ -133,6 +137,7 @@ export function EnumNamePropType(value) { // integer-backed enums; | max = ... headroom values are plain Numbers export const Pending = Object.freeze({ None: 0, + Count: 0, // the declared variant count (SPEC §4.2) Max: 0, // the exported extent (SPEC §4.2) }); diff --git a/generated/js/Wire.js b/generated/js/Wire.js index d2bdb0e08..6501b09f8 100644 --- a/generated/js/Wire.js +++ b/generated/js/Wire.js @@ -28,6 +28,7 @@ export const Weapon = Object.freeze({ Laser: 1, Missile: 2, Railgun: 3, + Count: 3, // the declared variant count (SPEC §4.2) Max: 15, // the exported extent (SPEC §4.2) }); diff --git a/generated/rust-ludicrous/src/ludicrous.rs b/generated/rust-ludicrous/src/ludicrous.rs index 8e17c3463..39c8b778e 100644 --- a/generated/rust-ludicrous/src/ludicrous.rs +++ b/generated/rust-ludicrous/src/ludicrous.rs @@ -47,6 +47,7 @@ impl DriveMode { pub const CRUISE: DriveMode = DriveMode(1); pub const WARP: DriveMode = DriveMode(2); pub const LUDICROUS: DriveMode = DriveMode(3); + pub const COUNT: DriveMode = DriveMode(3); // the declared variant count (SPEC §4.2) pub const MAX: DriveMode = DriveMode(3); // the exported extent (SPEC §4.2) } diff --git a/generated/rust/src/enums.rs b/generated/rust/src/enums.rs index 685c1b0bf..b75ab5673 100644 --- a/generated/rust/src/enums.rs +++ b/generated/rust/src/enums.rs @@ -14,6 +14,7 @@ impl Team { pub const NONE: Team = Team(0); pub const RED: Team = Team(1); pub const BLUE: Team = Team(2); + pub const COUNT: Team = Team(2); // the declared variant count (SPEC §4.2) pub const MAX: Team = Team(2); // the exported extent (SPEC §4.2) } @@ -40,6 +41,7 @@ impl ShipType { pub const BOMBER: ShipType = ShipType(3); pub const DESTROYER: ShipType = ShipType(4); pub const CARRIER: ShipType = ShipType(5); + pub const COUNT: ShipType = ShipType(5); // the declared variant count (SPEC §4.2) pub const MAX: ShipType = ShipType(5); // the exported extent (SPEC §4.2) } @@ -67,6 +69,7 @@ impl MissileType { pub const HEATSEEKER: MissileType = MissileType(1); pub const TORPEDO: MissileType = MissileType(2); pub const NUKE: MissileType = MissileType(3); + pub const COUNT: MissileType = MissileType(3); // the declared variant count (SPEC §4.2) pub const MAX: MissileType = MissileType(3); // the exported extent (SPEC §4.2) } @@ -95,6 +98,7 @@ impl PropType { pub const SPHERE: PropType = PropType(4); pub const BLACK_HOLE: PropType = PropType(5); pub const DYSON_PANEL: PropType = PropType(6); + pub const COUNT: PropType = PropType(6); // the declared variant count (SPEC §4.2) pub const MAX: PropType = PropType(6); // the exported extent (SPEC §4.2) } @@ -120,6 +124,7 @@ pub struct Pending(pub u8); impl Pending { pub const NONE: Pending = Pending(0); + pub const COUNT: Pending = Pending(0); // the declared variant count (SPEC §4.2) pub const MAX: Pending = Pending(0); // the exported extent (SPEC §4.2) } diff --git a/generated/rust/src/wire.rs b/generated/rust/src/wire.rs index e3ecae369..e1c75686b 100644 --- a/generated/rust/src/wire.rs +++ b/generated/rust/src/wire.rs @@ -26,6 +26,7 @@ impl Weapon { pub const LASER: Weapon = Weapon(1); pub const MISSILE: Weapon = Weapon(2); pub const RAILGUN: Weapon = Weapon(3); + pub const COUNT: Weapon = Weapon(3); // the declared variant count (SPEC §4.2) pub const MAX: Weapon = Weapon(15); // the exported extent (SPEC §4.2) } diff --git a/internal/ast/ast.go b/internal/ast/ast.go index 90439ead5..d137f07e6 100644 --- a/internal/ast/ast.go +++ b/internal/ast/ast.go @@ -251,8 +251,9 @@ type StringLit struct { Value string // without the quotes } -// MaxExpr is a set-extent reference: E.Max on an enum or generated set, and -// F.Count on a flags declaration (SPEC §4.2). Sel is "Max" or "Count". +// MaxExpr is a set reference: E.Max, the extent of an enum or a generated +// set, and E.Count, the declared variant count of an enum or a flags +// declaration (SPEC §4.2). Sel is "Max" or "Count". type MaxExpr struct { Pos Pos Enum string diff --git a/internal/check/check.go b/internal/check/check.go index dac119cfb..1fc3a1b56 100644 --- a/internal/check/check.go +++ b/internal/check/check.go @@ -531,7 +531,7 @@ var valuedAttr = map[string]bool{ func (c *checker) enumMax(e *ast.MaxExpr) (*big.Int, bool) { if e.Sel == "Count" { - return c.flagsCount(e) + return c.declaredCount(e) } d, ok := c.astDecls[e.Enum] if !ok { @@ -569,25 +569,34 @@ func (c *checker) enumMax(e *ast.MaxExpr) (*big.Int, bool) { return big.NewInt(en.Max), true } -// flagsCount resolves F.Count (SPEC §4.2): the DECLARED variant count of a -// flags declaration — not the wire width, which a | max = K widening can -// raise above it. -func (c *checker) flagsCount(e *ast.MaxExpr) (*big.Int, bool) { +// declaredCount resolves E.Count (SPEC §4.2): the DECLARED variant count of +// an enum or a flags declaration — one word meaning one thing in both. It +// excludes an enum's implicit None, and it is not the wire extent: under +// | max = K headroom an enum's Max and a flags declaration's wire width rise +// above the count, and Count stays the count. Unlike .Max it needs no bound, +// so an enum whose | max = ... failed to resolve still answers it exactly. +func (c *checker) declaredCount(e *ast.MaxExpr) (*big.Int, bool) { d, ok := c.astDecls[e.Enum] if !ok { - c.errf(e.Pos, "undefined flags %s in %s.Count", e.Enum, e.Enum) + c.errf(e.Pos, "undefined enum or flags %s in %s.Count", e.Enum, e.Enum) return nil, false } - fd, ok := d.(*ast.FlagsDecl) - if !ok { - c.errf(e.Pos, "%s is not a flags declaration — .Count names a flags declaration's variant count; an enum's extent is %s.Max (SPEC §4.2)", e.Enum, e.Enum) - return nil, false - } - fl := c.resolveFlags(fd) - if fl == nil { - return nil, false + switch d := d.(type) { + case *ast.FlagsDecl: + fl := c.resolveFlags(d) + if fl == nil { + return nil, false + } + return big.NewInt(int64(len(fl.Variants))), true + case *ast.EnumDecl: + en := c.resolveEnum(d) + if en == nil { + return nil, false + } + return big.NewInt(int64(len(en.Variants))), true } - return big.NewInt(int64(len(fl.Variants))), true + c.errf(e.Pos, "%s is neither an enum nor a flags declaration — .Count names a declared variant count (SPEC §4.2)", e.Enum) + return nil, false } // generatedSetMax resolves E.Max over the GENERATED tag set (SPEC §4.2, @@ -648,6 +657,10 @@ func (c *checker) resolveEnum(d *ast.EnumDecl) *ir.Enum { c.errf(v.Pos, "variant Max is a compile error — every generated enum carries its extent as the member Max, the same number E.Max names (SPEC §4.2)") continue } + if v.Text == "Count" { + c.errf(v.Pos, "variant Count is a compile error — every generated enum carries its declared variant count as the member Count, the same number E.Count names (SPEC §4.2)") + continue + } if seen[v.Text] { c.errf(v.Pos, "duplicate variant %s", v.Text) continue @@ -2871,7 +2884,12 @@ func (c *checker) checkClaimedNames() { // including against the implicit NONE add(name+"None", fmt.Sprintf("enum %s's generated None constant", name), d.Pos) add(name+"Max", fmt.Sprintf("enum %s's generated Max extent (Go form)", name), d.Pos) - assoc := map[string]string{"NONE": "the implicit None variant", "MAX": "the generated Max extent"} + add(name+"Count", fmt.Sprintf("enum %s's generated Count constant (Go form)", name), d.Pos) + assoc := map[string]string{ + "NONE": "the implicit None variant", + "MAX": "the generated Max extent", + "COUNT": "the generated Count constant", + } for _, v := range d.Variants { add(name+v.Text, fmt.Sprintf("enum %s's generated variant constant", name), v.Pos) rv := ir.RustConstName(v.Text) @@ -2883,14 +2901,15 @@ func (c *checker) checkClaimedNames() { } } // the C target flattens variants as #define ENUM_VARIANT into the - // one preprocessor namespace, plus _NONE, _MAX and the debug-name - // function — spellings no other claim covers (they were + // one preprocessor namespace, plus _NONE, _MAX, _COUNT and the + // debug-name function — spellings no other claim covers (they were // emitted and never registered, so a const like DriveModeLudicrous // beside enum DriveMode { Ludicrous } produced a silent duplicate // #define in C while every other target compiled) whyC := fmt.Sprintf("enum %s's generated variant constants (C form)", name) addRust(ir.RustConstName(name)+"_NONE", whyC, d.Pos, name+"None") addRust(ir.RustConstName(name)+"_MAX", whyC, d.Pos) + addRust(ir.RustConstName(name)+"_COUNT", whyC, d.Pos, name+"Count") addRust("enum_name_"+ir.RustSnake(name), fmt.Sprintf("enum %s's generated debug-name function (C form)", name), d.Pos) for _, v := range d.Variants { addRust(ir.RustConstName(name)+"_"+ir.RustConstName(v.Text), whyC, v.Pos, name+v.Text) diff --git a/internal/check/diagnostics_test.go b/internal/check/diagnostics_test.go index 6d69bf809..9b532a784 100644 --- a/internal/check/diagnostics_test.go +++ b/internal/check/diagnostics_test.go @@ -233,10 +233,14 @@ func TestDiagnostics(t *testing.T) { src: "package t\ntype V { x uint8 }\nconst N = V.Max + 1\n"}, {name: "Max reference to a flags declaration", want: "has no .Max", src: "package t\nflags F { A, B }\nconst N = F.Max\n"}, - {name: "Count reference to an enum", want: "is not a flags declaration", - src: "package t\nenum E { A }\nconst N = E.Count\n"}, - {name: "Count reference undefined", want: "undefined flags", + {name: "Count reference to a non-enum, non-flags declaration", want: "neither an enum nor a flags declaration", + src: "package t\ntype V { x uint8 }\nconst N = V.Count\n"}, + {name: "Count reference undefined", want: "undefined enum or flags", src: "package t\nconst N = F.Count\n"}, + {name: "variant named Count", want: "carries its declared variant count as the member Count", + src: "package t\nenum E { A, Count }\n"}, + {name: "a decl collides with an enum's generated Count constant (Go)", want: "generated Count constant", + src: "package t\nenum Weapon { Laser }\nconst WeaponCount = 3\n"}, {name: "65 flags variants overflow uint64 storage", want: "one bit per variant, up to 64", src: "package t\nflags F { " + flags65 + " }\n"}, // ---- unions (SPEC §4.8) ---- @@ -506,6 +510,10 @@ func TestGoodCornersStillCompile(t *testing.T) { src: "package t\nflags F { " + strings.Replace(flags65, ", V64", "", 1) + " }\n"}, {name: "F.Count in a constant expression", src: "package t\nflags F { A, B }\nconst N = F.Count\n"}, + {name: "E.Count in a constant expression, headroom included", + src: "package t\nenum E | max = 15\n{ A, B }\nconst N = E.Count\n"}, + {name: "E.Count as an array bound", + src: "package t\nenum E | max = 15\n{ A, B }\ntype T { xs [..E.Count]uint8 }\n"}, {name: "a // comment terminates the qualification section", src: "package t\ntype T { h int16 | min = 0, max = 5 // the section ends here\n}\n"}, {name: "a qualified declaration's body opens on the next line", diff --git a/internal/check/projection_test.go b/internal/check/projection_test.go index 8ddb53fb1..249011edc 100644 --- a/internal/check/projection_test.go +++ b/internal/check/projection_test.go @@ -250,6 +250,75 @@ const WideN = Wide.Count } } +// E.Count is the DECLARED variant count of an enum, excluding the implicit +// None (SPEC §4.2). It equals E.Max when nothing widens the enum and stays +// the count under | max = K headroom, where Max is the extent — so the two +// words mean one thing each, in enums and flags alike, and a bound written +// over either folds to the number the author asked for. +func TestEnumCountValue(t *testing.T) { + u := build(t, `package probe + +enum Plain { Laser, Missile } + +enum Wide | max = 15 +{ + Laser, + Missile, + Railgun, +} + +const PlainN = Plain.Count +const PlainM = Plain.Max +const WideN = Wide.Count +const WideM = Wide.Max + +type Loadout { + slots [..Wide.Count]uint8 + keyed [Wide.Max]uint8 +} +`) + for _, tc := range []struct { + name string + want int64 + }{{"PlainN", 2}, {"PlainM", 2}, {"WideN", 3}, {"WideM", 15}} { + c := u.Consts[tc.name] + if c == nil || c.Int == nil || c.Int.Int64() != tc.want { + t.Errorf("const %s: want %d, got %v — Count is the declared count and Max the extent (SPEC §4.2)", tc.name, tc.want, c) + } + } + fields := u.Structs["Loadout"].Fields + if got := fields[0].ArrayBound; got != 3 { + t.Errorf("[..Wide.Count]uint8 bound = %d, want 3 — E.Count must fold in an array bound", got) + } + if got := fields[1].ArrayBound; got != 15 { + t.Errorf("[Wide.Max]uint8 bound = %d, want 15 — E.Max stays the extent beside E.Count", got) + } +} + +// The generated Count is a CLAIMED name (SPEC §11): a user symbol that would +// collide with it is refused, and the diagnostic names the enum it belongs to +// — the same claim E.Max's generated twin has carried since it existed. +func TestEnumCountIsClaimed(t *testing.T) { + source := "package probe\n\nenum Weapon { Laser, Missile }\n\nconst WeaponCount = 3\n" + f, perrs := parser.Parse("Probe.schema", []byte(source)) + if len(perrs) > 0 { + t.Fatalf("parse: %v", perrs) + } + _, cerrs := check.Unit([]check.SourceFile{{ + Path: "Probe.schema", Name: "Probe.schema", Base: "Probe", Bytes: []byte(source), AST: f, + }}) + if len(cerrs) == 0 { + t.Fatal("const WeaponCount compiled beside enum Weapon — the generated Count would be silently overwritten") + } + for _, e := range cerrs { + text := e.Error() + if strings.Contains(text, "generated Count constant") && strings.Contains(text, "Weapon") { + return + } + } + t.Fatalf("no diagnostic names enum Weapon's generated Count constant; got: %v", cerrs) +} + // [..N] is pure sugar for [0..N] (SPEC §4.3): same IR, same wire, same // protocol id — the respelling of the retired [..N] must be spelling only. func TestUpToBoundIsSugar(t *testing.T) { diff --git a/internal/codegen/c/c.go b/internal/codegen/c/c.go index fe0291009..1ce6dbc32 100644 --- a/internal/codegen/c/c.go +++ b/internal/codegen/c/c.go @@ -302,6 +302,7 @@ func (g *gen) emitEnum(d *ir.Enum) { for i, v := range d.Variants { g.pf("#define %s_%s %d\n", screaming(d.Name), screaming(v), i+1) } + g.pf("#define %s_COUNT %d\n", screaming(d.Name), len(d.Variants)) g.pf("#define %s_MAX %d\n", screaming(d.Name), d.Max) // the debug/log name, the counterpart of C++'s and Go's EnumName diff --git a/internal/codegen/cpp/cpp.go b/internal/codegen/cpp/cpp.go index 760a2686d..bda8091da 100644 --- a/internal/codegen/cpp/cpp.go +++ b/internal/codegen/cpp/cpp.go @@ -360,6 +360,7 @@ func (g *gen) emitEnum(d *ir.Enum) { for i, v := range d.Variants { g.pf(" %s = %d,\n", v, i+1) } + g.pf(" Count = %d, // the declared variant count (SPEC §4.2)\n", len(d.Variants)) g.pf(" Max = %d, // the exported extent (SPEC §4.2)\n", d.Max) g.pf("};\n\n") g.pf("// EnumName: debug/log name for any %s value, out-of-set included\n", d.Name) diff --git a/internal/codegen/csharp/csharp.go b/internal/codegen/csharp/csharp.go index 6230e29dd..26ab0e950 100644 --- a/internal/codegen/csharp/csharp.go +++ b/internal/codegen/csharp/csharp.go @@ -279,6 +279,7 @@ func (g *gen) emitEnum(d *ir.Enum) { for i, v := range d.Variants { g.tf(" %s = %d,\n", v, i+1) } + g.tf(" Count = %d, // the declared variant count (SPEC §4.2)\n", len(d.Variants)) g.tf(" Max = %d, // the exported extent (SPEC §4.2)\n", d.Max) g.tf("}\n\n") // the ulong parameter (not the enum type) keeps out-of-set values exact: diff --git a/internal/codegen/dart/dart.go b/internal/codegen/dart/dart.go index 7b9dd0069..adaa944f2 100644 --- a/internal/codegen/dart/dart.go +++ b/internal/codegen/dart/dart.go @@ -541,6 +541,7 @@ func (g *gen) emitEnum(d *ir.Enum) { for i, v := range d.Variants { g.bpf(" static const int %s = %d;\n", dartName(v), i+1) } + g.bpf(" static const int count = %d; // the declared variant count (SPEC §4.2)\n", len(d.Variants)) g.bpf(" static const int max = %d; // the exported extent (SPEC §4.2)\n", d.Max) g.bpf("}\n\n") diff --git a/internal/codegen/elixir/elixir.go b/internal/codegen/elixir/elixir.go index 6d8e7ad27..ff25ff15c 100644 --- a/internal/codegen/elixir/elixir.go +++ b/internal/codegen/elixir/elixir.go @@ -392,6 +392,8 @@ func (g *gen) emitEnumModule(d *ir.Enum) { for i, v := range d.Variants { g.bpf(" def %s, do: %d\n", elixirName(v), i+1) } + g.bpf(" # the declared variant count (SPEC §4.2)\n") + g.bpf(" def count, do: %s\n", intLit64(int64(len(d.Variants)))) g.bpf(" # the exported extent (SPEC §4.2)\n") g.bpf(" def max, do: %s\n", intLit64(d.Max)) g.bpf("end\n\n") diff --git a/internal/codegen/golang/golang.go b/internal/codegen/golang/golang.go index fcf154066..fab3e8e2b 100644 --- a/internal/codegen/golang/golang.go +++ b/internal/codegen/golang/golang.go @@ -214,6 +214,7 @@ func (g *gen) emitEnum(d *ir.Enum) { for i, v := range d.Variants { g.pf("\t%s%s %s = %d\n", d.Name, v, d.Name, i+1) } + g.pf("\t%sCount %s = %d // the declared variant count (SPEC §4.2)\n", d.Name, d.Name, len(d.Variants)) g.pf("\t%sMax %s = %d // the exported extent (SPEC §4.2)\n", d.Name, d.Name, d.Max) g.pf(")\n\n") // the uint64 parameter (not the enum type) keeps out-of-set values exact: diff --git a/internal/codegen/golang/golang_test.go b/internal/codegen/golang/golang_test.go index b448accec..fe02b8d64 100644 --- a/internal/codegen/golang/golang_test.go +++ b/internal/codegen/golang/golang_test.go @@ -9,6 +9,9 @@ import ( cgen "github.com/mas-bandwidth/schema/v2/internal/codegen/c" "github.com/mas-bandwidth/schema/v2/internal/codegen/cpp" "github.com/mas-bandwidth/schema/v2/internal/codegen/csharp" + "github.com/mas-bandwidth/schema/v2/internal/codegen/dart" + "github.com/mas-bandwidth/schema/v2/internal/codegen/elixir" + "github.com/mas-bandwidth/schema/v2/internal/codegen/java" "github.com/mas-bandwidth/schema/v2/internal/codegen/js" "github.com/mas-bandwidth/schema/v2/internal/codegen/rust" "github.com/mas-bandwidth/schema/v2/internal/parser" @@ -23,6 +26,21 @@ func countAcross(files map[string][]byte, needle string) int { return n } +// collapseColumns squeezes each line's whitespace runs to one space, so a +// needle can name a whole emitted line — symbol, value and trailing comment +// — without pinning the column go/format aligned it into. +func collapseColumns(files map[string][]byte) map[string][]byte { + out := make(map[string][]byte, len(files)) + for name, src := range files { + lines := strings.Split(string(src), "\n") + for i, line := range lines { + lines[i] = strings.Join(strings.Fields(line), " ") + } + out[name] = []byte(strings.Join(lines, "\n")) + } + return out +} + // A bare float const infers float64 (SPEC §4.2, Go's literal rule): the Go // target must export it exactly as the explicit annotation would — a TYPED // float64 constant, the same surface every other target already emits @@ -136,6 +154,109 @@ func TestEnumExtentEmitted(t *testing.T) { } } +// Every generated enum carries its DECLARED variant count as the member +// Count beside the extent Max (SPEC §4.2), in each target's own idiom and in +// all nine. Without headroom the two numbers coincide; under | max = K they +// part, and that is the case a loop written against Max alone gets wrong — +// so both enums are pinned here, and Count < Max is asserted on the widened +// one. +func TestEnumDeclaredCountEmitted(t *testing.T) { + src := "package t\n\n" + + "enum Weapon | max = 15\n{ Laser, Missile }\n\n" + + "enum Team { Red, Blue, Green }\n\n" + + "type Box {\n w Weapon\n t Team\n}\n" + f, perrs := parser.Parse("Counts.schema", []byte(src)) + if len(perrs) > 0 { + t.Fatalf("parse: %v", perrs[0]) + } + u, cerrs := check.Unit([]check.SourceFile{{ + Path: "Counts.schema", Name: "Counts.schema", Base: "Counts", + Bytes: []byte(src), AST: f, + }}) + if len(cerrs) > 0 { + t.Fatalf("check: %v", cerrs[0]) + } + if got, max := len(u.Enums["Weapon"].Variants), u.Enums["Weapon"].Max; int64(got) >= max { + t.Fatalf("Weapon: Count = %d, Max = %d — the headroom case must have Count < Max", got, max) + } + + type expectation struct { + needle string + count int + } + type target struct { + name string + files map[string][]byte + genErr error + expects []expectation + } + var targets []target + addTarget := func(name string, files map[string][]byte, err error, expects ...expectation) { + targets = append(targets, target{name, files, err, expects}) + } + + goFiles, goErr := Generate(u) + // go/format aligns a const block into columns, so the Go needles are + // matched against a space-collapsed copy: symbol, value and comment + // together, without a column position baked into the test + addTarget("Go", collapseColumns(goFiles), goErr, + expectation{"WeaponCount Weapon = 2 // the declared variant count (SPEC §4.2)", 1}, + expectation{"TeamCount Team = 3 // the declared variant count (SPEC §4.2)", 1}, + expectation{"WeaponMax Weapon = 15 // the exported extent (SPEC §4.2)", 1}) + rustFiles, rustErr := rust.Generate(u) + addTarget("Rust", rustFiles, rustErr, + expectation{"pub const COUNT: Weapon = Weapon(2);", 1}, + expectation{"pub const COUNT: Team = Team(3);", 1}, + expectation{"pub const MAX: Weapon = Weapon(15);", 1}) + csFiles, csErr := csharp.Generate(u) + addTarget("C#", csFiles, csErr, + expectation{"Count = 2,", 1}, + expectation{"Count = 3,", 1}, + expectation{"Max = 15,", 1}) + jsFiles, jsErr := js.Generate(u) + addTarget("JS", jsFiles, jsErr, + expectation{"Count: 2,", 1}, + expectation{"Count: 3,", 1}, + expectation{"Max: 15,", 1}) + cFiles, cErr := cgen.Generate(u) + addTarget("C", cFiles, cErr, + expectation{"#define WEAPON_COUNT 2", 1}, + expectation{"#define TEAM_COUNT 3", 1}, + expectation{"#define WEAPON_MAX 15", 1}) + cppFiles, cppErr := cpp.Generate(u) + addTarget("C++", cppFiles, cppErr, + expectation{"Count = 2,", 1}, + expectation{"Count = 3,", 1}, + expectation{"Max = 15,", 1}) + dartFiles, dartErr := dart.Generate(u) + addTarget("Dart", dartFiles, dartErr, + expectation{"static const int count = 2;", 1}, + expectation{"static const int count = 3;", 1}, + expectation{"static const int max = 15;", 1}) + javaFiles, javaErr := java.Generate(u) + addTarget("Java", javaFiles, javaErr, + expectation{"public static final byte count = 2;", 1}, + expectation{"public static final byte count = 3;", 1}, + expectation{"public static final byte max = 15;", 1}) + elixirFiles, elixirErr := elixir.Generate(u) + addTarget("Elixir", elixirFiles, elixirErr, + expectation{"def count, do: 2", 1}, + expectation{"def count, do: 3", 1}, + expectation{"def max, do: 15", 1}) + + for _, tgt := range targets { + if tgt.genErr != nil { + t.Errorf("%s: generate: %v", tgt.name, tgt.genErr) + continue + } + for _, e := range tgt.expects { + if got := countAcross(tgt.files, e.needle); got != e.count { + t.Errorf("%s: %q emitted %d times, want %d — every generated enum carries Count beside Max (SPEC §4.2)", tgt.name, e.needle, got, e.count) + } + } + } +} + // A union declaration emits its full surface in every target (SPEC §4.8): // the Type tag enum with None/variants/Max, the storage shape, the // wire pair, and the bounds. The needles pin each target's idiom — red-first diff --git a/internal/codegen/java/java.go b/internal/codegen/java/java.go index af0bb191b..bb10a3b45 100644 --- a/internal/codegen/java/java.go +++ b/internal/codegen/java/java.go @@ -438,6 +438,8 @@ func (g *gen) emitEnum(d *ir.Enum) { for i, v := range d.Variants { g.bpf(" public static final %s %s = %s;\n", typ, javaName(v), narrowLit(typ, big.NewInt(int64(i+1)))) } + g.bpf(" // the declared variant count (SPEC §4.2)\n") + g.bpf(" public static final %s count = %s;\n", typ, narrowLit(typ, big.NewInt(int64(len(d.Variants))))) g.bpf(" // the exported extent (SPEC §4.2)\n") g.bpf(" public static final %s max = %s;\n", typ, narrowLit(typ, big.NewInt(d.Max))) g.bpf(" }\n\n") diff --git a/internal/codegen/js/js.go b/internal/codegen/js/js.go index 44392d8b9..5b8bbeafe 100644 --- a/internal/codegen/js/js.go +++ b/internal/codegen/js/js.go @@ -302,6 +302,7 @@ func (g *gen) emitEnum(d *ir.Enum) { for i, v := range d.Variants { g.pf(" %s: %d,\n", v, i+1) } + g.pf(" Count: %d, // the declared variant count (SPEC §4.2)\n", len(d.Variants)) g.pf(" Max: %d, // the exported extent (SPEC §4.2)\n", d.Max) g.pf("});\n\n") g.pf("// EnumName%s: debug/log/tooling name for any %s wire value —\n", d.Name, d.Name) diff --git a/internal/codegen/rust/rust.go b/internal/codegen/rust/rust.go index 2c384a6c1..a090ee196 100644 --- a/internal/codegen/rust/rust.go +++ b/internal/codegen/rust/rust.go @@ -333,6 +333,7 @@ func (g *gen) emitEnum(d *ir.Enum) { for i, v := range d.Variants { g.pf(" pub const %s: %s = %s(%d);\n", ir.RustConstName(v), d.Name, d.Name, i+1) } + g.pf(" pub const COUNT: %s = %s(%d); // the declared variant count (SPEC §4.2)\n", d.Name, d.Name, len(d.Variants)) g.pf(" pub const MAX: %s = %s(%d); // the exported extent (SPEC §4.2)\n", d.Name, d.Name, d.Max) g.pf("}\n\n") diff --git a/internal/goldens/goldens_test.go b/internal/goldens/goldens_test.go index 3938b2aa1..e60a62fe9 100644 --- a/internal/goldens/goldens_test.go +++ b/internal/goldens/goldens_test.go @@ -187,6 +187,38 @@ func TestGoldenSourceElixir(t *testing.T) { pinDir(t, filepath.Join(goldenDir, "elixir"), files) } +// The enum `Count` export moves NEITHER WIRE. Count is generated-code +// surface: it enters no wire-shape projection and no cook projection, so the +// packet wire's protocol id and the table wire's build version must both +// stand exactly where they stood before it existed. The numbers are written +// here as literals rather than read from testdata/golden — a re-pin of those +// files is precisely the mistake this refuses, and a gate that re-pins with +// them would say nothing. What legitimately moves them is a change to a +// PROJECTION itself — a wire-shape edit, or a cook form-version bump — which +// moves the corpus goldens in the same commit; a literal here that has to move +// alone is the defect this names. +func TestExportedSurfaceMovesNeitherWire(t *testing.T) { + for _, unit := range []struct { + name string + dir string + protocolId uint64 + buildVersion uint64 + }{ + {"examples", corpusDir, 0x91a8e85156dfe2b1, 0x69d6a810cfa22717}, + {"examples128", corpus128Dir, 0x42050541a90eea8a, 0xedde8274fbab7f85}, + } { + t.Run(unit.name, func(t *testing.T) { + u := loadCorpusDir(t, unit.dir) + if u.ProtocolId != unit.protocolId { + t.Errorf("protocol id = 0x%016x, want 0x%016x — the packet wire moved under an unchanged corpus (SPEC §3.1); a generated-code export must never reach it", u.ProtocolId, unit.protocolId) + } + if got := ir.BuildVersion(u); got != unit.buildVersion { + t.Errorf("build version = 0x%016x, want 0x%016x — the table wire moved under an unchanged corpus (docs/SPEC-TABLES.md §20); a generated-code export must never reach it", got, unit.buildVersion) + } + }) + } +} + // TestGoldenLudicrousId pins the fixed-point + 128-bit unit's protocol id. func TestGoldenLudicrousId(t *testing.T) { u := loadCorpusDir(t, corpus128Dir) diff --git a/internal/parser/parser.go b/internal/parser/parser.go index 5be9c4f8b..091c7f713 100644 --- a/internal/parser/parser.go +++ b/internal/parser/parser.go @@ -802,12 +802,12 @@ func (p *parser) parsePrimary() ast.Expr { return &ast.StringLit{Pos: t.Pos, Value: strings.Trim(t.Text, `"`)} case scanner.Ident: p.advance() - // E.Max / F.Count — contextual after '.' (SPEC §4.2) + // E.Max / E.Count — contextual after '.' (SPEC §4.2) if p.kind() == scanner.Dot { dot := p.advance() m := p.expect(scanner.Ident, `"Max" or "Count"`) if m.Text != "Max" && m.Text != "Count" { - p.errf(dot.Pos, "only .Max (enums and generated sets) and .Count (flags) are legal after a name (found .%s)", m.Text) + p.errf(dot.Pos, "only .Max (enums and generated sets) and .Count (enums and flags) are legal after a name (found .%s)", m.Text) } return &ast.MaxExpr{Pos: t.Pos, Enum: t.Text, Sel: m.Text} } diff --git a/ir/expr.go b/ir/expr.go index 4885e5d3f..2da82a1a6 100644 --- a/ir/expr.go +++ b/ir/expr.go @@ -105,10 +105,10 @@ func ExprConsts(e Expr) []string { return names } -// ExprHasEnumMax reports whether e contains an enum max reference. E.Max has -// no twin in any generated target, so a backend folds any expression -// containing one to the resolved value and keeps the schema form in a -// comment ([RenderExpr]). +// ExprHasEnumMax reports whether e contains a set reference — `E.Max` or +// `E.Count` (SPEC §4.2). Neither has a twin in any generated target, so a +// backend folds any expression containing one to the resolved value and +// keeps the schema form in a comment ([RenderExpr]). func ExprHasEnumMax(e Expr) bool { switch e := e.(type) { case *ast.MaxExpr: diff --git a/testdata/golden/c/Enums.h b/testdata/golden/c/Enums.h index 6f3442d90..195e8f6b1 100644 --- a/testdata/golden/c/Enums.h +++ b/testdata/golden/c/Enums.h @@ -30,6 +30,7 @@ typedef uint8_t Team; #define TEAM_NONE 0 #define TEAM_RED 1 #define TEAM_BLUE 2 +#define TEAM_COUNT 2 #define TEAM_MAX 2 /* Debug/log name for any Team value, out-of-set included. */ @@ -56,6 +57,7 @@ typedef uint8_t ShipType; #define SHIP_TYPE_BOMBER 3 #define SHIP_TYPE_DESTROYER 4 #define SHIP_TYPE_CARRIER 5 +#define SHIP_TYPE_COUNT 5 #define SHIP_TYPE_MAX 5 /* Debug/log name for any ShipType value, out-of-set included. */ @@ -83,6 +85,7 @@ typedef uint8_t MissileType; #define MISSILE_TYPE_HEATSEEKER 1 #define MISSILE_TYPE_TORPEDO 2 #define MISSILE_TYPE_NUKE 3 +#define MISSILE_TYPE_COUNT 3 #define MISSILE_TYPE_MAX 3 /* Debug/log name for any MissileType value, out-of-set included. */ @@ -111,6 +114,7 @@ typedef uint8_t PropType; #define PROP_TYPE_SPHERE 4 #define PROP_TYPE_BLACK_HOLE 5 #define PROP_TYPE_DYSON_PANEL 6 +#define PROP_TYPE_COUNT 6 #define PROP_TYPE_MAX 6 /* Debug/log name for any PropType value, out-of-set included. */ @@ -136,6 +140,7 @@ static SCHEMA_UNUSED const char * enum_name_prop_type( PropType value ) values wire-legal, which a C enum cannot hold honestly. */ typedef uint8_t Pending; #define PENDING_NONE 0 +#define PENDING_COUNT 0 #define PENDING_MAX 0 /* Debug/log name for any Pending value, out-of-set included. */ diff --git a/testdata/golden/c/Wire.h b/testdata/golden/c/Wire.h index 12e50b4ce..ba7481ce8 100644 --- a/testdata/golden/c/Wire.h +++ b/testdata/golden/c/Wire.h @@ -37,6 +37,7 @@ typedef uint8_t Weapon; #define WEAPON_LASER 1 #define WEAPON_MISSILE 2 #define WEAPON_RAILGUN 3 +#define WEAPON_COUNT 3 #define WEAPON_MAX 15 /* Debug/log name for any Weapon value, out-of-set included. */ diff --git a/testdata/golden/cpp/Enums.h b/testdata/golden/cpp/Enums.h index c5edf6869..7efbf3994 100644 --- a/testdata/golden/cpp/Enums.h +++ b/testdata/golden/cpp/Enums.h @@ -15,6 +15,7 @@ enum class Team : uint8_t { None = 0, Red = 1, Blue = 2, + Count = 2, // the declared variant count (SPEC §4.2) Max = 2, // the exported extent (SPEC §4.2) }; @@ -38,6 +39,7 @@ enum class ShipType : uint8_t { Bomber = 3, Destroyer = 4, Carrier = 5, + Count = 5, // the declared variant count (SPEC §4.2) Max = 5, // the exported extent (SPEC §4.2) }; @@ -62,6 +64,7 @@ enum class MissileType : uint8_t { Heatseeker = 1, Torpedo = 2, Nuke = 3, + Count = 3, // the declared variant count (SPEC §4.2) Max = 3, // the exported extent (SPEC §4.2) }; @@ -87,6 +90,7 @@ enum class PropType : uint8_t { Sphere = 4, BlackHole = 5, DysonPanel = 6, + Count = 6, // the declared variant count (SPEC §4.2) Max = 6, // the exported extent (SPEC §4.2) }; @@ -109,6 +113,7 @@ inline const char * EnumName( PropType value ) // enum Pending — None = 0 implicit, variants dense from 1, wire range [0, 0] (SPEC §4.2) enum class Pending : uint8_t { None = 0, + Count = 0, // the declared variant count (SPEC §4.2) Max = 0, // the exported extent (SPEC §4.2) }; diff --git a/testdata/golden/cpp/Wire.h b/testdata/golden/cpp/Wire.h index 3af7d3ddf..c45be4d67 100644 --- a/testdata/golden/cpp/Wire.h +++ b/testdata/golden/cpp/Wire.h @@ -22,6 +22,7 @@ enum class Weapon : uint8_t { Laser = 1, Missile = 2, Railgun = 3, + Count = 3, // the declared variant count (SPEC §4.2) Max = 15, // the exported extent (SPEC §4.2) }; diff --git a/testdata/golden/cs/Enums.cs b/testdata/golden/cs/Enums.cs index 5e1f8664f..299b655a4 100644 --- a/testdata/golden/cs/Enums.cs +++ b/testdata/golden/cs/Enums.cs @@ -15,6 +15,7 @@ public enum Team : byte None = 0, Red = 1, Blue = 2, + Count = 2, // the declared variant count (SPEC §4.2) Max = 2, // the exported extent (SPEC §4.2) } @@ -29,6 +30,7 @@ public enum ShipType : byte Bomber = 3, Destroyer = 4, Carrier = 5, + Count = 5, // the declared variant count (SPEC §4.2) Max = 5, // the exported extent (SPEC §4.2) } @@ -41,6 +43,7 @@ public enum MissileType : byte Heatseeker = 1, Torpedo = 2, Nuke = 3, + Count = 3, // the declared variant count (SPEC §4.2) Max = 3, // the exported extent (SPEC §4.2) } @@ -56,6 +59,7 @@ public enum PropType : byte Sphere = 4, BlackHole = 5, DysonPanel = 6, + Count = 6, // the declared variant count (SPEC §4.2) Max = 6, // the exported extent (SPEC §4.2) } @@ -65,6 +69,7 @@ public enum PropType : byte public enum Pending : byte { None = 0, + Count = 0, // the declared variant count (SPEC §4.2) Max = 0, // the exported extent (SPEC §4.2) } diff --git a/testdata/golden/cs/Wire.cs b/testdata/golden/cs/Wire.cs index 116d9e650..df7a4d101 100644 --- a/testdata/golden/cs/Wire.cs +++ b/testdata/golden/cs/Wire.cs @@ -20,6 +20,7 @@ public enum Weapon : byte Laser = 1, Missile = 2, Railgun = 3, + Count = 3, // the declared variant count (SPEC §4.2) Max = 15, // the exported extent (SPEC §4.2) } diff --git a/testdata/golden/dart/Enums.dart b/testdata/golden/dart/Enums.dart index 50de5ef18..9fa13de93 100644 --- a/testdata/golden/dart/Enums.dart +++ b/testdata/golden/dart/Enums.dart @@ -19,6 +19,7 @@ abstract final class Team { static const int none = 0; static const int red = 1; static const int blue = 2; + static const int count = 2; // the declared variant count (SPEC §4.2) static const int max = 2; // the exported extent (SPEC §4.2) } @@ -48,6 +49,7 @@ abstract final class ShipType { static const int bomber = 3; static const int destroyer = 4; static const int carrier = 5; + static const int count = 5; // the declared variant count (SPEC §4.2) static const int max = 5; // the exported extent (SPEC §4.2) } @@ -81,6 +83,7 @@ abstract final class MissileType { static const int heatseeker = 1; static const int torpedo = 2; static const int nuke = 3; + static const int count = 3; // the declared variant count (SPEC §4.2) static const int max = 3; // the exported extent (SPEC §4.2) } @@ -113,6 +116,7 @@ abstract final class PropType { static const int sphere = 4; static const int blackHole = 5; static const int dysonPanel = 6; + static const int count = 6; // the declared variant count (SPEC §4.2) static const int max = 6; // the exported extent (SPEC §4.2) } @@ -145,6 +149,7 @@ String enumNamePropType(int value) { // headroom values have no Dart enum member to be abstract final class Pending { static const int none = 0; + static const int count = 0; // the declared variant count (SPEC §4.2) static const int max = 0; // the exported extent (SPEC §4.2) } diff --git a/testdata/golden/dart/Wire.dart b/testdata/golden/dart/Wire.dart index 44137c792..cd2917b9e 100644 --- a/testdata/golden/dart/Wire.dart +++ b/testdata/golden/dart/Wire.dart @@ -95,6 +95,7 @@ abstract final class Weapon { static const int laser = 1; static const int missile = 2; static const int railgun = 3; + static const int count = 3; // the declared variant count (SPEC §4.2) static const int max = 15; // the exported extent (SPEC §4.2) } diff --git a/testdata/golden/elixir/Enums.ex b/testdata/golden/elixir/Enums.ex index 1532f3f30..fbba6b378 100644 --- a/testdata/golden/elixir/Enums.ex +++ b/testdata/golden/elixir/Enums.ex @@ -12,6 +12,8 @@ defmodule Example.Team do def none, do: 0 def red, do: 1 def blue, do: 2 + # the declared variant count (SPEC §4.2) + def count, do: 2 # the exported extent (SPEC §4.2) def max, do: 2 end @@ -27,6 +29,8 @@ defmodule Example.ShipType do def bomber, do: 3 def destroyer, do: 4 def carrier, do: 5 + # the declared variant count (SPEC §4.2) + def count, do: 5 # the exported extent (SPEC §4.2) def max, do: 5 end @@ -40,6 +44,8 @@ defmodule Example.MissileType do def heatseeker, do: 1 def torpedo, do: 2 def nuke, do: 3 + # the declared variant count (SPEC §4.2) + def count, do: 3 # the exported extent (SPEC §4.2) def max, do: 3 end @@ -56,6 +62,8 @@ defmodule Example.PropType do def sphere, do: 4 def black_hole, do: 5 def dyson_panel, do: 6 + # the declared variant count (SPEC §4.2) + def count, do: 6 # the exported extent (SPEC §4.2) def max, do: 6 end @@ -66,6 +74,8 @@ end # | max = ... headroom values have no richer Elixir value to be defmodule Example.Pending do def none, do: 0 + # the declared variant count (SPEC §4.2) + def count, do: 0 # the exported extent (SPEC §4.2) def max, do: 0 end diff --git a/testdata/golden/elixir/Wire.ex b/testdata/golden/elixir/Wire.ex index 16ab11553..3393b8781 100644 --- a/testdata/golden/elixir/Wire.ex +++ b/testdata/golden/elixir/Wire.ex @@ -13,6 +13,8 @@ defmodule Example.Weapon do def laser, do: 1 def missile, do: 2 def railgun, do: 3 + # the declared variant count (SPEC §4.2) + def count, do: 3 # the exported extent (SPEC §4.2) def max, do: 15 end diff --git a/testdata/golden/go/Enums.go b/testdata/golden/go/Enums.go index dd4c07e76..78dc79031 100644 --- a/testdata/golden/go/Enums.go +++ b/testdata/golden/go/Enums.go @@ -14,10 +14,11 @@ import ( type Team uint8 const ( - TeamNone Team = 0 - TeamRed Team = 1 - TeamBlue Team = 2 - TeamMax Team = 2 // the exported extent (SPEC §4.2) + TeamNone Team = 0 + TeamRed Team = 1 + TeamBlue Team = 2 + TeamCount Team = 2 // the declared variant count (SPEC §4.2) + TeamMax Team = 2 // the exported extent (SPEC §4.2) ) // EnumNameTeam: debug/log/tooling name for any Team wire value — @@ -44,6 +45,7 @@ const ( ShipTypeBomber ShipType = 3 ShipTypeDestroyer ShipType = 4 ShipTypeCarrier ShipType = 5 + ShipTypeCount ShipType = 5 // the declared variant count (SPEC §4.2) ShipTypeMax ShipType = 5 // the exported extent (SPEC §4.2) ) @@ -75,6 +77,7 @@ const ( MissileTypeHeatseeker MissileType = 1 MissileTypeTorpedo MissileType = 2 MissileTypeNuke MissileType = 3 + MissileTypeCount MissileType = 3 // the declared variant count (SPEC §4.2) MissileTypeMax MissileType = 3 // the exported extent (SPEC §4.2) ) @@ -105,6 +108,7 @@ const ( PropTypeSphere PropType = 4 PropTypeBlackHole PropType = 5 PropTypeDysonPanel PropType = 6 + PropTypeCount PropType = 6 // the declared variant count (SPEC §4.2) PropTypeMax PropType = 6 // the exported extent (SPEC §4.2) ) @@ -134,8 +138,9 @@ func EnumNamePropType(value uint64) string { type Pending uint8 const ( - PendingNone Pending = 0 - PendingMax Pending = 0 // the exported extent (SPEC §4.2) + PendingNone Pending = 0 + PendingCount Pending = 0 // the declared variant count (SPEC §4.2) + PendingMax Pending = 0 // the exported extent (SPEC §4.2) ) // EnumNamePending: debug/log/tooling name for any Pending wire value — diff --git a/testdata/golden/go/Wire.go b/testdata/golden/go/Wire.go index f081af11e..4d99c775f 100644 --- a/testdata/golden/go/Wire.go +++ b/testdata/golden/go/Wire.go @@ -29,6 +29,7 @@ const ( WeaponLaser Weapon = 1 WeaponMissile Weapon = 2 WeaponRailgun Weapon = 3 + WeaponCount Weapon = 3 // the declared variant count (SPEC §4.2) WeaponMax Weapon = 15 // the exported extent (SPEC §4.2) ) diff --git a/testdata/golden/java/Enums.java b/testdata/golden/java/Enums.java index ae28335b7..c2d99d07d 100644 --- a/testdata/golden/java/Enums.java +++ b/testdata/golden/java/Enums.java @@ -22,6 +22,8 @@ private Team() {} public static final byte none = 0; public static final byte red = 1; public static final byte blue = 2; + // the declared variant count (SPEC §4.2) + public static final byte count = 2; // the exported extent (SPEC §4.2) public static final byte max = 2; } @@ -54,6 +56,8 @@ private ShipType() {} public static final byte bomber = 3; public static final byte destroyer = 4; public static final byte carrier = 5; + // the declared variant count (SPEC §4.2) + public static final byte count = 5; // the exported extent (SPEC §4.2) public static final byte max = 5; } @@ -93,6 +97,8 @@ private MissileType() {} public static final byte heatseeker = 1; public static final byte torpedo = 2; public static final byte nuke = 3; + // the declared variant count (SPEC §4.2) + public static final byte count = 3; // the exported extent (SPEC §4.2) public static final byte max = 3; } @@ -129,6 +135,8 @@ private PropType() {} public static final byte sphere = 4; public static final byte blackHole = 5; public static final byte dysonPanel = 6; + // the declared variant count (SPEC §4.2) + public static final byte count = 6; // the exported extent (SPEC §4.2) public static final byte max = 6; } @@ -168,6 +176,8 @@ public static final class Pending { private Pending() {} public static final byte none = 0; + // the declared variant count (SPEC §4.2) + public static final byte count = 0; // the exported extent (SPEC §4.2) public static final byte max = 0; } diff --git a/testdata/golden/java/Wire.java b/testdata/golden/java/Wire.java index 61550a14b..79d7b7a94 100644 --- a/testdata/golden/java/Wire.java +++ b/testdata/golden/java/Wire.java @@ -37,6 +37,8 @@ private Weapon() {} public static final byte laser = 1; public static final byte missile = 2; public static final byte railgun = 3; + // the declared variant count (SPEC §4.2) + public static final byte count = 3; // the exported extent (SPEC §4.2) public static final byte max = 15; } diff --git a/testdata/golden/js/Enums.js b/testdata/golden/js/Enums.js index 57e6027e9..8537cf651 100644 --- a/testdata/golden/js/Enums.js +++ b/testdata/golden/js/Enums.js @@ -11,6 +11,7 @@ export const Team = Object.freeze({ None: 0, Red: 1, Blue: 2, + Count: 2, // the declared variant count (SPEC §4.2) Max: 2, // the exported extent (SPEC §4.2) }); @@ -39,6 +40,7 @@ export const ShipType = Object.freeze({ Bomber: 3, Destroyer: 4, Carrier: 5, + Count: 5, // the declared variant count (SPEC §4.2) Max: 5, // the exported extent (SPEC §4.2) }); @@ -71,6 +73,7 @@ export const MissileType = Object.freeze({ Heatseeker: 1, Torpedo: 2, Nuke: 3, + Count: 3, // the declared variant count (SPEC §4.2) Max: 3, // the exported extent (SPEC §4.2) }); @@ -102,6 +105,7 @@ export const PropType = Object.freeze({ Sphere: 4, BlackHole: 5, DysonPanel: 6, + Count: 6, // the declared variant count (SPEC §4.2) Max: 6, // the exported extent (SPEC §4.2) }); @@ -133,6 +137,7 @@ export function EnumNamePropType(value) { // integer-backed enums; | max = ... headroom values are plain Numbers export const Pending = Object.freeze({ None: 0, + Count: 0, // the declared variant count (SPEC §4.2) Max: 0, // the exported extent (SPEC §4.2) }); diff --git a/testdata/golden/js/Wire.js b/testdata/golden/js/Wire.js index d2bdb0e08..6501b09f8 100644 --- a/testdata/golden/js/Wire.js +++ b/testdata/golden/js/Wire.js @@ -28,6 +28,7 @@ export const Weapon = Object.freeze({ Laser: 1, Missile: 2, Railgun: 3, + Count: 3, // the declared variant count (SPEC §4.2) Max: 15, // the exported extent (SPEC §4.2) }); diff --git a/testdata/golden/ludicrous/c/Ludicrous.h b/testdata/golden/ludicrous/c/Ludicrous.h index 4ad9d97de..6b52ce62e 100644 --- a/testdata/golden/ludicrous/c/Ludicrous.h +++ b/testdata/golden/ludicrous/c/Ludicrous.h @@ -38,6 +38,7 @@ typedef uint8_t DriveMode; #define DRIVE_MODE_CRUISE 1 #define DRIVE_MODE_WARP 2 #define DRIVE_MODE_LUDICROUS 3 +#define DRIVE_MODE_COUNT 3 #define DRIVE_MODE_MAX 3 /* Debug/log name for any DriveMode value, out-of-set included. */ diff --git a/testdata/golden/ludicrous/cpp/Ludicrous.h b/testdata/golden/ludicrous/cpp/Ludicrous.h index 40d94ed07..df1f42bb9 100644 --- a/testdata/golden/ludicrous/cpp/Ludicrous.h +++ b/testdata/golden/ludicrous/cpp/Ludicrous.h @@ -23,6 +23,7 @@ enum class DriveMode : uint8_t { Cruise = 1, Warp = 2, Ludicrous = 3, + Count = 3, // the declared variant count (SPEC §4.2) Max = 3, // the exported extent (SPEC §4.2) }; diff --git a/testdata/golden/ludicrous/cs/Ludicrous.cs b/testdata/golden/ludicrous/cs/Ludicrous.cs index 209b724a8..0b964fd80 100644 --- a/testdata/golden/ludicrous/cs/Ludicrous.cs +++ b/testdata/golden/ludicrous/cs/Ludicrous.cs @@ -25,6 +25,7 @@ public enum DriveMode : byte Cruise = 1, Warp = 2, Ludicrous = 3, + Count = 3, // the declared variant count (SPEC §4.2) Max = 3, // the exported extent (SPEC §4.2) } diff --git a/testdata/golden/ludicrous/dart/Ludicrous.dart b/testdata/golden/ludicrous/dart/Ludicrous.dart index 13873a5c3..448c0490f 100644 --- a/testdata/golden/ludicrous/dart/Ludicrous.dart +++ b/testdata/golden/ludicrous/dart/Ludicrous.dart @@ -47,6 +47,7 @@ abstract final class DriveMode { static const int cruise = 1; static const int warp = 2; static const int ludicrous = 3; + static const int count = 3; // the declared variant count (SPEC §4.2) static const int max = 3; // the exported extent (SPEC §4.2) } diff --git a/testdata/golden/ludicrous/elixir/Ludicrous.ex b/testdata/golden/ludicrous/elixir/Ludicrous.ex index 0cee0e7c7..54d8f9fd8 100644 --- a/testdata/golden/ludicrous/elixir/Ludicrous.ex +++ b/testdata/golden/ludicrous/elixir/Ludicrous.ex @@ -38,6 +38,8 @@ defmodule Ludicrous.DriveMode do def cruise, do: 1 def warp, do: 2 def ludicrous, do: 3 + # the declared variant count (SPEC §4.2) + def count, do: 3 # the exported extent (SPEC §4.2) def max, do: 3 end diff --git a/testdata/golden/ludicrous/go/Ludicrous.go b/testdata/golden/ludicrous/go/Ludicrous.go index 892046a78..e1a5259b6 100644 --- a/testdata/golden/ludicrous/go/Ludicrous.go +++ b/testdata/golden/ludicrous/go/Ludicrous.go @@ -30,6 +30,7 @@ const ( DriveModeCruise DriveMode = 1 DriveModeWarp DriveMode = 2 DriveModeLudicrous DriveMode = 3 + DriveModeCount DriveMode = 3 // the declared variant count (SPEC §4.2) DriveModeMax DriveMode = 3 // the exported extent (SPEC §4.2) ) diff --git a/testdata/golden/ludicrous/java/Ludicrous.java b/testdata/golden/ludicrous/java/Ludicrous.java index 2947d5a28..897cb4a39 100644 --- a/testdata/golden/ludicrous/java/Ludicrous.java +++ b/testdata/golden/ludicrous/java/Ludicrous.java @@ -54,6 +54,8 @@ private DriveMode() {} public static final byte cruise = 1; public static final byte warp = 2; public static final byte ludicrous = 3; + // the declared variant count (SPEC §4.2) + public static final byte count = 3; // the exported extent (SPEC §4.2) public static final byte max = 3; } diff --git a/testdata/golden/ludicrous/js/Ludicrous.js b/testdata/golden/ludicrous/js/Ludicrous.js index e2fe24022..7f8957b0f 100644 --- a/testdata/golden/ludicrous/js/Ludicrous.js +++ b/testdata/golden/ludicrous/js/Ludicrous.js @@ -34,6 +34,7 @@ export const DriveMode = Object.freeze({ Cruise: 1, Warp: 2, Ludicrous: 3, + Count: 3, // the declared variant count (SPEC §4.2) Max: 3, // the exported extent (SPEC §4.2) }); diff --git a/testdata/golden/ludicrous/rust/ludicrous.rs b/testdata/golden/ludicrous/rust/ludicrous.rs index 8e17c3463..39c8b778e 100644 --- a/testdata/golden/ludicrous/rust/ludicrous.rs +++ b/testdata/golden/ludicrous/rust/ludicrous.rs @@ -47,6 +47,7 @@ impl DriveMode { pub const CRUISE: DriveMode = DriveMode(1); pub const WARP: DriveMode = DriveMode(2); pub const LUDICROUS: DriveMode = DriveMode(3); + pub const COUNT: DriveMode = DriveMode(3); // the declared variant count (SPEC §4.2) pub const MAX: DriveMode = DriveMode(3); // the exported extent (SPEC §4.2) } diff --git a/testdata/golden/rust/enums.rs b/testdata/golden/rust/enums.rs index 685c1b0bf..b75ab5673 100644 --- a/testdata/golden/rust/enums.rs +++ b/testdata/golden/rust/enums.rs @@ -14,6 +14,7 @@ impl Team { pub const NONE: Team = Team(0); pub const RED: Team = Team(1); pub const BLUE: Team = Team(2); + pub const COUNT: Team = Team(2); // the declared variant count (SPEC §4.2) pub const MAX: Team = Team(2); // the exported extent (SPEC §4.2) } @@ -40,6 +41,7 @@ impl ShipType { pub const BOMBER: ShipType = ShipType(3); pub const DESTROYER: ShipType = ShipType(4); pub const CARRIER: ShipType = ShipType(5); + pub const COUNT: ShipType = ShipType(5); // the declared variant count (SPEC §4.2) pub const MAX: ShipType = ShipType(5); // the exported extent (SPEC §4.2) } @@ -67,6 +69,7 @@ impl MissileType { pub const HEATSEEKER: MissileType = MissileType(1); pub const TORPEDO: MissileType = MissileType(2); pub const NUKE: MissileType = MissileType(3); + pub const COUNT: MissileType = MissileType(3); // the declared variant count (SPEC §4.2) pub const MAX: MissileType = MissileType(3); // the exported extent (SPEC §4.2) } @@ -95,6 +98,7 @@ impl PropType { pub const SPHERE: PropType = PropType(4); pub const BLACK_HOLE: PropType = PropType(5); pub const DYSON_PANEL: PropType = PropType(6); + pub const COUNT: PropType = PropType(6); // the declared variant count (SPEC §4.2) pub const MAX: PropType = PropType(6); // the exported extent (SPEC §4.2) } @@ -120,6 +124,7 @@ pub struct Pending(pub u8); impl Pending { pub const NONE: Pending = Pending(0); + pub const COUNT: Pending = Pending(0); // the declared variant count (SPEC §4.2) pub const MAX: Pending = Pending(0); // the exported extent (SPEC §4.2) } diff --git a/testdata/golden/rust/wire.rs b/testdata/golden/rust/wire.rs index e3ecae369..e1c75686b 100644 --- a/testdata/golden/rust/wire.rs +++ b/testdata/golden/rust/wire.rs @@ -26,6 +26,7 @@ impl Weapon { pub const LASER: Weapon = Weapon(1); pub const MISSILE: Weapon = Weapon(2); pub const RAILGUN: Weapon = Weapon(3); + pub const COUNT: Weapon = Weapon(3); // the declared variant count (SPEC §4.2) pub const MAX: Weapon = Weapon(15); // the exported extent (SPEC §4.2) }