snix/users/sterni/blipqn/blipqn.bqn
sterni a9e121380b feat(sterni/blipqn): reuse address and socket for multiple Sends
This is achieved by storing the resources we need to acquire for
interacting with the flipdot (socket fd and addrinfo struct) in a
`struct flipdot` that is dynamically allocated and treated as an opaque
pointer object via the BQN FFI.

To make sure these resources are released correctly, we only provide a
lisp style WithFlipdot to the user which takes care of acquiring and
releasing the `struct flipdot`. This works even if an error occurs in
the function the user provides thanks to _defer_. I'm not sure if
calling it _defer_ is right since Go's error handling works differently,
so defer really is deferred execution in a sense which doesn't really
fit what we're doing here. The closest is probably Haskell's bracket,
but that name references it's triadic nature which doesn't fit our
implementation.

Change-Id: Iff65d277a448dbe0c6ac93e816ece5ab6fa10190
Reviewed-on: https://cl.tvl.fyi/c/depot/+/13011
Reviewed-by: sterni <sternenseemann@systemli.org>
Tested-by: BuildkiteCI
2025-01-17 15:50:33 +00:00

42 lines
1.5 KiB
BQN
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

WithFlipdot
t {
bool "i8"
# needs bound checking in wrapper (no c7 in CBQN) and zero byte appended
charp "*i8:c8"
# assume size_t is at least 32bit
size "u32"
# used for struct flipdot *
hdl "*"
}
ffi_flipdot_open "libflipdot.so" •FFI t.hdl"flipdot_open"t.charp"u16"
ffi_flipdot_close "libflipdot.so" •FFI """flipdot_close"t.hdl
ffi_flipdot_send "libflipdot.so" •FFI t.bool"flipdot_send"t.hdl"*u8"t.size
Compact +´( × 2)˘(8)
MakeFlipdot {
hostportwh:
"Hostname must be ASCII" ! ´(@+127)host
"Total pixel count must be divisible by 8" ! 0=8|w×h
hdl FFI_flipdot_open (host@)port
Close {𝕤 FFI_flipdot_close hdl}
shape hw
empty shape0
Send {FFI_flipdot_send hdl() Compact 𝕩}
}
# Inspired by Go's defer. Will execute 𝔽 after 𝔾 (passing 𝕨 and 𝕩 to each)
# even if an error occurs. If an error occurred, _defer_ will cause an
# assertion failure with the error message after executing 𝔾. This looses
# the original error location, though.
_defer_ {
# At least in CBQN, •CurrentError may fail for namespace related reasons
sr (1𝔾)(0(•CurrentError("_defer_: Unknown Error occurred"˙))) 𝕩 𝔽 𝕩 rr!s;
(𝕨𝔽) _𝕣_ (𝕨𝔾) 𝕩
}
WithFlipdot {{𝕩.Close @} _defer_ 𝕏 MakeFlipdot 𝕨}