Notcurses-Native.git | lib/Notcurses/Native/ | Str.rakumod


use NativeCall; unit module Notcurses::Native::Str; #|( Helpers for safely transferring C-allocated char* across the NativeCall boundary into Raku-owned Cs. Notcurses returns C from many calls with three distinct ownership semantics, and using C<--> Str> on the binding only works for one of them: =item B (e.g. C, C, C) — the C function strdups; the caller must C the returned pointer. C<--> Str> would copy and leak the original. Use C. =item B (e.g. the C / C family) — the returned pointer is inside the C the caller passed in. Freeing it would corrupt the buf. Use C. =item B (e.g. C, C, C) — the pointer is into notcurses's internal storage; the caller MUST NOT free. C<--> Str> works (Raku copies and never frees the original), so these bindings stay unchanged. ) # libc resolver, shared with Notcurses::Native (used by both the free # helper here and the setenv wrapper there). Resolved at BEGIN time — # the file shipped on disk doesn't change between BEGIN and runtime, so # this is safe to cache. Defers the actual library lookup to NativeCall. sub libc-name(--> Str) is export { state $resolved = do { if $*DISTRO.is-win { 'msvcrt' } elsif $*KERNEL.name.lc.contains('darwin') { 'libc.dylib' } elsif '/lib/ld-musl-x86_64.so.1'.IO.e { # musl Alpine / distroless — libc is the dynamic linker # itself, exposed under architecture-specific filenames. 'libc.musl-x86_64.so.1' } elsif '/lib/ld-musl-aarch64.so.1'.IO.e { 'libc.musl-aarch64.so.1' } else { 'libc.so.6' } }; $resolved } sub c-free(Pointer $p) is export is native(&libc-name) is symbol('free') { * } #|( Decode a malloc'd C string into a Raku-owned C and free the original pointer. Returns the type object C on a null pointer. Use as the wrapper around any notcurses binding whose contract is "caller frees the returned char*". The binding should be declared with C<--> Pointer> instead of C<--> Str> so NativeCall doesn't auto-decode-and-leak. ) sub strdup-copy-and-free(Pointer $p --> Str) is export { return Str unless $p.defined && +$p; my $s = nativecast(Str, $p); c-free($p); $s } #|( Decode a borrowed C-string pointer into a Raku-owned C WITHOUT freeing the source. Use when the pointer is into a caller-provided buffer or library-owned storage. Returns C (type object) on null. ) sub borrowed-str-from-pointer(Pointer $p --> Str) is export { return Str unless $p.defined && +$p; nativecast(Str, $p) }