silk.net.socket_native.
TCP and Unix socket connections and listeners, as ByteDuplex providers.
When to use#
To connect, call
connectResolvedwith endpoints fromsilk.net.resolver, orconnectUnixwith a socket path. The connection is lent to a callback and closed after it. UseconnectResolvedOwnedorconnectUnixOwnedto keep theConnectionyourself.To serve, call
listenorlistenUnix, thenacceptfor each client. UsewithAcceptedto get the connection and the peer address, and close them after.
A Connection provides ByteDuplex, so silk.http.exchange, silk.http.server, and
silk.io.buffered_duplex can use it.
Details#
All sockets are nonblocking. When a socket is not ready, the operation waits for the poll
interval with MonotonicClock, then tries again. So an idle wait costs about one check for each
interval. One deadline covers all attempts of one connect or accept.
A connect tries the endpoints in their order, until one connects or the attempt limit is reached. A flush means that the kernel accepted the bytes, not that the peer got them.
Errors#
NativeSocketError tells the rule, the system error, or the deadline. When all endpoints
fail, AttemptsExhausted has the error of the last attempt.
Gotchas#
With a deadline of
None, a connect or accept can wait forever.Closing a Unix listener does not remove its socket file. Remove it yourself.
Scoped functions close the socket on return, error, and cancellation. A trap does not.
On Darwin, socket setup is not safe against a
forkin another thread.A call fails to compile on targets other than Darwin on aarch64, and Linux with GNU libc on x86_64 or aarch64. The option types still compile.
Examples#
Connect to a local listener#
import silk.io.byte_duplex { ByteDuplex, ByteIoError, ReadTransfer }
import silk.core.effect { Effect }
import silk.system.monotonic_clock { MonotonicClock }
import silk.net.socket_native {
AcceptedView,
BoundAddress,
ConnectOptions,
Connection,
ListenOptions,
Listener,
NativeSocketError,
accept,
connectResolvedOwned,
listen,
withAccepted,
}
import silk.net.address { Endpoint, IpAddress, Ipv4Address, Port }
import silk.core.option { Option }
import silk.system.monotonic_clock_native { OsMonotonicClock }
import silk.system.system_clock { Instant }
// Reads one byte from the client and answers with one byte.
effect fn answer<'call>(view: &'call mut AcceptedView<'call>) -> i32
! ByteIoError
? &mut MonotonicClock {
let mut input: [u8; 1] = [0]
match move run ByteDuplex.readSome(&mut input, Option<Instant>.none())
|> Effect.provideMut<ByteDuplex>(&mut view.connection.*) {
ReadTransfer.Data { count } => {
if count != 1 || input[0] != 120 {
return 1
}
}
ReadTransfer.End => {
return 1
}
}
// One byte is always written at once, or the call fails.
let written = run ByteDuplex.writeSome(b"y", Option<Instant>.none())
|> Effect.provideMut<ByteDuplex>(&mut view.connection.*)
if written != 1 {
return 1
}
return 0
}
effect fn program() -> i32
! NativeSocketError | ByteIoError
? &mut MonotonicClock {
// Port 0 asks the system for a free port.
let local = Endpoint.make(
IpAddress.V4 { value: Ipv4Address.fromOctets([127, 0, 0, 1]) },
Port.fromU16(0)
)
let mut listener = run listen(local, ListenOptions.defaults())
let bound = match Listener.boundAddress(&listener) {
BoundAddress.Tcp { endpoint } => endpoint
_ => {
return 1
}
}
let targets = [bound]
let mut client = run connectResolvedOwned(
&targets,
ConnectOptions.defaults(),
Option<Instant>.none()
)
let sent = run ByteDuplex.writeSome(b"x", Option<Instant>.none())
|> Effect.provideMut<ByteDuplex>(&mut client)
if sent != 1 {
return 1
}
let accepted = run accept(&mut listener, Option<Instant>.none())
run Listener.close(&mut listener)
let served = run withAccepted<i32, ByteIoError>(move accepted, answer)
let mut reply: [u8; 1] = [0]
let read = run ByteDuplex.readSome(&mut reply, Option<Instant>.none())
|> Effect.provideMut<ByteDuplex>(&mut client)
run Connection.close(&mut client)
return match move read {
ReadTransfer.Data { count } => {
if served != 0 || count != 1 || reply[0] != 121 {
return 1
}
return 0
}
ReadTransfer.End => 1
}
}
effect fn failed<E>(error: E) -> i32 {
drop error
return 1
}
pub fn main() -> i32 {
let mut clock = OsMonotonicClock.make()
return run Effect.catchAll(program(), failed) |> Effect.provideMut<MonotonicClock>(&mut clock)
}Import as NativeSocket with import silk.net.socket_native { NativeSocket }.
Public declarations: 33.
ConnectionPhase#
pub enum ConnectionPhaseThe state of a Connection.
Connecting#
ConnectingThe connect has not finished.
Open#
OpenReads and writes are allowed.
WriteClosed#
WriteClosedThe write side is shut down. Reads are still allowed.
Closed#
ClosedThe socket is closed.
NativeSocketOperation#
pub enum NativeSocketOperationThe system call that failed.
Socket#
Socketsocket: create the socket.
Configure#
ConfigureSet descriptor flags or socket options.
Connect#
Connectconnect.
Bind#
Bindbind.
Listen#
Listenlisten.
GetSocketName#
GetSocketNamegetsockname: read the bound address.
Accept#
Acceptaccept.
ConvertAddress#
ConvertAddressConvert an address that the system returned.
Poll#
Pollpoll: check if the socket is ready.
GetSocketOption#
GetSocketOptiongetsockopt: read the error of the socket.
Read#
Readread.
Write#
Writewrite.
ShutdownWrite#
ShutdownWriteshutdown of the write side.
Close#
Closeclose.
Implementation Debug for NativeSocketOperation#
impl Debug for NativeSocketOperationOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as Socket.
ListenerPhase#
pub enum ListenerPhaseThe state of a Listener.
Open#
OpenThe listener accepts clients.
Closed#
ClosedThe listener is closed.
ListenOptionsReason#
pub enum ListenOptionsReasonThe ListenOptions value that is not valid.
KernelBacklog#
KernelBacklogThe backlog is not 1 through 65535.
PollInterval#
PollIntervalThe poll interval is not 1 nanosecond through 1 second.
Implementation Debug for ListenOptionsReason#
impl Debug for ListenOptionsReasonOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as KernelBacklog.
ListenOptionsError#
pub struct ListenOptionsErrorThe error of ListenOptions.make.
Field reason#
pub reason: ListenOptionsReasonThe value that is not valid.
Field value#
pub value: u64The value that you gave.
Implementation Debug for ListenOptionsError#
impl Debug for ListenOptionsErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the fields, as ListenOptionsError { reason: ..., value: ... }.
InvalidBindReason#
pub enum InvalidBindReasonWhy a Unix socket path for listenUnix is not valid.
EmptyPath#
EmptyPathThe path is empty.
RelativePath#
RelativePathThe path does not start with /.
NulPath#
NulPathThe path has a NUL byte.
AbstractPath#
AbstractPathThe path is an abstract socket address, which is not supported.
Implementation Debug for InvalidBindReason#
impl Debug for InvalidBindReasonOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as EmptyPath.
ConnectOptionsReason#
pub enum ConnectOptionsReasonThe ConnectOptions value that is not valid.
PollInterval#
PollIntervalThe poll interval is not 1 nanosecond through 1 second.
MaxAttempts#
MaxAttemptsThe attempt limit is not 1 through 1024.
Implementation Debug for ConnectOptionsReason#
impl Debug for ConnectOptionsReasonOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as PollInterval.
ConnectOptionsError#
pub struct ConnectOptionsErrorThe error of ConnectOptions.make.
Field reason#
pub reason: ConnectOptionsReasonThe value that is not valid.
Field value#
pub value: u64The value that you gave.
Implementation Debug for ConnectOptionsError#
impl Debug for ConnectOptionsErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the fields, as ConnectOptionsError { reason: ..., value: ... }.
InvalidEndpointReason#
pub enum InvalidEndpointReasonWhy the endpoints or the Unix socket path of a connect are not valid.
EmptyEndpoints#
EmptyEndpointsThe endpoint list is empty.
TooManyEndpoints#
TooManyEndpointsThere are more endpoints than the attempt limit.
EmptyPath#
EmptyPathThe path is empty.
RelativePath#
RelativePathThe path does not start with /.
NulPath#
NulPathThe path has a NUL byte.
PathTooLong#
PathTooLongThe path is too long for a socket address.
AbstractPath#
AbstractPathThe path is an abstract socket address, which is not supported.
Implementation Debug for InvalidEndpointReason#
impl Debug for InvalidEndpointReasonOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant, such as EmptyEndpoints.
AttemptFailure#
pub union AttemptFailureThe error of the last connect attempt, in AttemptsExhausted.
ConnectionRefused#
ConnectionRefusedThe peer refused the connection.
NetworkUnreachable#
NetworkUnreachableThe network cannot be reached.
AddressUnavailable#
AddressUnavailableThe address is not available.
NativeFailure#
NativeFailureAnother system error.
Field operation#
pub operation: NativeSocketOperationThe system call that failed.
Field errno#
pub errno: i32The errno value.
Implementation Debug for AttemptFailure#
impl Debug for AttemptFailureOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant and its fields, such as ConnectionRefused.
NativeSocketError#
pub union NativeSocketErrorThe error of a socket operation: the rule that failed, the system error, or the deadline.
AttemptsExhausted#
AttemptsExhaustedAll connect attempts failed.
Field attempted#
pub attempted: usizeThe number of attempts.
Field last#
pub last: AttemptFailureThe error of the last attempt.
TimeRangeError#
TimeRangeErrorThe time of the next check does not fit in an Instant.
InvalidEndpoint#
InvalidEndpointThe endpoints or the socket path of a connect are not valid.
Field reason#
pub reason: InvalidEndpointReasonThe rule that failed.
Field offset#
pub offset: usizeThe byte position of the problem in the path.
Field limit#
pub limit: usizeThe largest allowed value.
InvalidBindAddress#
InvalidBindAddressThe socket path of listenUnix is not valid.
Field reason#
pub reason: InvalidBindReasonThe rule that failed.
Field offset#
pub offset: usizeThe byte position of the problem in the path.
PathTooLong#
PathTooLongThe socket path is too long for a socket address.
Field length#
pub length: usizeThe length of the path.
Field limit#
pub limit: usizeThe largest allowed length.
AddressInUse#
AddressInUseThe local address is in use.
InvalidNativeAddress#
InvalidNativeAddressThe system returned an address with a wrong family or length.
Field family#
pub family: i32The address family, or -1 if the address is too short.
Field length#
pub length: usizeThe length of the address.
UnsupportedPeerAddress#
UnsupportedPeerAddressThe peer has an address form that is not supported.
Field family#
pub family: i32The address family, or -1 if the address is too short.
Field length#
pub length: usizeThe length of the address.
FamilyUnsupported#
FamilyUnsupportedThe system does not support the address family.
PermissionDenied#
PermissionDeniedThe system denied the operation.
ConnectionRefused#
ConnectionRefusedThe peer refused the connection.
NetworkUnreachable#
NetworkUnreachableThe network cannot be reached.
AddressUnavailable#
AddressUnavailableThe address is not available.
SystemResources#
SystemResourcesThe system does not have the resources, such as descriptors.
Timeout#
TimeoutThe deadline passed.
Closed#
ClosedThe socket is closed.
WriteClosed#
WriteClosedThe write side is shut down.
InvalidTransferCount#
InvalidTransferCountThe system returned a transfer count that is not valid.
Field operation#
pub operation: ByteIoOperationThe operation.
Field count#
pub count: usizeThe count that the system returned.
Field limit#
pub limit: usizeThe largest valid count.
NativeFailure#
NativeFailureAnother system error.
Field operation#
pub operation: NativeSocketOperationThe system call that failed.
Field errno#
pub errno: i32The errno value.
Implementation Debug for NativeSocketError#
impl Debug for NativeSocketErrorOperation debug#
effect fn debug(self: &Self, formatter: &mut Formatter) -> () ! WriterError ? &mut WriterWrites the name of the variant and its fields, such as AttemptsExhausted { ... }.
NativeSocket#
pub struct NativeSocketAn empty marker type for this module.
ConnectOptions#
pub struct ConnectOptionsThe settings of a connect: Nagle, the poll interval, and the attempt limit.
ListenOptions#
pub struct ListenOptionsThe settings of a listener: the backlog, address reuse, and the poll interval of accept.
UnixSocketPath#
pub struct UnixSocketPathA copy of a Unix socket path, at most 108 bytes.
BoundAddress#
pub union BoundAddressThe local address of a Listener.
Tcp#
TcpA TCP listener.
Field endpoint#
pub endpoint: EndpointThe address and port. With port 0 in listen, this is the port that the system chose.
Unix#
UnixA Unix socket listener.
Field path#
pub path: UnixSocketPathThe socket path.
UnixPeerAddress#
pub union UnixPeerAddressThe address of a Unix socket client.
Unnamed#
UnnamedThe client socket has no path. This is normal for a client.
Pathname#
PathnameThe client socket has a path.
Field path#
pub path: UnixSocketPathThe path.
PeerAddress#
pub union PeerAddressThe address of an accepted client.
Tcp#
TcpA TCP client.
Field endpoint#
pub endpoint: EndpointThe address and port of the client.
Unix#
UnixA Unix socket client.
Field peer#
pub peer: UnixPeerAddressThe address of the client.
Implementation Copy for ConnectOptionsError#
impl Copy for ConnectOptionsErrorImplementation Copy for AttemptFailure#
impl Copy for AttemptFailureImplementation Copy for NativeSocketError#
impl Copy for NativeSocketErrorImplementation Copy for ConnectOptions#
impl Copy for ConnectOptionsImplementation Copy for ListenOptionsError#
impl Copy for ListenOptionsErrorImplementation Copy for ListenOptions#
impl Copy for ListenOptionsImplementation Copy for UnixSocketPath#
impl Copy for UnixSocketPathImplementation Copy for BoundAddress#
impl Copy for BoundAddressImplementation Copy for UnixPeerAddress#
impl Copy for UnixPeerAddressImplementation Copy for PeerAddress#
impl Copy for PeerAddressImplementation ConnectOptions#
impl ConnectOptionsAssociated function make#
pub fn make(
noDelay: bool,
pollIntervalNanoseconds: u64,
maxAttempts: usize,
) -> Result<ConnectOptions, ConnectOptionsError>Returns connect options.
Errors#
ConnectOptionsError if pollIntervalNanoseconds is not 1 through 1000000000, or
maxAttempts is not 1 through 1024.
Associated function defaults#
pub fn defaults() -> ConnectOptionsReturns the default connect options: Nagle on, a 1 ms poll interval, and 64 attempts.
Method noDelay#
pub fn noDelay(self: &Self) -> boolReturns whether Nagle is off (TCP_NODELAY).
Method pollInterval#
pub fn pollInterval(self: &Self) -> u64Returns the poll interval, in nanoseconds.
Method maxAttempts#
pub fn maxAttempts(self: &Self) -> usizeReturns the attempt limit.
Implementation ListenOptions#
impl ListenOptionsAssociated function make#
pub fn make(
kernelBacklog: usize,
reuseAddress: bool,
pollIntervalNanoseconds: u64,
) -> Result<ListenOptions, ListenOptionsError>Returns listen options.
Errors#
ListenOptionsError if kernelBacklog is not 1 through 65535, or pollIntervalNanoseconds
is not 1 through 1000000000.
Associated function defaults#
pub fn defaults() -> ListenOptionsReturns the default listen options: a backlog of 128, no address reuse, and a 1 ms poll interval.
Method kernelBacklog#
pub fn kernelBacklog(self: &Self) -> usizeReturns the backlog of the kernel.
Method reuseAddress#
pub fn reuseAddress(self: &Self) -> boolReturns whether the listener sets SO_REUSEADDR.
Method pollInterval#
pub fn pollInterval(self: &Self) -> u64Returns the poll interval of accept, in nanoseconds.
Implementation UnixSocketPath#
impl UnixSocketPathMethod bytes#
pub fn bytes(self: &Self) -> &[u8]Returns the path bytes.
Connection#
pub struct ConnectionAn open socket connection. It provides ByteDuplex, so silk.http.exchange,
silk.http.server, and silk.io.buffered_duplex can use it.
Details#
The socket is nonblocking. When it is not ready, an operation waits for the poll interval with
MonotonicClock, then tries again. So an idle wait costs about one check for each interval. A
flush means that the kernel accepted the bytes, not that the peer got them.
Listener#
pub struct ListenerA listening socket and its local address.
Accepted#
pub struct AcceptedA connection from accept, with the address of the client. Use it with withAccepted.
AcceptedView#
pub struct AcceptedView<'a>The connection and the client address that withAccepted lends to its callback.
Field connection#
pub connection: &'a mut ConnectionThe connection. It is valid only in the callback.
Field peer#
pub peer: &'a PeerAddressThe address of the client.
AcceptedContext#
pub interface AcceptedContext<A, E, ?CallbackRequirements, ?ContextRequirements>A value that serves one accepted connection. See withAcceptedContext.
Details#
Implement it when the code that serves the connection owns state that is moved in, such as a
handler. use gets the value one time.
Operation use#
effect<'call> fn use<'call>(
context: Self,
view: &'call mut AcceptedView<'call>,
) -> A ! E ? CallbackRequirements | ContextRequirementsServes the connection in view, with context.
Implementation Connection#
impl ConnectionMethod phase#
pub fn phase(self: &Self) -> ConnectionPhaseReturns the state of the connection.
Method close#
pub effect fn close(self: &mut Self) -> () ! NativeSocketErrorCloses the connection. A second call does nothing.
The scoped functions close the connection too, and ignore a close error.
Implementation Listener#
impl ListenerMethod phase#
pub fn phase(self: &Self) -> ListenerPhaseReturns the state of the listener.
Method boundAddress#
pub fn boundAddress(self: &Self) -> BoundAddressReturns the local address of the listener.
Method close#
pub effect fn close(self: &mut Self) -> () ! NativeSocketErrorCloses the listener. A second call does nothing. It does not remove a Unix socket file.
Implementation Accepted#
impl AcceptedMethod peer#
pub fn peer(self: &Self) -> PeerAddressReturns the address of the client.
Method connectionPhase#
pub fn connectionPhase(self: &Self) -> ConnectionPhaseReturns the state of the connection.
listen#
pub effect fn listen(endpoint: Endpoint, options: ListenOptions) -> Listener ! NativeSocketErrorMakes a TCP listener on endpoint, IPv4 or IPv6.
With port 0, the system chooses a free port. Listener.boundAddress returns it.
Errors#
AddressInUse, PermissionDenied, SystemResources, or another NativeSocketError.
listenUnix#
pub effect fn listenUnix(path: &[u8], options: ListenOptions) -> Listener ! NativeSocketErrorMakes a Unix socket listener at path.
It does not remove an old file at path before, or the file after close.
Errors#
InvalidBindAddress or PathTooLong if path is not valid. AddressInUse if a file exists.
accept#
pub effect fn accept(
listener: &mut Listener,
deadline: Option<Instant>,
) -> Accepted ! NativeSocketError ? &mut MonotonicClockWaits for the next client, and returns its connection.
The listener stays open. deadline is absolute, and covers all checks of this call.
Errors#
Timeout if the deadline passes. Closed if the listener is closed.
withListener#
pub effect fn withListener<'env, A, E, ?CallbackRequirements>(
listener: Listener,
callback: for<'call> once fn<'env>(
&'call mut Listener
) -> once Effect<'call; A ! E ? CallbackRequirements>,
) -> A ! E ? CallbackRequirementsLends listener to callback, and closes it after, also on error or cancellation.
withAccepted#
pub effect fn withAccepted<'env, A, E, ?CallbackRequirements>(
accepted: Accepted,
callback: for<'call> once fn<'env>(
&'call mut AcceptedView<'call>
) -> once Effect<'call; A ! E ? CallbackRequirements>,
) -> A ! E ? CallbackRequirements
where CallbackRequirements in Without<CallbackRequirements, ByteDuplex>Lends the connection and the client address of accepted to callback, and closes the
connection after, also on error or cancellation.
withAcceptedContext#
pub effect<'env> fn withAcceptedContext<
A,
E,
?CallbackRequirements,
?ContextRequirements,
C: AcceptedContext<A, E, CallbackRequirements ? ContextRequirements> + 'env,
'env,
>(
accepted: Accepted,
context: C,
) -> A ! E ? CallbackRequirements | ContextRequirements
where CallbackRequirements in Without<CallbackRequirements, ByteDuplex>,
ContextRequirements in Without<ContextRequirements, ByteDuplex>Serves accepted with context, and closes the connection after.
Details#
context is used one time. The connection is closed on success, error, and cancellation. A
close error never replaces the result.
connectResolvedOwned#
pub effect fn connectResolvedOwned(
endpoints: &[Endpoint],
options: ConnectOptions,
deadline: Option<Instant>,
) -> Connection ! NativeSocketError ? &mut MonotonicClockConnects to the first of endpoints that accepts, and returns the connection.
Errors#
InvalidEndpointifendpointsis empty or longer than the attempt limit.AttemptsExhaustedif no endpoint accepts.Timeoutifdeadlinepasses.
connectUnixOwned#
pub effect fn connectUnixOwned(
path: &[u8],
options: ConnectOptions,
deadline: Option<Instant>,
) -> Connection ! NativeSocketError ? &mut MonotonicClockConnects to the Unix socket at path, and returns the connection.
Errors#
InvalidEndpoint if path is not valid. Timeout if deadline passes.
connectResolved#
pub effect fn connectResolved<'env, A, E, ?CallbackRequirements>(
endpoints: &[Endpoint],
options: ConnectOptions,
deadline: Option<Instant>,
callback: for<'call> once fn<'env>(
&'call mut Connection
) -> once Effect<'call; A ! E ? CallbackRequirements>,
) -> A ! E | NativeSocketError ? CallbackRequirements | &mut MonotonicClock
where CallbackRequirements in Without<CallbackRequirements, ByteDuplex>Connects to the first of endpoints that accepts, lends the connection to callback, and
closes it after, also on error or cancellation. A trap does not close it.
Errors#
The error of
callback.InvalidEndpointifendpointsis empty or longer than the attempt limit.AttemptsExhaustedif no endpoint accepts. It has the error of the last attempt.Timeoutifdeadlinepasses. One deadline covers all attempts.
Gotchas#
With a deadline of None, the connect can wait forever.
connectUnix#
pub effect fn connectUnix<'env, A, E, ?CallbackRequirements>(
path: &[u8],
options: ConnectOptions,
deadline: Option<Instant>,
callback: for<'call> once fn<'env>(
&'call mut Connection
) -> once Effect<'call; A ! E ? CallbackRequirements>,
) -> A ! E | NativeSocketError ? CallbackRequirements | &mut MonotonicClock
where CallbackRequirements in Without<CallbackRequirements, ByteDuplex>Connects to the Unix socket at path, lends the connection to callback, and closes it after,
also on error or cancellation. A trap does not close it.
Errors#
The error of
callback.InvalidEndpointifpathis not valid.Timeoutifdeadlinepasses.
Implementation Connection#
impl ConnectionImplementation ByteDuplex for Connection#
impl ByteDuplex for ConnectionOperation readSomeRaw#
readSomeRaw: Connection.readConnectionOperation writeSomeRaw#
writeSomeRaw: Connection.writeConnectionOperation writeSomeVectoredRaw#
writeSomeVectoredRaw: Connection.writeConnectionVectoredOperation flushRaw#
flushRaw: Connection.flushConnectionOperation shutdownWriteRaw#
shutdownWriteRaw: Connection.shutdownConnectionOperation closeRaw#
closeRaw: Connection.closeByteConnectionCategory: Networking.
Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, wasm32-wasip1, wasm32-wasip2.