Skip to content

Instantly share code, notes, and snippets.

@BruceChen7
Last active August 1, 2022 15:29
Show Gist options
  • Save BruceChen7/a61ca9dab2385de822c8bac26baaaa3d to your computer and use it in GitHub Desktop.
Save BruceChen7/a61ca9dab2385de822c8bac26baaaa3d to your computer and use it in GitHub Desktop.
#ziglang#type#zig#async
// 固定数组,类型体操
// [Zig lang 初体验 -- 『大道至简』的 comptime - 纯纯的 Blog](https://blog.zhuangty.com/zig-lang-comptime/)
const std = @import("std");
const ArrayList = std.ArrayList;
const DynamicBitSet = std.bit_set.DynamicBitSet;
fn FixedArray(comptime T: type) type {
return struct {
const Self = @This();
data: ArrayList(T),
validity: DynamicBitSet,
pub const Ref = T;
pub fn deinit(self: *Self) void {
self.data.deinit();
self.validity.deinit();
}
pub fn value(self: *const Self, idx: usize) ?Self.Ref {
if (self.validity.isSet(idx)) {
return self.data.items[idx];
} else {
return null;
}
}
pub fn len(self: *const Self) usize {
return self.data.len();
}
};
}
// 类型可以做逻辑
// ...
const sizeLarge = (@sizeOf(T) > 8);
pub const Ref = if (sizeLarge > 8) *T else T;
// ...
pub fn value(self: *const Self, idx: usize) ?Self.Ref {
if (self.validity.isSet(idx)) {
if (sizeLarge) {
return &self.data.items[idx];
} else {
return self.data.items[idx];
}
} else {
return null;
}
}
const BytesArrayBuilder = struct {
const Self = @This();
pub const Array = BytesArray;
data: ArrayList(u8),
offsets: ArrayList(u32),
validity: DynamicBitSet,
pub fn init(allocator: Allocator) !Self {
var offsets = try ArrayList(u32).initCapacity(allocator, 1);
offsets.appendAssumeCapacity(0);
return Self{
.data = ArrayList(u8).init(allocator),
.offsets = offsets,
.validity = try DynamicBitSet.initEmpty(allocator, 0),
};
}
fn append(self: *Self, v: Self.Array.Ref) !void {
try self.data.appendSlice(v);
try self.offsets.append(@intCast(u32, self.data.items.len));
try self.validity.resize(self.validity.capacity() + 1, true);
}
fn append_null(self: *Self) !void {
try self.offsets.append(@intCast(u32, self.data.items.len));
try self.validity.resize(self.validity.capacity() + 1, false);
}
pub fn finish(self: Self) BytesArray {
return BytesArray{
.data = self.data,
.offsets = self.offsets,
.validity = self.validity,
};
}
};
// 定义 DataType,假设我们支持五种类型。
const DataType = union(enum) {
SmallInt: void,
Integer: void,
BigInt: void,
Varchar: void,
Char: u16, // Char 的长度
// 关联逻辑类型和物理类型
fn ArrayType(self: DataType) type {
return switch (self) {
DataType.SmallInt => FixedArray(i16),
DataType.Integer => FixedArray(i32),
DataType.BigInt => FixedArray(i64),
DataType.Varchar => BytesArray,
DataType.Char => BytesArray,
};
}
};
@BruceChen7
Copy link
Author

BruceChen7 commented Jul 8, 2022

const ally = testing.allocator;
const Foo = struct {
    a: u32,
    b: []const u8,
    c: u8,
};
var list = MultiArrayList(Foo){};
defer list.deinit(ally);
try list.ensureTotalCapacity(ally, 2);
list.appendAssumeCapacity(.{
    .a = 1,
    .b = "foobar",
    .c = 'a',
});
list.appendAssumeCapacity(.{
    .a = 2,
    .b = "zigzag",
    .c = 'b',
});
try testing.expectEqualSlices(u32, list.items(.a), &[_]u32{ 1, 2 });
try testing.expectEqualSlices(u8, list.items(.c), &[_]u8{ 'a', 'b' });
try testing.expectEqual(@as(usize, 2), list.items(.b).len);
try testing.expectEqualStrings("foobar", list.items(.b)[0]);
try testing.expectEqualStrings("zigzag", list.items(.b)[1]);
try list.append(ally, .{
    .a = 3,
    .b = "fizzbuzz",
    .c = 'c',
});

使用体验都跟 ArrayList 几乎完全一模一样,但是内部确实按字段列存储的,它的内部实现大量使用了编译期反射生成友好的代码。这对 Data-oriented Programming 的场景是非常友好的。

@BruceChen7
Copy link
Author

BruceChen7 commented Jul 9, 2022

async in zig

// 阻塞模式
const net = @import("std").net;

pub fn main() !void {
    const addr = try net.Address.parseIp("127.0.0.1", 7000);
    try send_message(addr);
}

fn send_message(addr: net.Address) !void {
    var socket = try net.tcpConnectToAddress(addr);
    defer socket.close();

    _ = try socket.write("Hello World!\n");
}

const net = @import("std").net;

// 采用事件模型
pub const io_mode = .evented;

pub fn main() !void {
    const addr = try net.Address.parseIp("127.0.0.1", 7000);
    try send_message(addr);
}


// 非阻塞模式,没有着色问题
fn send_message(addr: net.Address) !void {
    var socket = try net.tcpConnectToAddress(addr);
    defer socket.close();

    _ = try socket.write("Hello World!\n");
}

着色问题

  • 由于你不能从非async代码中调用async函数,你最终会有很多重复的工作,你需要重新实现部分标准库和所有网络相关的库,以考虑到async/await。这方面的一个例子是Python,在Python 3中引入async/await后,诞生了aio-libs这样的项目,其目标是在AsyncIO之上重新实现流行的网络库。

@BruceChen7
Copy link
Author

pub const BoolParser = struct {
    // 是否支持
    pub fn isSupported(comptime T: type) bool {
        return switch (@typeInfo(T)) {
            .Bool, .Int, .Float => true,
            else => false,
        };
    }

    pub fn parse(comptime T: type, comptime _: type, msg: anytype) !T {
        const ch = try msg.readByte();
        try msg.skipBytes(2, .{});
        return switch (@typeInfo(T)) {
            else => unreachable,
            .Bool => ch == 't',
            .Int, .Float => if (ch == 't') @as(T, 1) else @as(T, 0),
        };
    }

    pub fn isSupportedAlloc(comptime T: type) bool {
        return isSupported(T);
    }

    pub fn parseAlloc(comptime T: type, comptime rootParser: type, allocator: std.mem.Allocator, msg: anytype) !T {
        _ = allocator;

        return parse(T, rootParser, msg);
    }
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment