const c = @cImport({ @cInclude("zaprus.h"); }); fn zigToCMessage(msg: zaprus.Message) !c.SaprusMessage { return switch (msg) { .relay => |r| .{ .packet_type = @intFromEnum(msg), .payload_len = @intCast(r.payload.len), .headers = .{ .relay = .{ .dest = r.header.dest, } }, .payload = @constCast(r.payload.ptr), }, .connection => |con| .{ .packet_type = @intFromEnum(msg), .payload_len = @intCast(con.payload.len), .headers = .{ .connection = .{ .src_port = con.header.src_port, .dest_port = con.header.dest_port, .seq_num = con.header.seq_num, .msg_id = con.header.msg_id, ._reserved = con.header.reserved, .options = @bitCast(con.header.options), } }, .payload = @constCast(con.payload.ptr), }, .file_transfer => return zaprus.Error.NotImplementedSaprusType, else => return zaprus.Error.UnknownSaprusType, }; } fn cToZigMessage(msg: c.SaprusMessage) !zaprus.Message { const msg_type: zaprus.PacketType = @enumFromInt(msg.packet_type); return switch (msg_type) { .relay => .{ .relay = .{ .header = .{ .dest = msg.headers.relay.dest[0..4].*, }, .payload = msg.payload[0..msg.payload_len], }, }, .connection => .{ .connection = .{ .header = .{ .src_port = msg.headers.connection.src_port, .dest_port = msg.headers.connection.dest_port, .seq_num = msg.headers.connection.seq_num, .msg_id = msg.headers.connection.msg_id, .reserved = msg.headers.connection._reserved, .options = @bitCast(msg.headers.connection.options), }, .payload = msg.payload[0..msg.payload_len], }, }, .file_transfer => return zaprus.Error.NotImplementedSaprusType, else => return zaprus.Error.UnknownSaprusType, }; } // client export fn zaprus_init() c_int { SaprusClient.init() catch return 1; return 0; } export fn zaprus_deinit() c_int { SaprusClient.deinit(); return 0; } export fn zaprus_send_relay(payload: [*]const u8, len: usize, dest: [*]u8) c_int { SaprusClient.sendRelay(payload[0..len], dest[0..4].*, allocator) catch return 1; return 0; } export fn zaprus_send_initial_connection(payload: [*]const u8, len: usize, initial_port: u16) c_int { _ = SaprusClient.sendInitialConnection(payload[0..len], initial_port, allocator) catch return 1; return 0; } export fn zaprus_connect(payload: [*]const u8, len: usize) ?*c.SaprusMessage { if (SaprusClient.connect(payload[0..len], allocator)) |msg| { var m = zigToCMessage(msg) catch return null; return &m; } else |_| { return null; } } // message /// ptr should be freed by the caller. export fn zaprus_message_to_bytes(msg: c.SaprusMessage, ptr: *[*]u8, len: *usize) c_int { var m = cToZigMessage(msg) catch return 1; const bytes = m.toBytes(allocator) catch return 1; ptr.* = bytes.ptr; len.* = bytes.len; return 0; } /// Return value should be destroyed with zaprus_message_deinit. export fn zaprus_message_from_bytes(bytes: [*]const u8, len: usize) ?*c.SaprusMessage { if (zaprus.Message.fromBytes(bytes[0..len], allocator)) |msg| { var m = zigToCMessage(msg) catch return null; return &m; } else |_| return null; } export fn zaprus_message_deinit(msg: *c.SaprusMessage) void { if (cToZigMessage(msg.*)) |m| { m.deinit(allocator); } else |_| unreachable; } const std = @import("std"); const zaprus = @import("./root.zig"); const SaprusClient = zaprus.Client; const allocator = std.heap.c_allocator; test { std.testing.refAllDeclsRecursively(@This()); }