From ad43577b44c8fdb2e18b413e2137a23a942df613 Mon Sep 17 00:00:00 2001 From: Spencer Brower Date: Wed, 8 Jul 2026 12:37:26 -0400 Subject: [PATCH] feat(zmq): Simplified bindings. --- .gitignore | 1 + main.odin | 14 ++++---- zmq/zmq.odin | 83 +++++++++++++++++++++++++---------------------- zmq/zmq_test.odin | 13 ++++++++ 4 files changed, 66 insertions(+), 45 deletions(-) create mode 100644 zmq/zmq_test.odin diff --git a/.gitignore b/.gitignore index 4a8461c..d15e7ed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .direnv node_modules vendor +zmq_odin diff --git a/main.odin b/main.odin index c8d163e..9cdb6a6 100644 --- a/main.odin +++ b/main.odin @@ -31,7 +31,7 @@ main :: proc() { req, cerr := zmq.socket(ctx, .REQ) if cerr != nil { - log.panic(zmq.strerror(cerr)) + log.panicf("err: %v (%d) %s", cerr, cerr, zmq.strerror(cerr)) } defer zmq.close(req) if err := zmq.connect(req, "inproc://echo"); err != nil { @@ -41,7 +41,7 @@ main :: proc() { echo(req, rep) } -echo :: proc(req, rep: zmq.Socket) { +echo :: proc(client, server: zmq.Socket) { scanner: bufio.Scanner bufio.scanner_init(&scanner, os.to_reader(os.stdin)) defer bufio.scanner_destroy(&scanner) @@ -52,20 +52,20 @@ echo :: proc(req, rep: zmq.Socket) { if len(line) == 0 { continue } - if _, err := zmq.send(req, transmute([]u8)line); err != nil { + if _, err := zmq.send(client, line); err != nil { fmt.eprintfln("send: %s", zmq.strerror(err)) return } - n, rerr := zmq.recv(rep, buf[:]) + n, rerr := zmq.recv(server, buf[:]) if rerr != nil { fmt.eprintfln("rep recv: %s", zmq.strerror(rerr)) return } - if _, werr := zmq.send(rep, buf[:n]); werr != nil { - fmt.eprintfln("rep send: %s", zmq.strerror(werr)) + if _, werr := zmq.send(server, buf[:n]); werr != nil { + fmt.eprintfln("rep send: %v %s", werr, zmq.strerror(werr)) return } - m, qerr := zmq.recv(req, buf[:]) + m, qerr := zmq.recv(client, buf[:]) if qerr != nil { fmt.eprintfln("req recv: %s", zmq.strerror(qerr)) return diff --git a/zmq/zmq.odin b/zmq/zmq.odin index 67035d6..3a669be 100644 --- a/zmq/zmq.odin +++ b/zmq/zmq.odin @@ -6,35 +6,35 @@ import "core:strings" foreign import lib "system:zmq" -@(default_calling_convention = "c") +Context :: distinct rawptr +Socket :: distinct rawptr + +@(default_calling_convention = "c", link_prefix = "zmq_") foreign lib { - @(link_name = "zmq_ctx_new") - _ctx_new :: proc() -> rawptr --- + // TODO: Try to access errno directly + errno :: proc() -> c.int --- + + ctx_new :: proc() -> Context --- @(link_name = "zmq_ctx_term") - _ctx_term :: proc(ctx: rawptr) -> c.int --- + _ctx_term :: proc(ctx: Context) -> c.int --- @(link_name = "zmq_socket") - _socket :: proc(ctx: rawptr, type: Socket_Type) -> rawptr --- + _socket :: proc(ctx: Context, type: Socket_Type) -> Socket --- @(link_name = "zmq_close") - _close :: proc(s: rawptr) -> c.int --- + _close :: proc(s: Socket) -> c.int --- @(link_name = "zmq_bind") - _bind :: proc(s: rawptr, addr: cstring) -> c.int --- + _bind :: proc(s: Socket, addr: cstring) -> c.int --- @(link_name = "zmq_connect") - _connect :: proc(s: rawptr, addr: cstring) -> c.int --- + _connect :: proc(s: Socket, addr: cstring) -> c.int --- @(link_name = "zmq_send") - _send :: proc(s: rawptr, buf: rawptr, len: c.size_t, flags: c.int) -> c.int --- + _send :: proc(s: Socket, buf: rawptr, len: c.size_t, flags: Flags) -> c.int --- @(link_name = "zmq_recv") - _recv :: proc(s: rawptr, buf: rawptr, len: c.size_t, flags: c.int) -> c.int --- - @(link_name = "zmq_errno") - _errno :: proc() -> c.int --- + _recv :: proc(s: Socket, buf: rawptr, len: c.size_t, flags: Flags) -> c.int --- @(link_name = "zmq_strerror") _strerror :: proc(errnum: c.int) -> cstring --- @(link_name = "zmq_version") _version :: proc(major, minor, patch: ^c.int) --- } -Context :: distinct rawptr -Socket :: distinct rawptr - Socket_Type :: enum c.int { PAIR = 0, PUB = 1, @@ -73,23 +73,23 @@ Error :: union #shared_nil { ZMQ_Error, } -from_errno :: proc(raw: c.int) -> Error { +last_error :: proc() -> Error { + raw := errno() + if raw >= HAUSNUMERO { return ZMQ_Error(raw) } return os.Platform_Error(raw) } -last_error :: proc() -> Error {return from_errno(_errno())} - -strerror :: proc(e: Error) -> string { +strerror :: proc(e: Error) -> cstring { switch v in e { case os.Platform_Error: - return string(_strerror(c.int(v))) + return _strerror(c.int(v)) case ZMQ_Error: - return string(_strerror(c.int(v))) + return _strerror(c.int(v)) case: - return "" + return _strerror(0) } } @@ -99,46 +99,53 @@ version :: proc() -> (major, minor, patch: int) { return int(ma), int(mi), int(pa) } -ctx_new :: proc() -> Context { - return Context(_ctx_new()) -} - ctx_term :: proc(ctx: Context) -> Error { - return _ctx_term(rawptr(ctx)) == 0 ? nil : last_error() + return _ctx_term(ctx) == 0 ? nil : last_error() } -socket :: proc(ctx: Context, type: Socket_Type) -> (Socket, Error) { - s := _socket(rawptr(ctx), type) +socket :: proc(ctx: Context, type: Socket_Type) -> (s: Socket, err: Error) { + s = _socket(ctx, type) + if s == nil { - return nil, last_error() + err = last_error() } - return Socket(s), nil + + return s, err } close :: proc(s: Socket) -> Error { - return _close(rawptr(s)) == 0 ? nil : last_error() + return _close(s) == 0 ? nil : last_error() } bind :: proc(s: Socket, addr: string, allocator := context.temp_allocator) -> Error { c := strings.clone_to_cstring(addr, allocator) - return _bind(rawptr(s), c) == 0 ? nil : last_error() + return _bind(s, c) == 0 ? nil : last_error() } connect :: proc(s: Socket, addr: string, allocator := context.temp_allocator) -> Error { c := strings.clone_to_cstring(addr, allocator) - return _connect(rawptr(s), c) == 0 ? nil : last_error() + return _connect(s, c) == 0 ? nil : last_error() } -send :: proc(s: Socket, buf: []u8, flags: Flags = Flags{}) -> (int, Error) { - n := _send(rawptr(s), rawptr(&buf[0]), c.size_t(len(buf)), transmute(c.int)flags) +send :: proc { + send_bytes, + send_string, +} + +send_bytes :: proc(s: Socket, buf: []u8, flags: Flags = Flags{}) -> (int, Error) { + n := _send(s, rawptr(&buf[0]), c.size_t(len(buf)), flags) if n < 0 { return -1, last_error() } - return int(n), nil + return int(n), Error{} +} + +send_string :: proc(s: Socket, buf: string, flags: Flags = Flags{}) -> (int, Error) { + return send_bytes(s, transmute([]u8)buf, flags) } recv :: proc(s: Socket, buf: []u8, flags: Flags = Flags{}) -> (int, Error) { - n := _recv(rawptr(s), rawptr(&buf[0]), c.size_t(len(buf)), transmute(c.int)flags) + n := _recv(s, rawptr(&buf[0]), c.size_t(len(buf)), flags) if n < 0 { return -1, last_error() } diff --git a/zmq/zmq_test.odin b/zmq/zmq_test.odin new file mode 100644 index 0000000..72c5adc --- /dev/null +++ b/zmq/zmq_test.odin @@ -0,0 +1,13 @@ +#+test + +package zmq + +import "core:testing" + +@(test) +test_error_type :: proc(t: ^testing.T) { + e: Error = .EFSM + + testing.expect_value(t, size_of(e), 8) +} +