Skip to content

Commit

Permalink
de: Add support for std.IntegerBitSet
Browse files Browse the repository at this point in the history
  • Loading branch information
Jason Phan committed Feb 4, 2023
1 parent 5d5ba25 commit 8ac2162
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/de/blocks.zig
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ pub const BufMap = @import("blocks/buf_map.zig");
/// Deserialization block for `std.HashMap` values.
pub const HashMap = _HashMap;

/// Deserialization block for `std.IntegerBitSet` values.
pub const IntegerBitSet = @import("blocks/integer_bit_set.zig");

/// Deserialization block for `std.HashMapUnmanaged` values.
pub const HashMapUnmanaged = _HashMap;

Expand Down
117 changes: 117 additions & 0 deletions src/de/blocks/integer_bit_set.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
const std = @import("std");

const IntegerBitSetVisitor = @import("../impls/visitor/integer_bit_set.zig").Visitor;
const testing = @import("../testing.zig");

const Self = @This();

/// Specifies all types that can be deserialized by this block.
pub fn is(
/// The type being deserialized into.
comptime T: type,
) bool {
return comptime std.mem.startsWith(u8, @typeName(T), "bit_set.IntegerBitSet");
}

/// Specifies the deserialization process for types relevant to this block.
pub fn deserialize(
/// An optional memory allocator.
allocator: ?std.mem.Allocator,
/// The type being deserialized into.
comptime T: type,
/// A `getty.Deserializer` interface value.
deserializer: anytype,
/// A `getty.de.Visitor` interface value.
visitor: anytype,
) !@TypeOf(visitor).Value {
_ = T;

return try deserializer.deserializeSeq(allocator, visitor);
}

/// Returns a type that implements `getty.de.Visitor`.
pub fn Visitor(
/// The type being deserialized into.
comptime T: type,
) type {
return IntegerBitSetVisitor(T);
}

test "deserialize - std.IntegerBitSet" {
const tests = .{
.{
.name = "zero-sized",
.tokens = &.{
.{ .Seq = .{ .len = 0 } },
.{ .SeqEnd = {} },
},
.want = std.StaticBitSet(0).initEmpty(),
},
.{
.name = "empty",
.tokens = &.{
.{ .Seq = .{ .len = 3 } },
.{ .I32 = 0 },
.{ .I32 = 0 },
.{ .I32 = 0 },
.{ .SeqEnd = {} },
},
.want = std.StaticBitSet(3).initEmpty(),
},
.{
.name = "full",
.tokens = &.{
.{ .Seq = .{ .len = 3 } },
.{ .I32 = 1 },
.{ .I32 = 1 },
.{ .I32 = 1 },
.{ .SeqEnd = {} },
},
.want = std.StaticBitSet(3).initFull(),
},
.{
.name = "mixed (I)",
.tokens = &.{
.{ .Seq = .{ .len = 5 } },
.{ .I32 = 1 },
.{ .I32 = 1 },
.{ .I32 = 0 },
.{ .I32 = 1 },
.{ .I32 = 0 },
.{ .SeqEnd = {} },
},
.want = blk: {
var want = std.StaticBitSet(5).initEmpty();
want.set(1);
want.set(3);
want.set(4);
break :blk want;
},
},
.{
.name = "mixed (I*)",
.tokens = &.{
.{ .Seq = .{ .len = 5 } },
.{ .I32 = 1 },
.{ .I32 = 0 },
.{ .I32 = 0 },
.{ .I32 = 1 },
.{ .I32 = 1 },
.{ .SeqEnd = {} },
},
.want = blk: {
var want = std.StaticBitSet(5).initEmpty();
want.set(0);
want.set(1);
want.set(4);
break :blk want;
},
},
};

inline for (tests) |t| {
const Want = @TypeOf(t.want);
const got = try testing.deserialize(null, t.name, Self, Want, t.tokens);
try testing.expectEqual(t.name, t.want, got);
}
}
70 changes: 70 additions & 0 deletions src/de/impls/visitor/integer_bit_set.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
const std = @import("std");

const free = @import("../../free.zig").free;
const Ignored = @import("../../impls/seed/ignored.zig").Ignored;
const VisitorInterface = @import("../../interfaces/visitor.zig").Visitor;

pub fn Visitor(comptime IntegerBitSet: type) type {
return struct {
const Self = @This();

pub usingnamespace VisitorInterface(
Self,
Value,
.{
.visitSeq = visitSeq,
},
);

const Value = IntegerBitSet;

fn visitSeq(_: Self, allocator: ?std.mem.Allocator, comptime Deserializer: type, seq: anytype) Deserializer.Error!Value {
var bitset = Value.initEmpty();

if (Value.bit_length == 0) {
if (try seq.nextElement(allocator, Value.MaskInt) != null) {
return error.InvalidLength;
}

return bitset;
}

// Deserialize bits from N to 1, where N is the bitset's bit
// length.
//
// NOTE: The 0th bit needs to be deserialized separately due to
// compile errors related to the shift bit being too large or
// something.
comptime var i: usize = Value.bit_length - 1;
inline while (i > 0) : (i -= 1) {
if (try seq.nextElement(allocator, Value.MaskInt)) |bit| {
switch (bit) {
0 => {},
1 => bitset.set(i),
else => return error.InvalidValue,
}
} else {
return error.InvalidValue;
}
}

// Deserialize 0th bit.
if (try seq.nextElement(allocator, Value.MaskInt)) |bit| {
switch (bit) {
0 => {},
1 => bitset.set(0),
else => return error.InvalidValue,
}
} else {
return error.InvalidValue;
}

// Check for end of sequence.
if (try seq.nextElement(allocator, Value.MaskInt) != null) {
return error.InvalidLength;
}

return bitset;
}
};
}
1 change: 1 addition & 0 deletions src/de/tuples.zig
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ pub const default = .{
// - std.StringArrayHashMapUnmanaged
blocks.HashMap,

blocks.IntegerBitSet,
blocks.MultiArrayList,
blocks.SinglyLinkedList,
blocks.NetAddress,
Expand Down

0 comments on commit 8ac2162

Please sign in to comment.