Selkie.git | lib/Selkie/App/Internal/ | ErrorLogPlatform.rakumod


=begin pod

=head1 NAME

Selkie::App::Internal::ErrorLogPlatform - platform fd adapter for error logging

=head1 DESCRIPTION

Internal implementation detail used by C<Selkie::App::Internal::ErrorLog>.

=end pod

unit module Selkie::App::Internal::ErrorLogPlatform;

use NativeCall;

use Selkie::App::Internal::PosixFD;

# Official Windows MoarVM builds use /MT, so their integer file descriptors
# belong to a private, statically linked CRT.  No NativeCall DLL owns that
# descriptor table.  Windows therefore redirects Raku's PROCESS::<$ERR>
# object and the independent Win32 standard handle; only POSIX mutates fd 2.
our sub error-log-api-spec(Bool:D $is-win --> Map:D) is export(:test) {
	$is-win
		?? Map.new(
			api          => "win32",
			library      => "kernel32",
			create-file  => "CreateFileW",
			close-handle => "CloseHandle",
		)
		!! Map.new(
			api     => "posix",
			library => Str,
			dup     => "dup",
			dup2    => "dup2",
			close   => "close",
		)
}

our constant IS-WINDOWS is export = $*DISTRO.is-win;
our constant WINDOWS-STD-ERROR-HANDLE is export = 0xFFFF_FFF4;
our constant WINDOWS-FILE-APPEND-DATA is export = 0x0000_0004;
our constant WINDOWS-SYNCHRONIZE is export = 0x0010_0000;
our constant WINDOWS-FILE-SHARE-ALL is export = 0x0000_0007;
our constant WINDOWS-OPEN-ALWAYS is export = 4;
our constant WINDOWS-FILE-ATTRIBUTE-NORMAL is export = 0x0000_0080;
our sub fd-dup(int32 $fd --> int32) is export {
	posix-fd-dup($fd)
}
our sub fd-dup2(int32 $source, int32 $target --> int32) is export {
	posix-fd-dup2($source, $target)
}
our sub fd-close(int32 $fd --> int32) is export {
	posix-fd-close($fd)
}

# GetStdHandle and SetStdHandle take a DWORD, not a signed integer.  The
# standard-handle constants are C casts such as ((DWORD)-12), whose value at
# the ABI boundary is the unsigned 32-bit integer 0xFFFFFFF4.  Passing -12 as
# an int32 is not portable through foreign-function interfaces.
our sub windows-get-std-handle(uint32 --> Pointer) is export
	is native("kernel32") is symbol("GetStdHandle") { * }
our sub windows-set-std-handle(uint32, Pointer --> int32) is export
	is native("kernel32") is symbol("SetStdHandle") { * }
our sub windows-create-file(
	Str is encoded("utf16"), uint32, uint32, Pointer,
	uint32, uint32, Pointer --> Pointer
) is export is native("kernel32") is symbol("CreateFileW") { * }
our sub windows-close-handle(Pointer --> int32) is export
	is native("kernel32") is symbol("CloseHandle") { * }