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
This commit is contained in:
parent
1027e21eee
commit
a9e121380b
3 changed files with 78 additions and 34 deletions
|
|
@ -1,20 +1,42 @@
|
|||
MakeFlipdot⇐
|
||||
WithFlipdot⇐
|
||||
|
||||
# - host (char*) argument:
|
||||
# - Assume char is i8 (safe even if it's actually u8 if
|
||||
# ASCII). We can't let •FFI check this for us since CBQN doesn't support
|
||||
# specifying c7. We do this in MakeFlipdot
|
||||
# - Needs to be zero-terminated, we also do this in MakeFlipdot.
|
||||
# - bitmap_len (size_t) argument: assume size_t is at least u32.
|
||||
ffi_send_to_flipdot ← "libflipdot.so" •FFI "i8"‿"send_to_flipdot"‿"*i8:c8"‿"u16"‿"*u8"‿"u32"
|
||||
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 ← {
|
||||
host‿port 𝕊 w‿h:
|
||||
"Total pixel count must be divisible by 8" ! 0=8|w×h
|
||||
host‿port‿w‿h:
|
||||
"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 ⇐ h‿w
|
||||
empty ⇐ shape⥊0
|
||||
Send ⇐ {"sendto(2) error"!FFI_send_to_flipdot (host∾@)‿port∾(⊢⋈≠) Compact 𝕩}
|
||||
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
|
||||
s‿r ← (1⊸⋈∘𝔾)⎊(0⊸⋈∘(•CurrentError⎊("_defer_: Unknown Error occurred"˙))) 𝕩 ⋄ 𝔽 𝕩 ⋄ r⊣r!s;
|
||||
(𝕨⊸𝔽) _𝕣_ (𝕨⊸𝔾) 𝕩
|
||||
}
|
||||
|
||||
WithFlipdot ← {{𝕩.Close @} _defer_ 𝕏 MakeFlipdot 𝕨}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue