@@ -26,10 +26,21 @@ pub fn getMaxEnumSize(comptime T: type) usize {
2626}
2727
2828pub fn getEnumSize (comptime T : type , value : T ) usize {
29- const Type = assertEnumType (T );
30- const tag_type = @typeInfo (Type ).@"enum" .tag_type ;
31- const int_value = @intFromEnum (value );
32- return getIntSize (tag_type , int_value );
29+ switch (@typeInfo (T )) {
30+ .@"enum" = > {
31+ const tag_type = @typeInfo (T ).@"enum" .tag_type ;
32+ const int_value = @intFromEnum (value );
33+ return getIntSize (tag_type , int_value );
34+ },
35+ .optional = > | opt_info | {
36+ if (value ) | v | {
37+ return getEnumSize (opt_info .child , v );
38+ } else {
39+ return 1 ; // size of null
40+ }
41+ },
42+ else = > @compileError ("Expected enum or optional enum, got " ++ @typeName (T )),
43+ }
3344}
3445
3546pub fn packEnum (writer : anytype , comptime T : type , value_or_maybe_null : T ) ! void {
@@ -43,10 +54,53 @@ pub fn packEnum(writer: anytype, comptime T: type, value_or_maybe_null: T) !void
4354}
4455
4556pub fn unpackEnum (reader : anytype , comptime T : type ) ! T {
46- const Type = assertEnumType (T );
47- const tag_type = @typeInfo (Type ).@"enum" .tag_type ;
48- const int_value = try unpackInt (reader , tag_type );
49- return @enumFromInt (int_value );
57+ switch (@typeInfo (T )) {
58+ .@"enum" = > {
59+ const tag_type = @typeInfo (T ).@"enum" .tag_type ;
60+ const int_value = try unpackInt (reader , tag_type );
61+ return @enumFromInt (int_value );
62+ },
63+ .optional = > | opt_info | {
64+ const header = try reader .readByte ();
65+ if (header == hdrs .NIL ) {
66+ return null ;
67+ }
68+
69+ // Put the header back and unpack as non-optional enum
70+ // We need to create a buffered reader that includes the header
71+ const backup_reader = struct {
72+ header : u8 ,
73+ reader : @TypeOf (reader ),
74+ header_consumed : bool = false ,
75+
76+ const Self = @This ();
77+
78+ pub fn readByte (self : * Self ) ! u8 {
79+ if (! self .header_consumed ) {
80+ self .header_consumed = true ;
81+ return self .header ;
82+ }
83+ return try self .reader .readByte ();
84+ }
85+
86+ pub fn readBytesNoEof (self : * Self , buf : []u8 ) ! void {
87+ if (! self .header_consumed and buf .len > 0 ) {
88+ buf [0 ] = self .header ;
89+ self .header_consumed = true ;
90+ if (buf .len > 1 ) {
91+ try self .reader .readBytesNoEof (buf [1.. ]);
92+ }
93+ } else {
94+ try self .reader .readBytesNoEof (buf );
95+ }
96+ }
97+ };
98+
99+ var backup = backup_reader { .header = header , .reader = reader };
100+ return try unpackEnum (backup .reader (), opt_info .child );
101+ },
102+ else = > @compileError ("Expected enum or optional enum, got " ++ @typeName (T )),
103+ }
50104}
51105
52106test "getMaxEnumSize" {
@@ -127,4 +181,48 @@ test "enum edge cases" {
127181 const result = try unpackEnum (stream .reader (), MixedEnum );
128182 try std .testing .expectEqual (MixedEnum .second , result );
129183 try std .testing .expectEqual (11 , @intFromEnum (result ));
184+ }
185+
186+ test "optional enum" {
187+ const TestEnum = enum (u8 ) { foo = 1 , bar = 2 };
188+ const OptionalEnum = ? TestEnum ;
189+
190+ // Test non-null optional enum
191+ {
192+ var buffer = std .ArrayList (u8 ).init (std .testing .allocator );
193+ defer buffer .deinit ();
194+
195+ const value : OptionalEnum = .bar ;
196+ try packEnum (buffer .writer (), OptionalEnum , value );
197+
198+ var stream = std .io .fixedBufferStream (buffer .items );
199+ const result = try unpackEnum (stream .reader (), OptionalEnum );
200+ try std .testing .expectEqual (@as (OptionalEnum , .bar ), result );
201+ }
202+
203+ // Test null optional enum
204+ {
205+ var buffer = std .ArrayList (u8 ).init (std .testing .allocator );
206+ defer buffer .deinit ();
207+
208+ const value : OptionalEnum = null ;
209+ try packEnum (buffer .writer (), OptionalEnum , value );
210+
211+ var stream = std .io .fixedBufferStream (buffer .items );
212+ const result = try unpackEnum (stream .reader (), OptionalEnum );
213+ try std .testing .expectEqual (@as (OptionalEnum , null ), result );
214+ }
215+ }
216+
217+ test "getEnumSize with optional" {
218+ const TestEnum = enum (u8 ) { foo = 0 , bar = 150 };
219+ const OptionalEnum = ? TestEnum ;
220+
221+ // Test non-null optional enum size
222+ const value : OptionalEnum = .bar ;
223+ try std .testing .expectEqual (2 , getEnumSize (OptionalEnum , value )); // requires u8 format
224+
225+ // Test null optional enum size
226+ const null_value : OptionalEnum = null ;
227+ try std .testing .expectEqual (1 , getEnumSize (OptionalEnum , null_value )); // size of null
130228}
0 commit comments