diff --git a/README.md b/README.md index 4ba59d5e5..27365e258 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ learned from Preview 1, including adding support for a wider range of source languages, modularity, a more expressive type system, virtualizability, and more. -[Preview 1]: https://github.com/WebAssembly/WASI/tree/main/legacy/README.md +[Preview 1]: https://github.com/WebAssembly/WASI/tree/wasi-0.1 [WASI Preview 2]: https://github.com/WebAssembly/WASI/blob/main/docs/Preview2.md [Wit IDL]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md diff --git a/legacy/README.md b/legacy/README.md deleted file mode 100644 index c30d5f006..000000000 --- a/legacy/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Legacy WASI docs - -This directory documents the "preview0" and "preview1" iterations of WASI. - -Preview0 corresponded to the import module name `wasi_unstable`. It was -also called `snapshot_0` in some places. It was short-lived, and the changes -to preview1 were minor, so the focus here is on preview1. - -Preview1 corresponds to the import module name `wasi_snapshot_preview1`. - -There was some work under the name "ephemeral" towards an update of preview1 -however it is no longer being actively developed. The name "preview2" now -refers to the new wit-based iteration of WASI instead. - -Preview1 was defined using the witx IDL and associated tooling. Witx was -an s-expression-based IDL derived from WebAssembly's wat text format, adding -several extensions. It had a low-level C-like type system that emphasized raw -pointers, and callees were expected to have access to the caller's entire -linear memory, exported as "memory". It also had an implied global file -descriptor table. - -Some features in preview1 were not widely supported by engines: - - The `proc_raise` function, because Wasm itself has no signal-handling - facilities, and a process wishing to terminate abnormally typically - uses a Wasm trap instead of calling `proc_raise`. - - - The `process_cputime_id` and `thread_cputime_id`, because in many - engines, Wasm instances are not one-to-one with host processes, so the - usual host APIs aren't sufficient to implement these. - -One function has been added to preview1: - - `sock_accept`, allowing limited socket use cases to be supported. - Sockets support with `listen` and `connect` is being added in preview2. diff --git a/legacy/application-abi.md b/legacy/application-abi.md deleted file mode 100644 index ab36b34ab..000000000 --- a/legacy/application-abi.md +++ /dev/null @@ -1,75 +0,0 @@ -WASI Application ABI -==================== - -In addition to the APIs defined by the various WASI modules there -are also certain expectations that the WASI runtime places on an application -that wishes to be portable across WASI implementations. - -This document describes how a conforming WASI application is expected to behave -in terms of lifecycle (startup, shutdown, etc) and any exports it is expected to -include. - -Current Unstable ABI --------------------- - -There are two kinds of modules: - - - A *command* exports a function named `_start`, with no arguments and no return - values. - - `_start` is the default export which is called when the user doesn't select a - specific function to call. Commands may also export additional functions, - (similar to "multi-call" executables), which may be explicitly selected by the - user to run instead. - - Except as noted below, commands shall not export any mutable globals, tables, - or linear memories. - - Command instances may assume that they will be called from the environment - at most once. Command instances may assume that none of their exports are - accessed outside the duration of that call. - - - All other modules are *reactors*. A reactor may export a function named - `_initialize`, with no arguments and no return values. - - If an `_initialize` export is present, reactor instances may assume that it - will be called by the environment at most once, and that none of their - other exports are accessed before that call. - - After being instantiated, and after any `_initialize` function is called, - a reactor instance remains live, and its exports may be accessed. - -These kinds are mutually exclusive; implementations should report an error if -asked to instantiate a module containing exports which declare it to be of -multiple kinds. - -Regardless of the kind, all modules accessing WASI APIs also export a linear -memory with the name `memory`. Data pointers in WASI API calls are relative to -this memory's index space. - -Regardless of the kind, all modules accessing WASI APIs also export a table -with the name `__indirect_function_table`. Function pointers in WASI API calls -are relative to this table's index space. - -When `_start` or `_initialize` is called, environments shall provide file -descriptors with indices 0, 1, and 2 representing stream resources for -standard input, standard output, and standard error. Environments may provide -additional "preopen" file descriptors that can be inspected with -`fd_prestat_get` and `fd_prestat_dir_name`. These resources may be closed at -any time. - -Environments shall not access exports named `__heap_base` or `__data_end`. -Toolchains are encouraged to avoid providing these exports. - -In the future, as the underlying WebAssembly platform offers more features, -we hope to eliminate the requirement to export all of linear memory or all of -the indirect function table. - -Planned Stable ABI ------------------- - -There is ongoing discussion about what the stable ABI might look like: - -- https://github.com/WebAssembly/WASI/issues/13 -- https://github.com/WebAssembly/WASI/issues/19 -- https://github.com/WebAssembly/WASI/issues/24 diff --git a/legacy/optional-imports.md b/legacy/optional-imports.md deleted file mode 100644 index 237cd3927..000000000 --- a/legacy/optional-imports.md +++ /dev/null @@ -1,9 +0,0 @@ -Optional Imports -================ - -WASI originally had its own design for optional imports. To our knowledge, -no toolchains or engines ever implemented it, and it is no longer active. -In the future, optional imports are expected to be a -[feature of the component model]. - -[feature of the component model]: https://github.com/WebAssembly/component-model/blob/main/design/high-level/UseCases.md#exposing-host-functionality-to-components-as-imports diff --git a/legacy/preview0/docs.md b/legacy/preview0/docs.md deleted file mode 100644 index bfa2ea9ad..000000000 --- a/legacy/preview0/docs.md +++ /dev/null @@ -1,2509 +0,0 @@ -# Types -## `size`: `u32` - -Size: 4 - -Alignment: 4 - -## `filesize`: `u64` -Non-negative file size or length of a region within a file. - -Size: 8 - -Alignment: 8 - -## `timestamp`: `u64` -Timestamp in nanoseconds. - -Size: 8 - -Alignment: 8 - -## `clockid`: `Variant` -Identifiers for clocks. - -Size: 4 - -Alignment: 4 - -### Variant cases -- `realtime` -The clock measuring real time. Time value zero corresponds with -1970-01-01T00:00:00Z. - -- `monotonic` -The store-wide monotonic clock, which is defined as a clock measuring -real time, whose value cannot be adjusted and which cannot have negative -clock jumps. The epoch of this clock is undefined. The absolute time -value of this clock therefore has no meaning. - -- `process_cputime_id` -The CPU-time clock associated with the current process. - -- `thread_cputime_id` -The CPU-time clock associated with the current thread. - -## `errno`: `Variant` -Error codes returned by functions. -Not all of these error codes are returned by the functions provided by this -API; some are used in higher-level library layers, and others are provided -merely for alignment with POSIX. - -Size: 2 - -Alignment: 2 - -### Variant cases -- `success` -No error occurred. System call completed successfully. - -- `2big` -Argument list too long. - -- `acces` -Permission denied. - -- `addrinuse` -Address in use. - -- `addrnotavail` -Address not available. - -- `afnosupport` -Address family not supported. - -- `again` -Resource unavailable, or operation would block. - -- `already` -Connection already in progress. - -- `badf` -Bad file descriptor. - -- `badmsg` -Bad message. - -- `busy` -Device or resource busy. - -- `canceled` -Operation canceled. - -- `child` -No child processes. - -- `connaborted` -Connection aborted. - -- `connrefused` -Connection refused. - -- `connreset` -Connection reset. - -- `deadlk` -Resource deadlock would occur. - -- `destaddrreq` -Destination address required. - -- `dom` -Mathematics argument out of domain of function. - -- `dquot` -Reserved. - -- `exist` -File exists. - -- `fault` -Bad address. - -- `fbig` -File too large. - -- `hostunreach` -Host is unreachable. - -- `idrm` -Identifier removed. - -- `ilseq` -Illegal byte sequence. - -- `inprogress` -Operation in progress. - -- `intr` -Interrupted function. - -- `inval` -Invalid argument. - -- `io` -I/O error. - -- `isconn` -Socket is connected. - -- `isdir` -Is a directory. - -- `loop` -Too many levels of symbolic links. - -- `mfile` -File descriptor value too large. - -- `mlink` -Too many links. - -- `msgsize` -Message too large. - -- `multihop` -Reserved. - -- `nametoolong` -Filename too long. - -- `netdown` -Network is down. - -- `netreset` -Connection aborted by network. - -- `netunreach` -Network unreachable. - -- `nfile` -Too many files open in system. - -- `nobufs` -No buffer space available. - -- `nodev` -No such device. - -- `noent` -No such file or directory. - -- `noexec` -Executable file format error. - -- `nolck` -No locks available. - -- `nolink` -Reserved. - -- `nomem` -Not enough space. - -- `nomsg` -No message of the desired type. - -- `noprotoopt` -Protocol not available. - -- `nospc` -No space left on device. - -- `nosys` -Function not supported. - -- `notconn` -The socket is not connected. - -- `notdir` -Not a directory or a symbolic link to a directory. - -- `notempty` -Directory not empty. - -- `notrecoverable` -State not recoverable. - -- `notsock` -Not a socket. - -- `notsup` -Not supported, or operation not supported on socket. - -- `notty` -Inappropriate I/O control operation. - -- `nxio` -No such device or address. - -- `overflow` -Value too large to be stored in data type. - -- `ownerdead` -Previous owner died. - -- `perm` -Operation not permitted. - -- `pipe` -Broken pipe. - -- `proto` -Protocol error. - -- `protonosupport` -Protocol not supported. - -- `prototype` -Protocol wrong type for socket. - -- `range` -Result too large. - -- `rofs` -Read-only file system. - -- `spipe` -Invalid seek. - -- `srch` -No such process. - -- `stale` -Reserved. - -- `timedout` -Connection timed out. - -- `txtbsy` -Text file busy. - -- `xdev` -Cross-device link. - -- `notcapable` -Extension: Capabilities insufficient. - -## `rights`: `Record` -File descriptor rights, determining which actions may be performed. - -Size: 8 - -Alignment: 8 - -### Record members -- `fd_datasync`: `bool` -The right to invoke [`fd_datasync`](#fd_datasync). -If [`rights::path_open`](#rights.path_open) is set, includes the right to invoke -[`path_open`](#path_open) with [`fdflags::dsync`](#fdflags.dsync). - -Bit: 0 - -- `fd_read`: `bool` -The right to invoke [`fd_read`](#fd_read) and [`sock_recv`](#sock_recv). -If [`rights::fd_seek`](#rights.fd_seek) is set, includes the right to invoke [`fd_pread`](#fd_pread). - -Bit: 1 - -- `fd_seek`: `bool` -The right to invoke [`fd_seek`](#fd_seek). This flag implies [`rights::fd_tell`](#rights.fd_tell). - -Bit: 2 - -- `fd_fdstat_set_flags`: `bool` -The right to invoke [`fd_fdstat_set_flags`](#fd_fdstat_set_flags). - -Bit: 3 - -- `fd_sync`: `bool` -The right to invoke [`fd_sync`](#fd_sync). -If [`rights::path_open`](#rights.path_open) is set, includes the right to invoke -[`path_open`](#path_open) with [`fdflags::rsync`](#fdflags.rsync) and [`fdflags::dsync`](#fdflags.dsync). - -Bit: 4 - -- `fd_tell`: `bool` -The right to invoke [`fd_seek`](#fd_seek) in such a way that the file offset -remains unaltered (i.e., [`whence::cur`](#whence.cur) with offset zero), or to -invoke [`fd_tell`](#fd_tell). - -Bit: 5 - -- `fd_write`: `bool` -The right to invoke [`fd_write`](#fd_write) and [`sock_send`](#sock_send). -If [`rights::fd_seek`](#rights.fd_seek) is set, includes the right to invoke [`fd_pwrite`](#fd_pwrite). - -Bit: 6 - -- `fd_advise`: `bool` -The right to invoke [`fd_advise`](#fd_advise). - -Bit: 7 - -- `fd_allocate`: `bool` -The right to invoke [`fd_allocate`](#fd_allocate). - -Bit: 8 - -- `path_create_directory`: `bool` -The right to invoke [`path_create_directory`](#path_create_directory). - -Bit: 9 - -- `path_create_file`: `bool` -If [`rights::path_open`](#rights.path_open) is set, the right to invoke [`path_open`](#path_open) with [`oflags::creat`](#oflags.creat). - -Bit: 10 - -- `path_link_source`: `bool` -The right to invoke [`path_link`](#path_link) with the file descriptor as the -source directory. - -Bit: 11 - -- `path_link_target`: `bool` -The right to invoke [`path_link`](#path_link) with the file descriptor as the -target directory. - -Bit: 12 - -- `path_open`: `bool` -The right to invoke [`path_open`](#path_open). - -Bit: 13 - -- `fd_readdir`: `bool` -The right to invoke [`fd_readdir`](#fd_readdir). - -Bit: 14 - -- `path_readlink`: `bool` -The right to invoke [`path_readlink`](#path_readlink). - -Bit: 15 - -- `path_rename_source`: `bool` -The right to invoke [`path_rename`](#path_rename) with the file descriptor as the source directory. - -Bit: 16 - -- `path_rename_target`: `bool` -The right to invoke [`path_rename`](#path_rename) with the file descriptor as the target directory. - -Bit: 17 - -- `path_filestat_get`: `bool` -The right to invoke [`path_filestat_get`](#path_filestat_get). - -Bit: 18 - -- `path_filestat_set_size`: `bool` -The right to change a file's size (there is no `path_filestat_set_size`). -If [`rights::path_open`](#rights.path_open) is set, includes the right to invoke [`path_open`](#path_open) with [`oflags::trunc`](#oflags.trunc). - -Bit: 19 - -- `path_filestat_set_times`: `bool` -The right to invoke [`path_filestat_set_times`](#path_filestat_set_times). - -Bit: 20 - -- `fd_filestat_get`: `bool` -The right to invoke [`fd_filestat_get`](#fd_filestat_get). - -Bit: 21 - -- `fd_filestat_set_size`: `bool` -The right to invoke [`fd_filestat_set_size`](#fd_filestat_set_size). - -Bit: 22 - -- `fd_filestat_set_times`: `bool` -The right to invoke [`fd_filestat_set_times`](#fd_filestat_set_times). - -Bit: 23 - -- `path_symlink`: `bool` -The right to invoke [`path_symlink`](#path_symlink). - -Bit: 24 - -- `path_remove_directory`: `bool` -The right to invoke [`path_remove_directory`](#path_remove_directory). - -Bit: 25 - -- `path_unlink_file`: `bool` -The right to invoke [`path_unlink_file`](#path_unlink_file). - -Bit: 26 - -- `poll_fd_readwrite`: `bool` -If [`rights::fd_read`](#rights.fd_read) is set, includes the right to invoke [`poll_oneoff`](#poll_oneoff) to subscribe to [`eventtype::fd_read`](#eventtype.fd_read). -If [`rights::fd_write`](#rights.fd_write) is set, includes the right to invoke [`poll_oneoff`](#poll_oneoff) to subscribe to [`eventtype::fd_write`](#eventtype.fd_write). - -Bit: 27 - -- `sock_shutdown`: `bool` -The right to invoke [`sock_shutdown`](#sock_shutdown). - -Bit: 28 - -## `fd`: `Handle` -A file descriptor handle. - -Size: 4 - -Alignment: 4 - -### Supertypes -## `iovec`: `Record` -A region of memory for scatter/gather reads. - -Size: 8 - -Alignment: 4 - -### Record members -- `buf`: `Pointer` -The address of the buffer to be filled. - -Offset: 0 - -- `buf_len`: [`size`](#size) -The length of the buffer to be filled. - -Offset: 4 - -## `ciovec`: `Record` -A region of memory for scatter/gather writes. - -Size: 8 - -Alignment: 4 - -### Record members -- `buf`: `ConstPointer` -The address of the buffer to be written. - -Offset: 0 - -- `buf_len`: [`size`](#size) -The length of the buffer to be written. - -Offset: 4 - -## `iovec_array`: `List` - -Size: 8 - -Alignment: 4 - -## `ciovec_array`: `List` - -Size: 8 - -Alignment: 4 - -## `filedelta`: `s64` -Relative offset within a file. - -Size: 8 - -Alignment: 8 - -## `whence`: `Variant` -The position relative to which to set the offset of the file descriptor. - -Size: 1 - -Alignment: 1 - -### Variant cases -- `cur` -Seek relative to current position. - -- `end` -Seek relative to end-of-file. - -- `set` -Seek relative to start-of-file. - -## `dircookie`: `u64` -A reference to the offset of a directory entry. - -Size: 8 - -Alignment: 8 - -## `dirnamlen`: `u32` -The type for the [`dirent::d_namlen`](#dirent.d_namlen) field of [`dirent`](#dirent) struct. - -Size: 4 - -Alignment: 4 - -## `inode`: `u64` -File serial number that is unique within its file system. - -Size: 8 - -Alignment: 8 - -## `filetype`: `Variant` -The type of a file descriptor or file. - -Size: 1 - -Alignment: 1 - -### Variant cases -- `unknown` -The type of the file descriptor or file is unknown or is different from any of the other types specified. - -- `block_device` -The file descriptor or file refers to a block device inode. - -- `character_device` -The file descriptor or file refers to a character device inode. - -- `directory` -The file descriptor or file refers to a directory inode. - -- `regular_file` -The file descriptor or file refers to a regular file inode. - -- `socket_dgram` -The file descriptor or file refers to a datagram socket. - -- `socket_stream` -The file descriptor or file refers to a byte-stream socket. - -- `symbolic_link` -The file refers to a symbolic link inode. - -## `dirent`: `Record` -A directory entry. - -Size: 24 - -Alignment: 8 - -### Record members -- `d_next`: [`dircookie`](#dircookie) -The offset of the next directory entry stored in this directory. - -Offset: 0 - -- `d_ino`: [`inode`](#inode) -The serial number of the file referred to by this directory entry. - -Offset: 8 - -- `d_namlen`: [`dirnamlen`](#dirnamlen) -The length of the name of the directory entry. - -Offset: 16 - -- `d_type`: [`filetype`](#filetype) -The type of the file referred to by this directory entry. - -Offset: 20 - -## `advice`: `Variant` -File or memory access pattern advisory information. - -Size: 1 - -Alignment: 1 - -### Variant cases -- `normal` -The application has no advice to give on its behavior with respect to the specified data. - -- `sequential` -The application expects to access the specified data sequentially from lower offsets to higher offsets. - -- `random` -The application expects to access the specified data in a random order. - -- `willneed` -The application expects to access the specified data in the near future. - -- `dontneed` -The application expects that it will not access the specified data in the near future. - -- `noreuse` -The application expects to access the specified data once and then not reuse it thereafter. - -## `fdflags`: `Record` -File descriptor flags. - -Size: 2 - -Alignment: 2 - -### Record members -- `append`: `bool` -Append mode: Data written to the file is always appended to the file's end. - -Bit: 0 - -- `dsync`: `bool` -Write according to synchronized I/O data integrity completion. Only the data stored in the file is synchronized. - -Bit: 1 - -- `nonblock`: `bool` -Non-blocking mode. - -Bit: 2 - -- `rsync`: `bool` -Synchronized read I/O operations. - -Bit: 3 - -- `sync`: `bool` -Write according to synchronized I/O file integrity completion. In -addition to synchronizing the data stored in the file, the implementation -may also synchronously update the file's metadata. - -Bit: 4 - -## `fdstat`: `Record` -File descriptor attributes. - -Size: 24 - -Alignment: 8 - -### Record members -- `fs_filetype`: [`filetype`](#filetype) -File type. - -Offset: 0 - -- `fs_flags`: [`fdflags`](#fdflags) -File descriptor flags. - -Offset: 2 - -- `fs_rights_base`: [`rights`](#rights) -Rights that apply to this file descriptor. - -Offset: 8 - -- `fs_rights_inheriting`: [`rights`](#rights) -Maximum set of rights that may be installed on new file descriptors that -are created through this file descriptor, e.g., through [`path_open`](#path_open). - -Offset: 16 - -## `device`: `u64` -Identifier for a device containing a file system. Can be used in combination -with [`inode`](#inode) to uniquely identify a file or directory in the filesystem. - -Size: 8 - -Alignment: 8 - -## `fstflags`: `Record` -Which file time attributes to adjust. - -Size: 2 - -Alignment: 2 - -### Record members -- `atim`: `bool` -Adjust the last data access timestamp to the value stored in [`filestat::atim`](#filestat.atim). - -Bit: 0 - -- `atim_now`: `bool` -Adjust the last data access timestamp to the time of clock [`clockid::realtime`](#clockid.realtime). - -Bit: 1 - -- `mtim`: `bool` -Adjust the last data modification timestamp to the value stored in [`filestat::mtim`](#filestat.mtim). - -Bit: 2 - -- `mtim_now`: `bool` -Adjust the last data modification timestamp to the time of clock [`clockid::realtime`](#clockid.realtime). - -Bit: 3 - -## `lookupflags`: `Record` -Flags determining the method of how paths are resolved. - -Size: 4 - -Alignment: 4 - -### Record members -- `symlink_follow`: `bool` -As long as the resolved path corresponds to a symbolic link, it is expanded. - -Bit: 0 - -## `oflags`: `Record` -Open flags used by [`path_open`](#path_open). - -Size: 2 - -Alignment: 2 - -### Record members -- `creat`: `bool` -Create file if it does not exist. - -Bit: 0 - -- `directory`: `bool` -Fail if not a directory. - -Bit: 1 - -- `excl`: `bool` -Fail if file already exists. - -Bit: 2 - -- `trunc`: `bool` -Truncate file to size 0. - -Bit: 3 - -## `linkcount`: `u32` -Number of hard links to an inode. - -Size: 4 - -Alignment: 4 - -## `filestat`: `Record` -File attributes. - -Size: 56 - -Alignment: 8 - -### Record members -- `dev`: [`device`](#device) -Device ID of device containing the file. - -Offset: 0 - -- `ino`: [`inode`](#inode) -File serial number. - -Offset: 8 - -- `filetype`: [`filetype`](#filetype) -File type. - -Offset: 16 - -- `nlink`: [`linkcount`](#linkcount) -Number of hard links to the file. - -Offset: 20 - -- `size`: [`filesize`](#filesize) -For regular files, the file size in bytes. For symbolic links, the length in bytes of the pathname contained in the symbolic link. - -Offset: 24 - -- `atim`: [`timestamp`](#timestamp) -Last data access timestamp. - -Offset: 32 - -- `mtim`: [`timestamp`](#timestamp) -Last data modification timestamp. - -Offset: 40 - -- `ctim`: [`timestamp`](#timestamp) -Last file status change timestamp. - -Offset: 48 - -## `userdata`: `u64` -User-provided value that may be attached to objects that is retained when -extracted from the implementation. - -Size: 8 - -Alignment: 8 - -## `eventtype`: `Variant` -Type of a subscription to an event or its occurrence. - -Size: 1 - -Alignment: 1 - -### Variant cases -- `clock` -The time value of clock [`subscription_clock::id`](#subscription_clock.id) has -reached timestamp [`subscription_clock::timeout`](#subscription_clock.timeout). - -- `fd_read` -File descriptor [`subscription_fd_readwrite::file_descriptor`](#subscription_fd_readwrite.file_descriptor) has data -available for reading. This event always triggers for regular files. - -- `fd_write` -File descriptor [`subscription_fd_readwrite::file_descriptor`](#subscription_fd_readwrite.file_descriptor) has capacity -available for writing. This event always triggers for regular files. - -## `eventrwflags`: `Record` -The state of the file descriptor subscribed to with -[`eventtype::fd_read`](#eventtype.fd_read) or [`eventtype::fd_write`](#eventtype.fd_write). - -Size: 2 - -Alignment: 2 - -### Record members -- `fd_readwrite_hangup`: `bool` -The peer of this socket has closed or disconnected. - -Bit: 0 - -## `event_fd_readwrite`: `Record` -The contents of an [`event`](#event) for the [`eventtype::fd_read`](#eventtype.fd_read) and -[`eventtype::fd_write`](#eventtype.fd_write) variants - -Size: 16 - -Alignment: 8 - -### Record members -- `nbytes`: [`filesize`](#filesize) -The number of bytes available for reading or writing. - -Offset: 0 - -- `flags`: [`eventrwflags`](#eventrwflags) -The state of the file descriptor. - -Offset: 8 - -## `event`: `Record` -An event that occurred. - -Size: 32 - -Alignment: 8 - -### Record members -- `userdata`: [`userdata`](#userdata) -User-provided value that got attached to [`subscription::userdata`](#subscription.userdata). - -Offset: 0 - -- `error`: [`errno`](#errno) -If non-zero, an error that occurred while processing the subscription request. - -Offset: 8 - -- `type`: [`eventtype`](#eventtype) -The type of event that occurred - -Offset: 10 - -- `fd_readwrite`: [`event_fd_readwrite`](#event_fd_readwrite) -The contents of the event, if it is an [`eventtype::fd_read`](#eventtype.fd_read) or -[`eventtype::fd_write`](#eventtype.fd_write). [`eventtype::clock`](#eventtype.clock) events ignore this field. - -Offset: 16 - -## `subclockflags`: `Record` -Flags determining how to interpret the timestamp provided in -[`subscription_clock::timeout`](#subscription_clock.timeout). - -Size: 2 - -Alignment: 2 - -### Record members -- `subscription_clock_abstime`: `bool` -If set, treat the timestamp provided in -[`subscription_clock::timeout`](#subscription_clock.timeout) as an absolute timestamp of clock -[`subscription_clock::id`](#subscription_clock.id). If clear, treat the timestamp -provided in [`subscription_clock::timeout`](#subscription_clock.timeout) relative to the -current time value of clock [`subscription_clock::id`](#subscription_clock.id). - -Bit: 0 - -## `subscription_clock`: `Record` -The contents of a [`subscription`](#subscription) when type is [`eventtype::clock`](#eventtype.clock). - -Size: 40 - -Alignment: 8 - -### Record members -- `identifier`: [`userdata`](#userdata) -The user-defined unique identifier of the clock. - -Offset: 0 - -- `id`: [`clockid`](#clockid) -The clock against which to compare the timestamp. - -Offset: 8 - -- `timeout`: [`timestamp`](#timestamp) -The absolute or relative timestamp. - -Offset: 16 - -- `precision`: [`timestamp`](#timestamp) -The amount of time that the implementation may wait additionally -to coalesce with other events. - -Offset: 24 - -- `flags`: [`subclockflags`](#subclockflags) -Flags specifying whether the timeout is absolute or relative - -Offset: 32 - -## `subscription_fd_readwrite`: `Record` -The contents of a [`subscription`](#subscription) when the variant is -[`eventtype::fd_read`](#eventtype.fd_read) or [`eventtype::fd_write`](#eventtype.fd_write). - -Size: 4 - -Alignment: 4 - -### Record members -- `file_descriptor`: [`fd`](#fd) -The file descriptor on which to wait for it to become ready for reading or writing. - -Offset: 0 - -## `subscription_u`: `Variant` -The contents of a [`subscription`](#subscription). - -Size: 48 - -Alignment: 8 - -### Variant Layout -- size: 48 -- align: 8 -- tag_size: 1 -### Variant cases -- `clock`: [`subscription_clock`](#subscription_clock) - -- `fd_read`: [`subscription_fd_readwrite`](#subscription_fd_readwrite) - -- `fd_write`: [`subscription_fd_readwrite`](#subscription_fd_readwrite) - -## `subscription`: `Record` -Subscription to an event. - -Size: 56 - -Alignment: 8 - -### Record members -- `userdata`: [`userdata`](#userdata) -User-provided value that is attached to the subscription in the -implementation and returned through [`event::userdata`](#event.userdata). - -Offset: 0 - -- `u`: [`subscription_u`](#subscription_u) -The type of the event to which to subscribe. - -Offset: 8 - -## `exitcode`: `u32` -Exit code generated by a process when exiting. - -Size: 4 - -Alignment: 4 - -## `signal`: `Variant` -Signal condition. - -Size: 1 - -Alignment: 1 - -### Variant cases -- `none` -No signal. Note that POSIX has special semantics for `kill(pid, 0)`, -so this value is reserved. - -- `hup` -Hangup. -Action: Terminates the process. - -- `int` -Terminate interrupt signal. -Action: Terminates the process. - -- `quit` -Terminal quit signal. -Action: Terminates the process. - -- `ill` -Illegal instruction. -Action: Terminates the process. - -- `trap` -Trace/breakpoint trap. -Action: Terminates the process. - -- `abrt` -Process abort signal. -Action: Terminates the process. - -- `bus` -Access to an undefined portion of a memory object. -Action: Terminates the process. - -- `fpe` -Erroneous arithmetic operation. -Action: Terminates the process. - -- `kill` -Kill. -Action: Terminates the process. - -- `usr1` -User-defined signal 1. -Action: Terminates the process. - -- `segv` -Invalid memory reference. -Action: Terminates the process. - -- `usr2` -User-defined signal 2. -Action: Terminates the process. - -- `pipe` -Write on a pipe with no one to read it. -Action: Ignored. - -- `alrm` -Alarm clock. -Action: Terminates the process. - -- `term` -Termination signal. -Action: Terminates the process. - -- `chld` -Child process terminated, stopped, or continued. -Action: Ignored. - -- `cont` -Continue executing, if stopped. -Action: Continues executing, if stopped. - -- `stop` -Stop executing. -Action: Stops executing. - -- `tstp` -Terminal stop signal. -Action: Stops executing. - -- `ttin` -Background process attempting read. -Action: Stops executing. - -- `ttou` -Background process attempting write. -Action: Stops executing. - -- `urg` -High bandwidth data is available at a socket. -Action: Ignored. - -- `xcpu` -CPU time limit exceeded. -Action: Terminates the process. - -- `xfsz` -File size limit exceeded. -Action: Terminates the process. - -- `vtalrm` -Virtual timer expired. -Action: Terminates the process. - -- `prof` -Profiling timer expired. -Action: Terminates the process. - -- `winch` -Window changed. -Action: Ignored. - -- `poll` -I/O possible. -Action: Terminates the process. - -- `pwr` -Power failure. -Action: Terminates the process. - -- `sys` -Bad system call. -Action: Terminates the process. - -## `riflags`: `Record` -Flags provided to [`sock_recv`](#sock_recv). - -Size: 2 - -Alignment: 2 - -### Record members -- `recv_peek`: `bool` -Returns the message without removing it from the socket's receive queue. - -Bit: 0 - -- `recv_waitall`: `bool` -On byte-stream sockets, block until the full amount of data can be returned. - -Bit: 1 - -## `roflags`: `Record` -Flags returned by [`sock_recv`](#sock_recv). - -Size: 2 - -Alignment: 2 - -### Record members -- `recv_data_truncated`: `bool` -Returned by [`sock_recv`](#sock_recv): Message data has been truncated. - -Bit: 0 - -## `siflags`: `u16` -Flags provided to [`sock_send`](#sock_send). As there are currently no flags -defined, it must be set to zero. - -Size: 2 - -Alignment: 2 - -## `sdflags`: `Record` -Which channels on a socket to shut down. - -Size: 1 - -Alignment: 1 - -### Record members -- `rd`: `bool` -Disables further receive operations. - -Bit: 0 - -- `wr`: `bool` -Disables further send operations. - -Bit: 1 - -## `preopentype`: `Variant` -Identifiers for preopened capabilities. - -Size: 1 - -Alignment: 1 - -### Variant cases -- `dir` -A pre-opened directory. - -## `prestat_dir`: `Record` -The contents of a $prestat when type is [`preopentype::dir`](#preopentype.dir). - -Size: 4 - -Alignment: 4 - -### Record members -- `pr_name_len`: [`size`](#size) -The length of the directory name for use with [`fd_prestat_dir_name`](#fd_prestat_dir_name). - -Offset: 0 - -## `prestat`: `Variant` -Information about a pre-opened capability. - -Size: 8 - -Alignment: 4 - -### Variant Layout -- size: 8 -- align: 4 -- tag_size: 1 -### Variant cases -- `dir`: [`prestat_dir`](#prestat_dir) - -# Modules -## wasi_unstable -### Imports -#### Memory -### Functions - ---- - -#### `args_get(argv: Pointer>, argv_buf: Pointer) -> Result<(), errno>` -Read command-line argument data. -The size of the array should match that returned by [`args_sizes_get`](#args_sizes_get). -Each argument is expected to be `\0` terminated. - -##### Params -- `argv`: `Pointer>` - -- `argv_buf`: `Pointer` - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `args_sizes_get() -> Result<(size, size), errno>` -Return command-line argument data sizes. - -##### Params -##### Results -- `error`: `Result<(size, size), errno>` -Returns the number of arguments and the size of the argument string -data, or an error. - -###### Variant Layout -- size: 12 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: `(size, size)` - -####### Record members -- `0`: [`size`](#size) - -Offset: 0 - -- `1`: [`size`](#size) - -Offset: 4 - -- `err`: [`errno`](#errno) - - ---- - -#### `environ_get(environ: Pointer>, environ_buf: Pointer) -> Result<(), errno>` -Read environment variable data. -The sizes of the buffers should match that returned by [`environ_sizes_get`](#environ_sizes_get). -Key/value pairs are expected to be joined with `=`s, and terminated with `\0`s. - -##### Params -- `environ`: `Pointer>` - -- `environ_buf`: `Pointer` - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `environ_sizes_get() -> Result<(size, size), errno>` -Return environment variable data sizes. - -##### Params -##### Results -- `error`: `Result<(size, size), errno>` -Returns the number of environment variable arguments and the size of the -environment variable data. - -###### Variant Layout -- size: 12 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: `(size, size)` - -####### Record members -- `0`: [`size`](#size) - -Offset: 0 - -- `1`: [`size`](#size) - -Offset: 4 - -- `err`: [`errno`](#errno) - - ---- - -#### `clock_res_get(id: clockid) -> Result` -Return the resolution of a clock. -Implementations are required to provide a non-zero value for supported clocks. For unsupported clocks, return -[`errno::inval`](#errno.inval). -Note: This is similar to `clock_getres` in POSIX. - -##### Params -- `id`: [`clockid`](#clockid) -The clock for which to return the resolution. - -##### Results -- `error`: `Result` -The resolution of the clock, or an error if one happened. - -###### Variant Layout -- size: 16 -- align: 8 -- tag_size: 4 -###### Variant cases -- `ok`: [`timestamp`](#timestamp) - -- `err`: [`errno`](#errno) - - ---- - -#### `clock_time_get(id: clockid, precision: timestamp) -> Result` -Return the time value of a clock. -Note: This is similar to `clock_gettime` in POSIX. - -##### Params -- `id`: [`clockid`](#clockid) -The clock for which to return the time. - -- `precision`: [`timestamp`](#timestamp) -The maximum lag (exclusive) that the returned time value may have, compared to its actual value. - -##### Results -- `error`: `Result` -The time value of the clock. - -###### Variant Layout -- size: 16 -- align: 8 -- tag_size: 4 -###### Variant cases -- `ok`: [`timestamp`](#timestamp) - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_advise(fd: fd, offset: filesize, len: filesize, advice: advice) -> Result<(), errno>` -Provide file advisory information on a file descriptor. -Note: This is similar to `posix_fadvise` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `offset`: [`filesize`](#filesize) -The offset within the file to which the advisory applies. - -- `len`: [`filesize`](#filesize) -The length of the region to which the advisory applies. - -- `advice`: [`advice`](#advice) -The advice. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_allocate(fd: fd, offset: filesize, len: filesize) -> Result<(), errno>` -Force the allocation of space in a file. -Note: This is similar to `posix_fallocate` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `offset`: [`filesize`](#filesize) -The offset at which to start the allocation. - -- `len`: [`filesize`](#filesize) -The length of the area that is allocated. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_close(fd: fd) -> Result<(), errno>` -Close a file descriptor. -Note: This is similar to `close` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_datasync(fd: fd) -> Result<(), errno>` -Synchronize the data of a file to disk. -Note: This is similar to `fdatasync` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_fdstat_get(fd: fd) -> Result` -Get the attributes of a file descriptor. -Note: This returns similar flags to `fsync(fd, F_GETFL)` in POSIX, as well as additional fields. - -##### Params -- `fd`: [`fd`](#fd) - -##### Results -- `error`: `Result` -The buffer where the file descriptor's attributes are stored. - -###### Variant Layout -- size: 32 -- align: 8 -- tag_size: 4 -###### Variant cases -- `ok`: [`fdstat`](#fdstat) - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_fdstat_set_flags(fd: fd, flags: fdflags) -> Result<(), errno>` -Adjust the flags associated with a file descriptor. -Note: This is similar to `fcntl(fd, F_SETFL, flags)` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `flags`: [`fdflags`](#fdflags) -The desired values of the file descriptor flags. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_fdstat_set_rights(fd: fd, fs_rights_base: rights, fs_rights_inheriting: rights) -> Result<(), errno>` -Adjust the rights associated with a file descriptor. -This can only be used to remove rights, and returns [`errno::notcapable`](#errno.notcapable) if called in a way that would attempt to add rights - -##### Params -- `fd`: [`fd`](#fd) - -- `fs_rights_base`: [`rights`](#rights) -The desired rights of the file descriptor. - -- `fs_rights_inheriting`: [`rights`](#rights) - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_filestat_get(fd: fd) -> Result` -Return the attributes of an open file. - -##### Params -- `fd`: [`fd`](#fd) - -##### Results -- `error`: `Result` -The buffer where the file's attributes are stored. - -###### Variant Layout -- size: 64 -- align: 8 -- tag_size: 4 -###### Variant cases -- `ok`: [`filestat`](#filestat) - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_filestat_set_size(fd: fd, size: filesize) -> Result<(), errno>` -Adjust the size of an open file. If this increases the file's size, the extra bytes are filled with zeros. -Note: This is similar to `ftruncate` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `size`: [`filesize`](#filesize) -The desired file size. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_filestat_set_times(fd: fd, atim: timestamp, mtim: timestamp, fst_flags: fstflags) -> Result<(), errno>` -Adjust the timestamps of an open file or directory. -Note: This is similar to `futimens` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `atim`: [`timestamp`](#timestamp) -The desired values of the data access timestamp. - -- `mtim`: [`timestamp`](#timestamp) -The desired values of the data modification timestamp. - -- `fst_flags`: [`fstflags`](#fstflags) -A bitmask indicating which timestamps to adjust. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_pread(fd: fd, iovs: iovec_array, offset: filesize) -> Result` -Read from a file descriptor, without using and updating the file descriptor's offset. -Note: This is similar to `preadv` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `iovs`: [`iovec_array`](#iovec_array) -List of scatter/gather vectors in which to store data. - -- `offset`: [`filesize`](#filesize) -The offset within the file at which to read. - -##### Results -- `error`: `Result` -The number of bytes read. - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`size`](#size) - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_prestat_get(fd: fd) -> Result` -Return a description of the given preopened file descriptor. - -##### Params -- `fd`: [`fd`](#fd) - -##### Results -- `error`: `Result` -The buffer where the description is stored. - -###### Variant Layout -- size: 12 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`prestat`](#prestat) - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_prestat_dir_name(fd: fd, path: Pointer, path_len: size) -> Result<(), errno>` -Return a description of the given preopened file descriptor. - -##### Params -- `fd`: [`fd`](#fd) - -- `path`: `Pointer` -A buffer into which to write the preopened directory name. - -- `path_len`: [`size`](#size) - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_pwrite(fd: fd, iovs: ciovec_array, offset: filesize) -> Result` -Write to a file descriptor, without using and updating the file descriptor's offset. -Note: This is similar to `pwritev` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `iovs`: [`ciovec_array`](#ciovec_array) -List of scatter/gather vectors from which to retrieve data. - -- `offset`: [`filesize`](#filesize) -The offset within the file at which to write. - -##### Results -- `error`: `Result` -The number of bytes written. - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`size`](#size) - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_read(fd: fd, iovs: iovec_array) -> Result` -Read from a file descriptor. -Note: This is similar to `readv` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `iovs`: [`iovec_array`](#iovec_array) -List of scatter/gather vectors to which to store data. - -##### Results -- `error`: `Result` -The number of bytes read. - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`size`](#size) - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_readdir(fd: fd, buf: Pointer, buf_len: size, cookie: dircookie) -> Result` -Read directory entries from a directory. -When successful, the contents of the output buffer consist of a sequence of -directory entries. Each directory entry consists of a [`dirent`](#dirent) object, -followed by [`dirent::d_namlen`](#dirent.d_namlen) bytes holding the name of the directory -entry. -This function fills the output buffer as much as possible, potentially -truncating the last directory entry. This allows the caller to grow its -read buffer size in case it's too small to fit a single large directory -entry, or skip the oversized directory entry. - -##### Params -- `fd`: [`fd`](#fd) - -- `buf`: `Pointer` -The buffer where directory entries are stored - -- `buf_len`: [`size`](#size) - -- `cookie`: [`dircookie`](#dircookie) -The location within the directory to start reading - -##### Results -- `error`: `Result` -The number of bytes stored in the read buffer. If less than the size of the read buffer, the end of the directory has been reached. - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`size`](#size) - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_renumber(fd: fd, to: fd) -> Result<(), errno>` -Atomically replace a file descriptor by renumbering another file descriptor. -Due to the strong focus on thread safety, this environment does not provide -a mechanism to duplicate or renumber a file descriptor to an arbitrary -number, like `dup2()`. This would be prone to race conditions, as an actual -file descriptor with the same number could be allocated by a different -thread at the same time. -This function provides a way to atomically renumber file descriptors, which -would disappear if `dup2()` were to be removed entirely. - -##### Params -- `fd`: [`fd`](#fd) - -- `to`: [`fd`](#fd) -The file descriptor to overwrite. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_seek(fd: fd, offset: filedelta, whence: whence) -> Result` -Move the offset of a file descriptor. -Note: This is similar to `lseek` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `offset`: [`filedelta`](#filedelta) -The number of bytes to move. - -- `whence`: [`whence`](#whence) -The base from which the offset is relative. - -##### Results -- `error`: `Result` -The new offset of the file descriptor, relative to the start of the file. - -###### Variant Layout -- size: 16 -- align: 8 -- tag_size: 4 -###### Variant cases -- `ok`: [`filesize`](#filesize) - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_sync(fd: fd) -> Result<(), errno>` -Synchronize the data and metadata of a file to disk. -Note: This is similar to `fsync` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_tell(fd: fd) -> Result` -Return the current offset of a file descriptor. -Note: This is similar to `lseek(fd, 0, SEEK_CUR)` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -##### Results -- `error`: `Result` -The current offset of the file descriptor, relative to the start of the file. - -###### Variant Layout -- size: 16 -- align: 8 -- tag_size: 4 -###### Variant cases -- `ok`: [`filesize`](#filesize) - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_write(fd: fd, iovs: ciovec_array) -> Result` -Write to a file descriptor. -Note: This is similar to `writev` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `iovs`: [`ciovec_array`](#ciovec_array) -List of scatter/gather vectors from which to retrieve data. - -##### Results -- `error`: `Result` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`size`](#size) - -- `err`: [`errno`](#errno) - - ---- - -#### `path_create_directory(fd: fd, path: string) -> Result<(), errno>` -Create a directory. -Note: This is similar to `mkdirat` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `path`: `string` -The path at which to create the directory. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `path_filestat_get(fd: fd, flags: lookupflags, path: string) -> Result` -Return the attributes of a file or directory. -Note: This is similar to `stat` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `flags`: [`lookupflags`](#lookupflags) -Flags determining the method of how the path is resolved. - -- `path`: `string` -The path of the file or directory to inspect. - -##### Results -- `error`: `Result` -The buffer where the file's attributes are stored. - -###### Variant Layout -- size: 64 -- align: 8 -- tag_size: 4 -###### Variant cases -- `ok`: [`filestat`](#filestat) - -- `err`: [`errno`](#errno) - - ---- - -#### `path_filestat_set_times(fd: fd, flags: lookupflags, path: string, atim: timestamp, mtim: timestamp, fst_flags: fstflags) -> Result<(), errno>` -Adjust the timestamps of a file or directory. -Note: This is similar to `utimensat` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `flags`: [`lookupflags`](#lookupflags) -Flags determining the method of how the path is resolved. - -- `path`: `string` -The path of the file or directory to operate on. - -- `atim`: [`timestamp`](#timestamp) -The desired values of the data access timestamp. - -- `mtim`: [`timestamp`](#timestamp) -The desired values of the data modification timestamp. - -- `fst_flags`: [`fstflags`](#fstflags) -A bitmask indicating which timestamps to adjust. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `path_link(old_fd: fd, old_flags: lookupflags, old_path: string, new_fd: fd, new_path: string) -> Result<(), errno>` -Create a hard link. -Note: This is similar to `linkat` in POSIX. - -##### Params -- `old_fd`: [`fd`](#fd) - -- `old_flags`: [`lookupflags`](#lookupflags) -Flags determining the method of how the path is resolved. - -- `old_path`: `string` -The source path from which to link. - -- `new_fd`: [`fd`](#fd) -The working directory at which the resolution of the new path starts. - -- `new_path`: `string` -The destination path at which to create the hard link. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `path_open(fd: fd, dirflags: lookupflags, path: string, oflags: oflags, fs_rights_base: rights, fs_rights_inheriting: rights, fdflags: fdflags) -> Result` -Open a file or directory. -The returned file descriptor is not guaranteed to be the lowest-numbered -file descriptor not currently open; it is randomized to prevent -applications from depending on making assumptions about indexes, since this -is error-prone in multi-threaded contexts. The returned file descriptor is -guaranteed to be less than 2**31. -Note: This is similar to `openat` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `dirflags`: [`lookupflags`](#lookupflags) -Flags determining the method of how the path is resolved. - -- `path`: `string` -The relative path of the file or directory to open, relative to the -[`path_open::fd`](#path_open.fd) directory. - -- `oflags`: [`oflags`](#oflags) -The method by which to open the file. - -- `fs_rights_base`: [`rights`](#rights) -The initial rights of the newly created file descriptor. The -implementation is allowed to return a file descriptor with fewer rights -than specified, if and only if those rights do not apply to the type of -file being opened. -The *base* rights are rights that will apply to operations using the file -descriptor itself, while the *inheriting* rights are rights that apply to -file descriptors derived from it. - -- `fs_rights_inheriting`: [`rights`](#rights) - -- `fdflags`: [`fdflags`](#fdflags) - -##### Results -- `error`: `Result` -The file descriptor of the file that has been opened. - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`fd`](#fd) - -- `err`: [`errno`](#errno) - - ---- - -#### `path_readlink(fd: fd, path: string, buf: Pointer, buf_len: size) -> Result` -Read the contents of a symbolic link. -Note: This is similar to `readlinkat` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `path`: `string` -The path of the symbolic link from which to read. - -- `buf`: `Pointer` -The buffer to which to write the contents of the symbolic link. - -- `buf_len`: [`size`](#size) - -##### Results -- `error`: `Result` -The number of bytes placed in the buffer. - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`size`](#size) - -- `err`: [`errno`](#errno) - - ---- - -#### `path_remove_directory(fd: fd, path: string) -> Result<(), errno>` -Remove a directory. -Return [`errno::notempty`](#errno.notempty) if the directory is not empty. -Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `path`: `string` -The path to a directory to remove. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `path_rename(fd: fd, old_path: string, new_fd: fd, new_path: string) -> Result<(), errno>` -Rename a file or directory. -Note: This is similar to `renameat` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `old_path`: `string` -The source path of the file or directory to rename. - -- `new_fd`: [`fd`](#fd) -The working directory at which the resolution of the new path starts. - -- `new_path`: `string` -The destination path to which to rename the file or directory. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `path_symlink(old_path: string, fd: fd, new_path: string) -> Result<(), errno>` -Create a symbolic link. -Note: This is similar to `symlinkat` in POSIX. - -##### Params -- `old_path`: `string` -The contents of the symbolic link. - -- `fd`: [`fd`](#fd) - -- `new_path`: `string` -The destination path at which to create the symbolic link. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `path_unlink_file(fd: fd, path: string) -> Result<(), errno>` -Unlink a file. -Return [`errno::isdir`](#errno.isdir) if the path refers to a directory. -Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `path`: `string` -The path to a file to unlink. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `poll_oneoff(in: ConstPointer, out: Pointer, nsubscriptions: size) -> Result` -Concurrently poll for the occurrence of a set of events. - -##### Params -- `in`: `ConstPointer` -The events to which to subscribe. - -- `out`: `Pointer` -The events that have occurred. - -- `nsubscriptions`: [`size`](#size) -Both the number of subscriptions and events. - -##### Results -- `error`: `Result` -The number of events stored. - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`size`](#size) - -- `err`: [`errno`](#errno) - - ---- - -#### `proc_exit(rval: exitcode)` -Terminate the process normally. An exit code of 0 indicates successful -termination of the program. The meanings of other values is dependent on -the environment. - -##### Params -- `rval`: [`exitcode`](#exitcode) -The exit code returned by the process. - -##### Results - ---- - -#### `proc_raise(sig: signal) -> Result<(), errno>` -Send a signal to the process of the calling thread. -Note: This is similar to `raise` in POSIX. - -##### Params -- `sig`: [`signal`](#signal) -The signal condition to trigger. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `sched_yield() -> Result<(), errno>` -Temporarily yield execution of the calling thread. -Note: This is similar to [`sched_yield`](#sched_yield) in POSIX. - -##### Params -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `random_get(buf: Pointer, buf_len: size) -> Result<(), errno>` -Write high-quality random data into a buffer. -This function blocks when the implementation is unable to immediately -provide sufficient high-quality random data. - -##### Params -- `buf`: `Pointer` -The buffer to fill with random data. - -- `buf_len`: [`size`](#size) - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `sock_recv(fd: fd, ri_data: iovec_array, ri_flags: riflags) -> Result<(size, roflags), errno>` -Receive a message from a socket. -Note: This is similar to `recv` in POSIX, though it also supports reading -the data into multiple buffers in the manner of `readv`. - -##### Params -- `fd`: [`fd`](#fd) - -- `ri_data`: [`iovec_array`](#iovec_array) -List of scatter/gather vectors to which to store data. - -- `ri_flags`: [`riflags`](#riflags) -Message flags. - -##### Results -- `error`: `Result<(size, roflags), errno>` -Number of bytes stored in ri_data and message flags. - -###### Variant Layout -- size: 12 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: `(size, roflags)` - -####### Record members -- `0`: [`size`](#size) - -Offset: 0 - -- `1`: [`roflags`](#roflags) - -Offset: 4 - -- `err`: [`errno`](#errno) - - ---- - -#### `sock_send(fd: fd, si_data: ciovec_array, si_flags: siflags) -> Result` -Send a message on a socket. -Note: This is similar to `send` in POSIX, though it also supports writing -the data from multiple buffers in the manner of `writev`. - -##### Params -- `fd`: [`fd`](#fd) - -- `si_data`: [`ciovec_array`](#ciovec_array) -List of scatter/gather vectors to which to retrieve data - -- `si_flags`: [`siflags`](#siflags) -Message flags. - -##### Results -- `error`: `Result` -Number of bytes transmitted. - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`size`](#size) - -- `err`: [`errno`](#errno) - - ---- - -#### `sock_shutdown(fd: fd, how: sdflags) -> Result<(), errno>` -Shut down socket send and receive channels. -Note: This is similar to `shutdown` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `how`: [`sdflags`](#sdflags) -Which channels on the socket to shut down. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - diff --git a/legacy/preview0/witx/typenames.witx b/legacy/preview0/witx/typenames.witx deleted file mode 100644 index 0d277426c..000000000 --- a/legacy/preview0/witx/typenames.witx +++ /dev/null @@ -1,746 +0,0 @@ -;; Type names used by low-level WASI interfaces. -;; -;; Some content here is derived from [CloudABI](https://github.com/NuxiNL/cloudabi). -;; -;; This is a `witx` file. See [here](https://github.com/WebAssembly/WASI/blob/main/legacy/tools/witx-docs.md) -;; for an explanation of what that means. - -(typename $size u32) - -;;; Non-negative file size or length of a region within a file. -(typename $filesize u64) - -;;; Timestamp in nanoseconds. -(typename $timestamp u64) - -;;; Identifiers for clocks. -(typename $clockid - (enum (@witx tag u32) - ;;; The clock measuring real time. Time value zero corresponds with - ;;; 1970-01-01T00:00:00Z. - $realtime - ;;; The store-wide monotonic clock, which is defined as a clock measuring - ;;; real time, whose value cannot be adjusted and which cannot have negative - ;;; clock jumps. The epoch of this clock is undefined. The absolute time - ;;; value of this clock therefore has no meaning. - $monotonic - ;;; The CPU-time clock associated with the current process. - $process_cputime_id - ;;; The CPU-time clock associated with the current thread. - $thread_cputime_id - ) -) - -;;; Error codes returned by functions. -;;; Not all of these error codes are returned by the functions provided by this -;;; API; some are used in higher-level library layers, and others are provided -;;; merely for alignment with POSIX. -(typename $errno - (enum (@witx tag u16) - ;;; No error occurred. System call completed successfully. - $success - ;;; Argument list too long. - $2big - ;;; Permission denied. - $acces - ;;; Address in use. - $addrinuse - ;;; Address not available. - $addrnotavail - ;;; Address family not supported. - $afnosupport - ;;; Resource unavailable, or operation would block. - $again - ;;; Connection already in progress. - $already - ;;; Bad file descriptor. - $badf - ;;; Bad message. - $badmsg - ;;; Device or resource busy. - $busy - ;;; Operation canceled. - $canceled - ;;; No child processes. - $child - ;;; Connection aborted. - $connaborted - ;;; Connection refused. - $connrefused - ;;; Connection reset. - $connreset - ;;; Resource deadlock would occur. - $deadlk - ;;; Destination address required. - $destaddrreq - ;;; Mathematics argument out of domain of function. - $dom - ;;; Reserved. - $dquot - ;;; File exists. - $exist - ;;; Bad address. - $fault - ;;; File too large. - $fbig - ;;; Host is unreachable. - $hostunreach - ;;; Identifier removed. - $idrm - ;;; Illegal byte sequence. - $ilseq - ;;; Operation in progress. - $inprogress - ;;; Interrupted function. - $intr - ;;; Invalid argument. - $inval - ;;; I/O error. - $io - ;;; Socket is connected. - $isconn - ;;; Is a directory. - $isdir - ;;; Too many levels of symbolic links. - $loop - ;;; File descriptor value too large. - $mfile - ;;; Too many links. - $mlink - ;;; Message too large. - $msgsize - ;;; Reserved. - $multihop - ;;; Filename too long. - $nametoolong - ;;; Network is down. - $netdown - ;;; Connection aborted by network. - $netreset - ;;; Network unreachable. - $netunreach - ;;; Too many files open in system. - $nfile - ;;; No buffer space available. - $nobufs - ;;; No such device. - $nodev - ;;; No such file or directory. - $noent - ;;; Executable file format error. - $noexec - ;;; No locks available. - $nolck - ;;; Reserved. - $nolink - ;;; Not enough space. - $nomem - ;;; No message of the desired type. - $nomsg - ;;; Protocol not available. - $noprotoopt - ;;; No space left on device. - $nospc - ;;; Function not supported. - $nosys - ;;; The socket is not connected. - $notconn - ;;; Not a directory or a symbolic link to a directory. - $notdir - ;;; Directory not empty. - $notempty - ;;; State not recoverable. - $notrecoverable - ;;; Not a socket. - $notsock - ;;; Not supported, or operation not supported on socket. - $notsup - ;;; Inappropriate I/O control operation. - $notty - ;;; No such device or address. - $nxio - ;;; Value too large to be stored in data type. - $overflow - ;;; Previous owner died. - $ownerdead - ;;; Operation not permitted. - $perm - ;;; Broken pipe. - $pipe - ;;; Protocol error. - $proto - ;;; Protocol not supported. - $protonosupport - ;;; Protocol wrong type for socket. - $prototype - ;;; Result too large. - $range - ;;; Read-only file system. - $rofs - ;;; Invalid seek. - $spipe - ;;; No such process. - $srch - ;;; Reserved. - $stale - ;;; Connection timed out. - $timedout - ;;; Text file busy. - $txtbsy - ;;; Cross-device link. - $xdev - ;;; Extension: Capabilities insufficient. - $notcapable - ) -) - -;;; File descriptor rights, determining which actions may be performed. -(typename $rights - (flags (@witx repr u64) - ;;; The right to invoke `fd_datasync`. - ;; - ;;; If `rights::path_open` is set, includes the right to invoke - ;;; `path_open` with `fdflags::dsync`. - $fd_datasync - ;;; The right to invoke `fd_read` and `sock_recv`. - ;; - ;;; If `rights::fd_seek` is set, includes the right to invoke `fd_pread`. - $fd_read - ;;; The right to invoke `fd_seek`. This flag implies `rights::fd_tell`. - $fd_seek - ;;; The right to invoke `fd_fdstat_set_flags`. - $fd_fdstat_set_flags - ;;; The right to invoke `fd_sync`. - ;; - ;;; If `rights::path_open` is set, includes the right to invoke - ;;; `path_open` with `fdflags::rsync` and `fdflags::dsync`. - $fd_sync - ;;; The right to invoke `fd_seek` in such a way that the file offset - ;;; remains unaltered (i.e., `whence::cur` with offset zero), or to - ;;; invoke `fd_tell`. - $fd_tell - ;;; The right to invoke `fd_write` and `sock_send`. - ;;; If `rights::fd_seek` is set, includes the right to invoke `fd_pwrite`. - $fd_write - ;;; The right to invoke `fd_advise`. - $fd_advise - ;;; The right to invoke `fd_allocate`. - $fd_allocate - ;;; The right to invoke `path_create_directory`. - $path_create_directory - ;;; If `rights::path_open` is set, the right to invoke `path_open` with `oflags::creat`. - $path_create_file - ;;; The right to invoke `path_link` with the file descriptor as the - ;;; source directory. - $path_link_source - ;;; The right to invoke `path_link` with the file descriptor as the - ;;; target directory. - $path_link_target - ;;; The right to invoke `path_open`. - $path_open - ;;; The right to invoke `fd_readdir`. - $fd_readdir - ;;; The right to invoke `path_readlink`. - $path_readlink - ;;; The right to invoke `path_rename` with the file descriptor as the source directory. - $path_rename_source - ;;; The right to invoke `path_rename` with the file descriptor as the target directory. - $path_rename_target - ;;; The right to invoke `path_filestat_get`. - $path_filestat_get - ;;; The right to change a file's size (there is no `path_filestat_set_size`). - ;;; If `rights::path_open` is set, includes the right to invoke `path_open` with `oflags::trunc`. - $path_filestat_set_size - ;;; The right to invoke `path_filestat_set_times`. - $path_filestat_set_times - ;;; The right to invoke `fd_filestat_get`. - $fd_filestat_get - ;;; The right to invoke `fd_filestat_set_size`. - $fd_filestat_set_size - ;;; The right to invoke `fd_filestat_set_times`. - $fd_filestat_set_times - ;;; The right to invoke `path_symlink`. - $path_symlink - ;;; The right to invoke `path_remove_directory`. - $path_remove_directory - ;;; The right to invoke `path_unlink_file`. - $path_unlink_file - ;;; If `rights::fd_read` is set, includes the right to invoke `poll_oneoff` to subscribe to `eventtype::fd_read`. - ;;; If `rights::fd_write` is set, includes the right to invoke `poll_oneoff` to subscribe to `eventtype::fd_write`. - $poll_fd_readwrite - ;;; The right to invoke `sock_shutdown`. - $sock_shutdown - ) -) - -;;; A file descriptor handle. -(typename $fd (handle)) - -;;; A region of memory for scatter/gather reads. -(typename $iovec - (record - ;;; The address of the buffer to be filled. - (field $buf (@witx pointer u8)) - ;;; The length of the buffer to be filled. - (field $buf_len $size) - ) -) - -;;; A region of memory for scatter/gather writes. -(typename $ciovec - (record - ;;; The address of the buffer to be written. - (field $buf (@witx const_pointer u8)) - ;;; The length of the buffer to be written. - (field $buf_len $size) - ) -) - -(typename $iovec_array (list $iovec)) -(typename $ciovec_array (list $ciovec)) - -;;; Relative offset within a file. -(typename $filedelta s64) - -;;; The position relative to which to set the offset of the file descriptor. -(typename $whence - (enum (@witx tag u8) - ;;; Seek relative to current position. - $cur - ;;; Seek relative to end-of-file. - $end - ;;; Seek relative to start-of-file. - $set - ) -) - -;;; A reference to the offset of a directory entry. -(typename $dircookie u64) - -;;; The type for the `dirent::d_namlen` field of `dirent` struct. -(typename $dirnamlen u32) - -;;; File serial number that is unique within its file system. -(typename $inode u64) - -;;; The type of a file descriptor or file. -(typename $filetype - (enum (@witx tag u8) - ;;; The type of the file descriptor or file is unknown or is different from any of the other types specified. - $unknown - ;;; The file descriptor or file refers to a block device inode. - $block_device - ;;; The file descriptor or file refers to a character device inode. - $character_device - ;;; The file descriptor or file refers to a directory inode. - $directory - ;;; The file descriptor or file refers to a regular file inode. - $regular_file - ;;; The file descriptor or file refers to a datagram socket. - $socket_dgram - ;;; The file descriptor or file refers to a byte-stream socket. - $socket_stream - ;;; The file refers to a symbolic link inode. - $symbolic_link - ) -) - -;;; A directory entry. -(typename $dirent - (record - ;;; The offset of the next directory entry stored in this directory. - (field $d_next $dircookie) - ;;; The serial number of the file referred to by this directory entry. - (field $d_ino $inode) - ;;; The length of the name of the directory entry. - (field $d_namlen $dirnamlen) - ;;; The type of the file referred to by this directory entry. - (field $d_type $filetype) - ) -) - -;;; File or memory access pattern advisory information. -(typename $advice - (enum (@witx tag u8) - ;;; The application has no advice to give on its behavior with respect to the specified data. - $normal - ;;; The application expects to access the specified data sequentially from lower offsets to higher offsets. - $sequential - ;;; The application expects to access the specified data in a random order. - $random - ;;; The application expects to access the specified data in the near future. - $willneed - ;;; The application expects that it will not access the specified data in the near future. - $dontneed - ;;; The application expects to access the specified data once and then not reuse it thereafter. - $noreuse - ) -) - -;;; File descriptor flags. -(typename $fdflags - (flags (@witx repr u16) - ;;; Append mode: Data written to the file is always appended to the file's end. - $append - ;;; Write according to synchronized I/O data integrity completion. Only the data stored in the file is synchronized. - $dsync - ;;; Non-blocking mode. - $nonblock - ;;; Synchronized read I/O operations. - $rsync - ;;; Write according to synchronized I/O file integrity completion. In - ;;; addition to synchronizing the data stored in the file, the implementation - ;;; may also synchronously update the file's metadata. - $sync - ) -) - -;;; File descriptor attributes. -(typename $fdstat - (record - ;;; File type. - (field $fs_filetype $filetype) - ;;; File descriptor flags. - (field $fs_flags $fdflags) - ;;; Rights that apply to this file descriptor. - (field $fs_rights_base $rights) - ;;; Maximum set of rights that may be installed on new file descriptors that - ;;; are created through this file descriptor, e.g., through `path_open`. - (field $fs_rights_inheriting $rights) - ) -) - -;;; Identifier for a device containing a file system. Can be used in combination -;;; with `inode` to uniquely identify a file or directory in the filesystem. -(typename $device u64) - -;;; Which file time attributes to adjust. -(typename $fstflags - (flags (@witx repr u16) - ;;; Adjust the last data access timestamp to the value stored in `filestat::atim`. - $atim - ;;; Adjust the last data access timestamp to the time of clock `clockid::realtime`. - $atim_now - ;;; Adjust the last data modification timestamp to the value stored in `filestat::mtim`. - $mtim - ;;; Adjust the last data modification timestamp to the time of clock `clockid::realtime`. - $mtim_now - ) -) - -;;; Flags determining the method of how paths are resolved. -(typename $lookupflags - (flags (@witx repr u32) - ;;; As long as the resolved path corresponds to a symbolic link, it is expanded. - $symlink_follow - ) -) - -;;; Open flags used by `path_open`. -(typename $oflags - (flags (@witx repr u16) - ;;; Create file if it does not exist. - $creat - ;;; Fail if not a directory. - $directory - ;;; Fail if file already exists. - $excl - ;;; Truncate file to size 0. - $trunc - ) -) - -;;; Number of hard links to an inode. -(typename $linkcount u32) - -;;; File attributes. -(typename $filestat - (record - ;;; Device ID of device containing the file. - (field $dev $device) - ;;; File serial number. - (field $ino $inode) - ;;; File type. - (field $filetype $filetype) - ;;; Number of hard links to the file. - (field $nlink $linkcount) - ;;; For regular files, the file size in bytes. For symbolic links, the length in bytes of the pathname contained in the symbolic link. - (field $size $filesize) - ;;; Last data access timestamp. - (field $atim $timestamp) - ;;; Last data modification timestamp. - (field $mtim $timestamp) - ;;; Last file status change timestamp. - (field $ctim $timestamp) - ) -) - -;;; User-provided value that may be attached to objects that is retained when -;;; extracted from the implementation. -(typename $userdata u64) - -;;; Type of a subscription to an event or its occurrence. -(typename $eventtype - (enum (@witx tag u8) - ;;; The time value of clock `subscription_clock::id` has - ;;; reached timestamp `subscription_clock::timeout`. - $clock - ;;; File descriptor `subscription_fd_readwrite::file_descriptor` has data - ;;; available for reading. This event always triggers for regular files. - $fd_read - ;;; File descriptor `subscription_fd_readwrite::file_descriptor` has capacity - ;;; available for writing. This event always triggers for regular files. - $fd_write - ) -) - -;;; The state of the file descriptor subscribed to with -;;; `eventtype::fd_read` or `eventtype::fd_write`. -(typename $eventrwflags - (flags (@witx repr u16) - ;;; The peer of this socket has closed or disconnected. - $fd_readwrite_hangup - ) -) - -;;; The contents of an `event` for the `eventtype::fd_read` and -;;; `eventtype::fd_write` variants -(typename $event_fd_readwrite - (record - ;;; The number of bytes available for reading or writing. - (field $nbytes $filesize) - ;;; The state of the file descriptor. - (field $flags $eventrwflags) - ) -) - -;;; An event that occurred. -(typename $event - (record - ;;; User-provided value that got attached to `subscription::userdata`. - (field $userdata $userdata) - ;;; If non-zero, an error that occurred while processing the subscription request. - (field $error $errno) - ;;; The type of event that occurred - (field $type $eventtype) - ;;; The contents of the event, if it is an `eventtype::fd_read` or - ;;; `eventtype::fd_write`. `eventtype::clock` events ignore this field. - (field $fd_readwrite $event_fd_readwrite) - ) -) - -;;; Flags determining how to interpret the timestamp provided in -;;; `subscription_clock::timeout`. -(typename $subclockflags - (flags (@witx repr u16) - ;;; If set, treat the timestamp provided in - ;;; `subscription_clock::timeout` as an absolute timestamp of clock - ;;; `subscription_clock::id`. If clear, treat the timestamp - ;;; provided in `subscription_clock::timeout` relative to the - ;;; current time value of clock `subscription_clock::id`. - $subscription_clock_abstime - ) -) - -;;; The contents of a `subscription` when type is `eventtype::clock`. -(typename $subscription_clock - (record - ;;; The user-defined unique identifier of the clock. - (field $identifier $userdata) - ;;; The clock against which to compare the timestamp. - (field $id $clockid) - ;;; The absolute or relative timestamp. - (field $timeout $timestamp) - ;;; The amount of time that the implementation may wait additionally - ;;; to coalesce with other events. - (field $precision $timestamp) - ;;; Flags specifying whether the timeout is absolute or relative - (field $flags $subclockflags) - ) -) - -;;; The contents of a `subscription` when the variant is -;;; `eventtype::fd_read` or `eventtype::fd_write`. -(typename $subscription_fd_readwrite - (record - ;;; The file descriptor on which to wait for it to become ready for reading or writing. - (field $file_descriptor $fd) - ) -) - -;;; The contents of a `subscription`. -(typename $subscription_u - (union (@witx tag $eventtype) - $subscription_clock - $subscription_fd_readwrite - $subscription_fd_readwrite - ) -) - -;;; Subscription to an event. -(typename $subscription - (record - ;;; User-provided value that is attached to the subscription in the - ;;; implementation and returned through `event::userdata`. - (field $userdata $userdata) - ;;; The type of the event to which to subscribe. - (field $u $subscription_u) - ) -) - -;;; Exit code generated by a process when exiting. -(typename $exitcode u32) - -;;; Signal condition. -(typename $signal - (enum (@witx tag u8) - ;;; No signal. Note that POSIX has special semantics for `kill(pid, 0)`, - ;;; so this value is reserved. - $none - ;;; Hangup. - ;;; Action: Terminates the process. - $hup - ;;; Terminate interrupt signal. - ;;; Action: Terminates the process. - $int - ;;; Terminal quit signal. - ;;; Action: Terminates the process. - $quit - ;;; Illegal instruction. - ;;; Action: Terminates the process. - $ill - ;;; Trace/breakpoint trap. - ;;; Action: Terminates the process. - $trap - ;;; Process abort signal. - ;;; Action: Terminates the process. - $abrt - ;;; Access to an undefined portion of a memory object. - ;;; Action: Terminates the process. - $bus - ;;; Erroneous arithmetic operation. - ;;; Action: Terminates the process. - $fpe - ;;; Kill. - ;;; Action: Terminates the process. - $kill - ;;; User-defined signal 1. - ;;; Action: Terminates the process. - $usr1 - ;;; Invalid memory reference. - ;;; Action: Terminates the process. - $segv - ;;; User-defined signal 2. - ;;; Action: Terminates the process. - $usr2 - ;;; Write on a pipe with no one to read it. - ;;; Action: Ignored. - $pipe - ;;; Alarm clock. - ;;; Action: Terminates the process. - $alrm - ;;; Termination signal. - ;;; Action: Terminates the process. - $term - ;;; Child process terminated, stopped, or continued. - ;;; Action: Ignored. - $chld - ;;; Continue executing, if stopped. - ;;; Action: Continues executing, if stopped. - $cont - ;;; Stop executing. - ;;; Action: Stops executing. - $stop - ;;; Terminal stop signal. - ;;; Action: Stops executing. - $tstp - ;;; Background process attempting read. - ;;; Action: Stops executing. - $ttin - ;;; Background process attempting write. - ;;; Action: Stops executing. - $ttou - ;;; High bandwidth data is available at a socket. - ;;; Action: Ignored. - $urg - ;;; CPU time limit exceeded. - ;;; Action: Terminates the process. - $xcpu - ;;; File size limit exceeded. - ;;; Action: Terminates the process. - $xfsz - ;;; Virtual timer expired. - ;;; Action: Terminates the process. - $vtalrm - ;;; Profiling timer expired. - ;;; Action: Terminates the process. - $prof - ;;; Window changed. - ;;; Action: Ignored. - $winch - ;;; I/O possible. - ;;; Action: Terminates the process. - $poll - ;;; Power failure. - ;;; Action: Terminates the process. - $pwr - ;;; Bad system call. - ;;; Action: Terminates the process. - $sys - ) -) - -;;; Flags provided to `sock_recv`. -(typename $riflags - (flags (@witx repr u16) - ;;; Returns the message without removing it from the socket's receive queue. - $recv_peek - ;;; On byte-stream sockets, block until the full amount of data can be returned. - $recv_waitall - ) -) - -;;; Flags returned by `sock_recv`. -(typename $roflags - (flags (@witx repr u16) - ;;; Returned by `sock_recv`: Message data has been truncated. - $recv_data_truncated - ) -) - -;;; Flags provided to `sock_send`. As there are currently no flags -;;; defined, it must be set to zero. -(typename $siflags u16) - -;;; Which channels on a socket to shut down. -(typename $sdflags - (flags (@witx repr u8) - ;;; Disables further receive operations. - $rd - ;;; Disables further send operations. - $wr - ) -) - -;;; Identifiers for preopened capabilities. -(typename $preopentype - (enum (@witx tag u8) - ;;; A pre-opened directory. - $dir - ) -) - -;;; The contents of a $prestat when type is `preopentype::dir`. -(typename $prestat_dir - (record - ;;; The length of the directory name for use with `fd_prestat_dir_name`. - (field $pr_name_len $size) - ) -) - -;;; Information about a pre-opened capability. -(typename $prestat - (union (@witx tag $preopentype) - $prestat_dir - ) -) diff --git a/legacy/preview0/witx/wasi_unstable.witx b/legacy/preview0/witx/wasi_unstable.witx deleted file mode 100644 index 96f5953df..000000000 --- a/legacy/preview0/witx/wasi_unstable.witx +++ /dev/null @@ -1,510 +0,0 @@ -;; WASI Preview. This is an evolution of the API that WASI initially -;; launched with. -;; -;; Some content here is derived from [CloudABI](https://github.com/NuxiNL/cloudabi). -;; -;; This is a `witx` file. See [here](https://github.com/WebAssembly/WASI/blob/main/legacy/tools/witx-docs.md) -;; for an explanation of what that means. - -(use "typenames.witx") - -;;; This API predated the convention of naming modules with a `wasi_unstable_` -;;; prefix and a version number. It is preserved here for compatibility, but -;;; we shouldn't follow this pattern in new APIs. -(module $wasi_unstable - ;;; Linear memory to be accessed by WASI functions that need it. - (import "memory" (memory)) - - ;;; Read command-line argument data. - ;;; The size of the array should match that returned by `args_sizes_get`. - ;;; Each argument is expected to be `\0` terminated. - (@interface func (export "args_get") - (param $argv (@witx pointer (@witx pointer u8))) - (param $argv_buf (@witx pointer u8)) - (result $error (expected (error $errno))) - ) - ;;; Return command-line argument data sizes. - (@interface func (export "args_sizes_get") - ;;; Returns the number of arguments and the size of the argument string - ;;; data, or an error. - (result $error (expected (tuple $size $size) (error $errno))) - ) - - ;;; Read environment variable data. - ;;; The sizes of the buffers should match that returned by `environ_sizes_get`. - ;;; Key/value pairs are expected to be joined with `=`s, and terminated with `\0`s. - (@interface func (export "environ_get") - (param $environ (@witx pointer (@witx pointer u8))) - (param $environ_buf (@witx pointer u8)) - (result $error (expected (error $errno))) - ) - ;;; Return environment variable data sizes. - (@interface func (export "environ_sizes_get") - ;;; Returns the number of environment variable arguments and the size of the - ;;; environment variable data. - (result $error (expected (tuple $size $size) (error $errno))) - ) - - ;;; Return the resolution of a clock. - ;;; Implementations are required to provide a non-zero value for supported clocks. For unsupported clocks, return - ;;; `errno::inval`. - ;;; Note: This is similar to `clock_getres` in POSIX. - (@interface func (export "clock_res_get") - ;;; The clock for which to return the resolution. - (param $id $clockid) - ;;; The resolution of the clock, or an error if one happened. - (result $error (expected $timestamp (error $errno))) - ) - ;;; Return the time value of a clock. - ;;; Note: This is similar to `clock_gettime` in POSIX. - (@interface func (export "clock_time_get") - ;;; The clock for which to return the time. - (param $id $clockid) - ;;; The maximum lag (exclusive) that the returned time value may have, compared to its actual value. - (param $precision $timestamp) - ;;; The time value of the clock. - (result $error (expected $timestamp (error $errno))) - ) - - ;;; Provide file advisory information on a file descriptor. - ;;; Note: This is similar to `posix_fadvise` in POSIX. - (@interface func (export "fd_advise") - (param $fd $fd) - ;;; The offset within the file to which the advisory applies. - (param $offset $filesize) - ;;; The length of the region to which the advisory applies. - (param $len $filesize) - ;;; The advice. - (param $advice $advice) - (result $error (expected (error $errno))) - ) - - ;;; Force the allocation of space in a file. - ;;; Note: This is similar to `posix_fallocate` in POSIX. - (@interface func (export "fd_allocate") - (param $fd $fd) - ;;; The offset at which to start the allocation. - (param $offset $filesize) - ;;; The length of the area that is allocated. - (param $len $filesize) - (result $error (expected (error $errno))) - ) - - ;;; Close a file descriptor. - ;;; Note: This is similar to `close` in POSIX. - (@interface func (export "fd_close") - (param $fd $fd) - (result $error (expected (error $errno))) - ) - - ;;; Synchronize the data of a file to disk. - ;;; Note: This is similar to `fdatasync` in POSIX. - (@interface func (export "fd_datasync") - (param $fd $fd) - (result $error (expected (error $errno))) - ) - - ;;; Get the attributes of a file descriptor. - ;;; Note: This returns similar flags to `fsync(fd, F_GETFL)` in POSIX, as well as additional fields. - (@interface func (export "fd_fdstat_get") - (param $fd $fd) - ;;; The buffer where the file descriptor's attributes are stored. - (result $error (expected $fdstat (error $errno))) - ) - - ;;; Adjust the flags associated with a file descriptor. - ;;; Note: This is similar to `fcntl(fd, F_SETFL, flags)` in POSIX. - (@interface func (export "fd_fdstat_set_flags") - (param $fd $fd) - ;;; The desired values of the file descriptor flags. - (param $flags $fdflags) - (result $error (expected (error $errno))) - ) - - ;;; Adjust the rights associated with a file descriptor. - ;;; This can only be used to remove rights, and returns `errno::notcapable` if called in a way that would attempt to add rights - (@interface func (export "fd_fdstat_set_rights") - (param $fd $fd) - ;;; The desired rights of the file descriptor. - (param $fs_rights_base $rights) - (param $fs_rights_inheriting $rights) - (result $error (expected (error $errno))) - ) - - ;;; Return the attributes of an open file. - (@interface func (export "fd_filestat_get") - (param $fd $fd) - ;;; The buffer where the file's attributes are stored. - (result $error (expected $filestat (error $errno))) - ) - - ;;; Adjust the size of an open file. If this increases the file's size, the extra bytes are filled with zeros. - ;;; Note: This is similar to `ftruncate` in POSIX. - (@interface func (export "fd_filestat_set_size") - (param $fd $fd) - ;;; The desired file size. - (param $size $filesize) - (result $error (expected (error $errno))) - ) - - ;;; Adjust the timestamps of an open file or directory. - ;;; Note: This is similar to `futimens` in POSIX. - (@interface func (export "fd_filestat_set_times") - (param $fd $fd) - ;;; The desired values of the data access timestamp. - (param $atim $timestamp) - ;;; The desired values of the data modification timestamp. - (param $mtim $timestamp) - ;;; A bitmask indicating which timestamps to adjust. - (param $fst_flags $fstflags) - (result $error (expected (error $errno))) - ) - - ;;; Read from a file descriptor, without using and updating the file descriptor's offset. - ;;; Note: This is similar to `preadv` in POSIX. - (@interface func (export "fd_pread") - (param $fd $fd) - ;;; List of scatter/gather vectors in which to store data. - (param $iovs $iovec_array) - ;;; The offset within the file at which to read. - (param $offset $filesize) - ;;; The number of bytes read. - (result $error (expected $size (error $errno))) - ) - - ;;; Return a description of the given preopened file descriptor. - (@interface func (export "fd_prestat_get") - (param $fd $fd) - ;;; The buffer where the description is stored. - (result $error (expected $prestat (error $errno))) - ) - - ;;; Return a description of the given preopened file descriptor. - (@interface func (export "fd_prestat_dir_name") - (param $fd $fd) - ;;; A buffer into which to write the preopened directory name. - (param $path (@witx pointer u8)) - (param $path_len $size) - (result $error (expected (error $errno))) - ) - - ;;; Write to a file descriptor, without using and updating the file descriptor's offset. - ;;; Note: This is similar to `pwritev` in POSIX. - (@interface func (export "fd_pwrite") - (param $fd $fd) - ;;; List of scatter/gather vectors from which to retrieve data. - (param $iovs $ciovec_array) - ;;; The offset within the file at which to write. - (param $offset $filesize) - ;;; The number of bytes written. - (result $error (expected $size (error $errno))) - ) - - ;;; Read from a file descriptor. - ;;; Note: This is similar to `readv` in POSIX. - (@interface func (export "fd_read") - (param $fd $fd) - ;;; List of scatter/gather vectors to which to store data. - (param $iovs $iovec_array) - ;;; The number of bytes read. - (result $error (expected $size (error $errno))) - ) - - ;;; Read directory entries from a directory. - ;;; When successful, the contents of the output buffer consist of a sequence of - ;;; directory entries. Each directory entry consists of a `dirent` object, - ;;; followed by `dirent::d_namlen` bytes holding the name of the directory - ;;; entry. - ;; - ;;; This function fills the output buffer as much as possible, potentially - ;;; truncating the last directory entry. This allows the caller to grow its - ;;; read buffer size in case it's too small to fit a single large directory - ;;; entry, or skip the oversized directory entry. - (@interface func (export "fd_readdir") - (param $fd $fd) - ;;; The buffer where directory entries are stored - (param $buf (@witx pointer u8)) - (param $buf_len $size) - ;;; The location within the directory to start reading - (param $cookie $dircookie) - ;;; The number of bytes stored in the read buffer. If less than the size of the read buffer, the end of the directory has been reached. - (result $error (expected $size (error $errno))) - ) - - ;;; Atomically replace a file descriptor by renumbering another file descriptor. - ;; - ;;; Due to the strong focus on thread safety, this environment does not provide - ;;; a mechanism to duplicate or renumber a file descriptor to an arbitrary - ;;; number, like `dup2()`. This would be prone to race conditions, as an actual - ;;; file descriptor with the same number could be allocated by a different - ;;; thread at the same time. - ;; - ;;; This function provides a way to atomically renumber file descriptors, which - ;;; would disappear if `dup2()` were to be removed entirely. - (@interface func (export "fd_renumber") - (param $fd $fd) - ;;; The file descriptor to overwrite. - (param $to $fd) - (result $error (expected (error $errno))) - ) - - ;;; Move the offset of a file descriptor. - ;;; Note: This is similar to `lseek` in POSIX. - (@interface func (export "fd_seek") - (param $fd $fd) - ;;; The number of bytes to move. - (param $offset $filedelta) - ;;; The base from which the offset is relative. - (param $whence $whence) - ;;; The new offset of the file descriptor, relative to the start of the file. - (result $error (expected $filesize (error $errno))) - ) - - ;;; Synchronize the data and metadata of a file to disk. - ;;; Note: This is similar to `fsync` in POSIX. - (@interface func (export "fd_sync") - (param $fd $fd) - (result $error (expected (error $errno))) - ) - - ;;; Return the current offset of a file descriptor. - ;;; Note: This is similar to `lseek(fd, 0, SEEK_CUR)` in POSIX. - (@interface func (export "fd_tell") - (param $fd $fd) - ;;; The current offset of the file descriptor, relative to the start of the file. - (result $error (expected $filesize (error $errno))) - ) - - ;;; Write to a file descriptor. - ;;; Note: This is similar to `writev` in POSIX. - (@interface func (export "fd_write") - (param $fd $fd) - ;;; List of scatter/gather vectors from which to retrieve data. - (param $iovs $ciovec_array) - (result $error (expected $size (error $errno))) - ) - - ;;; Create a directory. - ;;; Note: This is similar to `mkdirat` in POSIX. - (@interface func (export "path_create_directory") - (param $fd $fd) - ;;; The path at which to create the directory. - (param $path string) - (result $error (expected (error $errno))) - ) - - ;;; Return the attributes of a file or directory. - ;;; Note: This is similar to `stat` in POSIX. - (@interface func (export "path_filestat_get") - (param $fd $fd) - ;;; Flags determining the method of how the path is resolved. - (param $flags $lookupflags) - ;;; The path of the file or directory to inspect. - (param $path string) - ;;; The buffer where the file's attributes are stored. - (result $error (expected $filestat (error $errno))) - ) - - ;;; Adjust the timestamps of a file or directory. - ;;; Note: This is similar to `utimensat` in POSIX. - (@interface func (export "path_filestat_set_times") - (param $fd $fd) - ;;; Flags determining the method of how the path is resolved. - (param $flags $lookupflags) - ;;; The path of the file or directory to operate on. - (param $path string) - ;;; The desired values of the data access timestamp. - (param $atim $timestamp) - ;;; The desired values of the data modification timestamp. - (param $mtim $timestamp) - ;;; A bitmask indicating which timestamps to adjust. - (param $fst_flags $fstflags) - (result $error (expected (error $errno))) - ) - - ;;; Create a hard link. - ;;; Note: This is similar to `linkat` in POSIX. - (@interface func (export "path_link") - (param $old_fd $fd) - ;;; Flags determining the method of how the path is resolved. - (param $old_flags $lookupflags) - ;;; The source path from which to link. - (param $old_path string) - ;;; The working directory at which the resolution of the new path starts. - (param $new_fd $fd) - ;;; The destination path at which to create the hard link. - (param $new_path string) - (result $error (expected (error $errno))) - ) - - ;;; Open a file or directory. - ;; - ;;; The returned file descriptor is not guaranteed to be the lowest-numbered - ;;; file descriptor not currently open; it is randomized to prevent - ;;; applications from depending on making assumptions about indexes, since this - ;;; is error-prone in multi-threaded contexts. The returned file descriptor is - ;;; guaranteed to be less than 2**31. - ;; - ;;; Note: This is similar to `openat` in POSIX. - (@interface func (export "path_open") - (param $fd $fd) - ;;; Flags determining the method of how the path is resolved. - (param $dirflags $lookupflags) - ;;; The relative path of the file or directory to open, relative to the - ;;; `path_open::fd` directory. - (param $path string) - ;;; The method by which to open the file. - (param $oflags $oflags) - ;;; The initial rights of the newly created file descriptor. The - ;;; implementation is allowed to return a file descriptor with fewer rights - ;;; than specified, if and only if those rights do not apply to the type of - ;;; file being opened. - ;; - ;;; The *base* rights are rights that will apply to operations using the file - ;;; descriptor itself, while the *inheriting* rights are rights that apply to - ;;; file descriptors derived from it. - (param $fs_rights_base $rights) - (param $fs_rights_inheriting $rights) - (param $fdflags $fdflags) - ;;; The file descriptor of the file that has been opened. - (result $error (expected $fd (error $errno))) - ) - - ;;; Read the contents of a symbolic link. - ;;; Note: This is similar to `readlinkat` in POSIX. - (@interface func (export "path_readlink") - (param $fd $fd) - ;;; The path of the symbolic link from which to read. - (param $path string) - ;;; The buffer to which to write the contents of the symbolic link. - (param $buf (@witx pointer u8)) - (param $buf_len $size) - ;;; The number of bytes placed in the buffer. - (result $error (expected $size (error $errno))) - ) - - ;;; Remove a directory. - ;;; Return `errno::notempty` if the directory is not empty. - ;;; Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. - (@interface func (export "path_remove_directory") - (param $fd $fd) - ;;; The path to a directory to remove. - (param $path string) - (result $error (expected (error $errno))) - ) - - ;;; Rename a file or directory. - ;;; Note: This is similar to `renameat` in POSIX. - (@interface func (export "path_rename") - (param $fd $fd) - ;;; The source path of the file or directory to rename. - (param $old_path string) - ;;; The working directory at which the resolution of the new path starts. - (param $new_fd $fd) - ;;; The destination path to which to rename the file or directory. - (param $new_path string) - (result $error (expected (error $errno))) - ) - - ;;; Create a symbolic link. - ;;; Note: This is similar to `symlinkat` in POSIX. - (@interface func (export "path_symlink") - ;;; The contents of the symbolic link. - (param $old_path string) - (param $fd $fd) - ;;; The destination path at which to create the symbolic link. - (param $new_path string) - (result $error (expected (error $errno))) - ) - - - ;;; Unlink a file. - ;;; Return `errno::isdir` if the path refers to a directory. - ;;; Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. - (@interface func (export "path_unlink_file") - (param $fd $fd) - ;;; The path to a file to unlink. - (param $path string) - (result $error (expected (error $errno))) - ) - - ;;; Concurrently poll for the occurrence of a set of events. - (@interface func (export "poll_oneoff") - ;;; The events to which to subscribe. - (param $in (@witx const_pointer $subscription)) - ;;; The events that have occurred. - (param $out (@witx pointer $event)) - ;;; Both the number of subscriptions and events. - (param $nsubscriptions $size) - ;;; The number of events stored. - (result $error (expected $size (error $errno))) - ) - - ;;; Terminate the process normally. An exit code of 0 indicates successful - ;;; termination of the program. The meanings of other values is dependent on - ;;; the environment. - (@interface func (export "proc_exit") - ;;; The exit code returned by the process. - (param $rval $exitcode) - (@witx noreturn) - ) - - ;;; Send a signal to the process of the calling thread. - ;;; Note: This is similar to `raise` in POSIX. - (@interface func (export "proc_raise") - ;;; The signal condition to trigger. - (param $sig $signal) - (result $error (expected (error $errno))) - ) - - ;;; Temporarily yield execution of the calling thread. - ;;; Note: This is similar to `sched_yield` in POSIX. - (@interface func (export "sched_yield") - (result $error (expected (error $errno))) - ) - - ;;; Write high-quality random data into a buffer. - ;;; This function blocks when the implementation is unable to immediately - ;;; provide sufficient high-quality random data. - (@interface func (export "random_get") - ;;; The buffer to fill with random data. - (param $buf (@witx pointer u8)) - (param $buf_len $size) - (result $error (expected (error $errno))) - ) - - ;;; Receive a message from a socket. - ;;; Note: This is similar to `recv` in POSIX, though it also supports reading - ;;; the data into multiple buffers in the manner of `readv`. - (@interface func (export "sock_recv") - (param $fd $fd) - ;;; List of scatter/gather vectors to which to store data. - (param $ri_data $iovec_array) - ;;; Message flags. - (param $ri_flags $riflags) - ;;; Number of bytes stored in ri_data and message flags. - (result $error (expected (tuple $size $roflags) (error $errno))) - ) - - ;;; Send a message on a socket. - ;;; Note: This is similar to `send` in POSIX, though it also supports writing - ;;; the data from multiple buffers in the manner of `writev`. - (@interface func (export "sock_send") - (param $fd $fd) - ;;; List of scatter/gather vectors to which to retrieve data - (param $si_data $ciovec_array) - ;;; Message flags. - (param $si_flags $siflags) - ;;; Number of bytes transmitted. - (result $error (expected $size (error $errno))) - ) - - ;;; Shut down socket send and receive channels. - ;;; Note: This is similar to `shutdown` in POSIX. - (@interface func (export "sock_shutdown") - (param $fd $fd) - ;;; Which channels on the socket to shut down. - (param $how $sdflags) - (result $error (expected (error $errno))) - ) -) diff --git a/legacy/preview1/docs.html b/legacy/preview1/docs.html deleted file mode 100644 index 8326504f3..000000000 --- a/legacy/preview1/docs.html +++ /dev/null @@ -1,1279 +0,0 @@ -

Types

-

<a href="#size" name="size"></a> size: u32

-

Size: 4
Alignment: 4

-

<a href="#filesize" name="filesize"></a> filesize: u64

-

Non-negative file size or length of a region within a file.
Size: 8
Alignment: 8

-

<a href="#timestamp" name="timestamp"></a> timestamp: u64

-

Timestamp in nanoseconds.
Size: 8
Alignment: 8

-

<a href="#clockid" name="clockid"></a> clockid: Enum(u32)

-

Identifiers for clocks.
Size: 4
Alignment: 4

-

Variants

-
    -
  • <a href="#clockid.realtime" name="clockid.realtime"></a> realtime
    The clock measuring real time. Time value zero corresponds with
    1970-01-01T00:00:00Z.

    -
  • -
  • <a href="#clockid.monotonic" name="clockid.monotonic"></a> monotonic
    The store-wide monotonic clock, which is defined as a clock measuring
    real time, whose value cannot be adjusted and which cannot have negative
    clock jumps. The epoch of this clock is undefined. The absolute time
    value of this clock therefore has no meaning.

    -
  • -
  • <a href="#clockid.process_cputime_id" name="clockid.process_cputime_id"></a> process_cputime_id
    The CPU-time clock associated with the current process.

    -
  • -
  • <a href="#clockid.thread_cputime_id" name="clockid.thread_cputime_id"></a> thread_cputime_id
    The CPU-time clock associated with the current thread.

    -
  • -
-

<a href="#errno" name="errno"></a> errno: Enum(u16)

-

Error codes returned by functions.
Not all of these error codes are returned by the functions provided by this
API; some are used in higher-level library layers, and others are provided
merely for alignment with POSIX.
Size: 2
Alignment: 2

-

Variants

-
    -
  • <a href="#errno.success" name="errno.success"></a> success
    No error occurred. System call completed successfully.

    -
  • -
  • <a href="#errno.2big" name="errno.2big"></a> 2big
    Argument list too long.

    -
  • -
  • <a href="#errno.acces" name="errno.acces"></a> acces
    Permission denied.

    -
  • -
  • <a href="#errno.addrinuse" name="errno.addrinuse"></a> addrinuse
    Address in use.

    -
  • -
  • <a href="#errno.addrnotavail" name="errno.addrnotavail"></a> addrnotavail
    Address not available.

    -
  • -
  • <a href="#errno.afnosupport" name="errno.afnosupport"></a> afnosupport
    Address family not supported.

    -
  • -
  • <a href="#errno.again" name="errno.again"></a> again
    Resource unavailable, or operation would block.

    -
  • -
  • <a href="#errno.already" name="errno.already"></a> already
    Connection already in progress.

    -
  • -
  • <a href="#errno.badf" name="errno.badf"></a> badf
    Bad file descriptor.

    -
  • -
  • <a href="#errno.badmsg" name="errno.badmsg"></a> badmsg
    Bad message.

    -
  • -
  • <a href="#errno.busy" name="errno.busy"></a> busy
    Device or resource busy.

    -
  • -
  • <a href="#errno.canceled" name="errno.canceled"></a> canceled
    Operation canceled.

    -
  • -
  • <a href="#errno.child" name="errno.child"></a> child
    No child processes.

    -
  • -
  • <a href="#errno.connaborted" name="errno.connaborted"></a> connaborted
    Connection aborted.

    -
  • -
  • <a href="#errno.connrefused" name="errno.connrefused"></a> connrefused
    Connection refused.

    -
  • -
  • <a href="#errno.connreset" name="errno.connreset"></a> connreset
    Connection reset.

    -
  • -
  • <a href="#errno.deadlk" name="errno.deadlk"></a> deadlk
    Resource deadlock would occur.

    -
  • -
  • <a href="#errno.destaddrreq" name="errno.destaddrreq"></a> destaddrreq
    Destination address required.

    -
  • -
  • <a href="#errno.dom" name="errno.dom"></a> dom
    Mathematics argument out of domain of function.

    -
  • -
  • <a href="#errno.dquot" name="errno.dquot"></a> dquot
    Reserved.

    -
  • -
  • <a href="#errno.exist" name="errno.exist"></a> exist
    File exists.

    -
  • -
  • <a href="#errno.fault" name="errno.fault"></a> fault
    Bad address.

    -
  • -
  • <a href="#errno.fbig" name="errno.fbig"></a> fbig
    File too large.

    -
  • -
  • <a href="#errno.hostunreach" name="errno.hostunreach"></a> hostunreach
    Host is unreachable.

    -
  • -
  • <a href="#errno.idrm" name="errno.idrm"></a> idrm
    Identifier removed.

    -
  • -
  • <a href="#errno.ilseq" name="errno.ilseq"></a> ilseq
    Illegal byte sequence.

    -
  • -
  • <a href="#errno.inprogress" name="errno.inprogress"></a> inprogress
    Operation in progress.

    -
  • -
  • <a href="#errno.intr" name="errno.intr"></a> intr
    Interrupted function.

    -
  • -
  • <a href="#errno.inval" name="errno.inval"></a> inval
    Invalid argument.

    -
  • -
  • <a href="#errno.io" name="errno.io"></a> io
    I/O error.

    -
  • -
  • <a href="#errno.isconn" name="errno.isconn"></a> isconn
    Socket is connected.

    -
  • -
  • <a href="#errno.isdir" name="errno.isdir"></a> isdir
    Is a directory.

    -
  • -
  • <a href="#errno.loop" name="errno.loop"></a> loop
    Too many levels of symbolic links.

    -
  • -
  • <a href="#errno.mfile" name="errno.mfile"></a> mfile
    File descriptor value too large.

    -
  • -
  • <a href="#errno.mlink" name="errno.mlink"></a> mlink
    Too many links.

    -
  • -
  • <a href="#errno.msgsize" name="errno.msgsize"></a> msgsize
    Message too large.

    -
  • -
  • <a href="#errno.multihop" name="errno.multihop"></a> multihop
    Reserved.

    -
  • -
  • <a href="#errno.nametoolong" name="errno.nametoolong"></a> nametoolong
    Filename too long.

    -
  • -
  • <a href="#errno.netdown" name="errno.netdown"></a> netdown
    Network is down.

    -
  • -
  • <a href="#errno.netreset" name="errno.netreset"></a> netreset
    Connection aborted by network.

    -
  • -
  • <a href="#errno.netunreach" name="errno.netunreach"></a> netunreach
    Network unreachable.

    -
  • -
  • <a href="#errno.nfile" name="errno.nfile"></a> nfile
    Too many files open in system.

    -
  • -
  • <a href="#errno.nobufs" name="errno.nobufs"></a> nobufs
    No buffer space available.

    -
  • -
  • <a href="#errno.nodev" name="errno.nodev"></a> nodev
    No such device.

    -
  • -
  • <a href="#errno.noent" name="errno.noent"></a> noent
    No such file or directory.

    -
  • -
  • <a href="#errno.noexec" name="errno.noexec"></a> noexec
    Executable file format error.

    -
  • -
  • <a href="#errno.nolck" name="errno.nolck"></a> nolck
    No locks available.

    -
  • -
  • <a href="#errno.nolink" name="errno.nolink"></a> nolink
    Reserved.

    -
  • -
  • <a href="#errno.nomem" name="errno.nomem"></a> nomem
    Not enough space.

    -
  • -
  • <a href="#errno.nomsg" name="errno.nomsg"></a> nomsg
    No message of the desired type.

    -
  • -
  • <a href="#errno.noprotoopt" name="errno.noprotoopt"></a> noprotoopt
    Protocol not available.

    -
  • -
  • <a href="#errno.nospc" name="errno.nospc"></a> nospc
    No space left on device.

    -
  • -
  • <a href="#errno.nosys" name="errno.nosys"></a> nosys
    Function not supported.

    -
  • -
  • <a href="#errno.notconn" name="errno.notconn"></a> notconn
    The socket is not connected.

    -
  • -
  • <a href="#errno.notdir" name="errno.notdir"></a> notdir
    Not a directory or a symbolic link to a directory.

    -
  • -
  • <a href="#errno.notempty" name="errno.notempty"></a> notempty
    Directory not empty.

    -
  • -
  • <a href="#errno.notrecoverable" name="errno.notrecoverable"></a> notrecoverable
    State not recoverable.

    -
  • -
  • <a href="#errno.notsock" name="errno.notsock"></a> notsock
    Not a socket.

    -
  • -
  • <a href="#errno.notsup" name="errno.notsup"></a> notsup
    Not supported, or operation not supported on socket.

    -
  • -
  • <a href="#errno.notty" name="errno.notty"></a> notty
    Inappropriate I/O control operation.

    -
  • -
  • <a href="#errno.nxio" name="errno.nxio"></a> nxio
    No such device or address.

    -
  • -
  • <a href="#errno.overflow" name="errno.overflow"></a> overflow
    Value too large to be stored in data type.

    -
  • -
  • <a href="#errno.ownerdead" name="errno.ownerdead"></a> ownerdead
    Previous owner died.

    -
  • -
  • <a href="#errno.perm" name="errno.perm"></a> perm
    Operation not permitted.

    -
  • -
  • <a href="#errno.pipe" name="errno.pipe"></a> pipe
    Broken pipe.

    -
  • -
  • <a href="#errno.proto" name="errno.proto"></a> proto
    Protocol error.

    -
  • -
  • <a href="#errno.protonosupport" name="errno.protonosupport"></a> protonosupport
    Protocol not supported.

    -
  • -
  • <a href="#errno.prototype" name="errno.prototype"></a> prototype
    Protocol wrong type for socket.

    -
  • -
  • <a href="#errno.range" name="errno.range"></a> range
    Result too large.

    -
  • -
  • <a href="#errno.rofs" name="errno.rofs"></a> rofs
    Read-only file system.

    -
  • -
  • <a href="#errno.spipe" name="errno.spipe"></a> spipe
    Invalid seek.

    -
  • -
  • <a href="#errno.srch" name="errno.srch"></a> srch
    No such process.

    -
  • -
  • <a href="#errno.stale" name="errno.stale"></a> stale
    Reserved.

    -
  • -
  • <a href="#errno.timedout" name="errno.timedout"></a> timedout
    Connection timed out.

    -
  • -
  • <a href="#errno.txtbsy" name="errno.txtbsy"></a> txtbsy
    Text file busy.

    -
  • -
  • <a href="#errno.xdev" name="errno.xdev"></a> xdev
    Cross-device link.

    -
  • -
  • <a href="#errno.notcapable" name="errno.notcapable"></a> notcapable
    Extension: Capabilities insufficient.

    -
  • -
-

<a href="#rights" name="rights"></a> rights: Flags(u64)

-

File descriptor rights, determining which actions may be performed.
Size: 8
Alignment: 8

-

Flags

-
    -
  • <a href="#rights.fd_datasync" name="rights.fd_datasync"></a> fd_datasync
    The right to invoke fd_datasync.
    If path_open is set, includes the right to invoke
    path_open with fdflags::dsync.

    -
  • -
  • <a href="#rights.fd_read" name="rights.fd_read"></a> fd_read
    The right to invoke fd_read and sock_recv.
    If rights::fd_seek is set, includes the right to invoke fd_pread.

    -
  • -
  • <a href="#rights.fd_seek" name="rights.fd_seek"></a> fd_seek
    The right to invoke fd_seek. This flag implies rights::fd_tell.

    -
  • -
  • <a href="#rights.fd_fdstat_set_flags" name="rights.fd_fdstat_set_flags"></a> fd_fdstat_set_flags
    The right to invoke fd_fdstat_set_flags.

    -
  • -
  • <a href="#rights.fd_sync" name="rights.fd_sync"></a> fd_sync
    The right to invoke fd_sync.
    If path_open is set, includes the right to invoke
    path_open with fdflags::rsync and fdflags::dsync.

    -
  • -
  • <a href="#rights.fd_tell" name="rights.fd_tell"></a> fd_tell
    The right to invoke fd_seek in such a way that the file offset
    remains unaltered (i.e., whence::cur with offset zero), or to
    invoke fd_tell.

    -
  • -
  • <a href="#rights.fd_write" name="rights.fd_write"></a> fd_write
    The right to invoke fd_write and sock_send.
    If rights::fd_seek is set, includes the right to invoke fd_pwrite.

    -
  • -
  • <a href="#rights.fd_advise" name="rights.fd_advise"></a> fd_advise
    The right to invoke fd_advise.

    -
  • -
  • <a href="#rights.fd_allocate" name="rights.fd_allocate"></a> fd_allocate
    The right to invoke fd_allocate.

    -
  • -
  • <a href="#rights.path_create_directory" name="rights.path_create_directory"></a> path_create_directory
    The right to invoke path_create_directory.

    -
  • -
  • <a href="#rights.path_create_file" name="rights.path_create_file"></a> path_create_file
    If path_open is set, the right to invoke path_open with oflags::creat.

    -
  • -
  • <a href="#rights.path_link_source" name="rights.path_link_source"></a> path_link_source
    The right to invoke path_link with the file descriptor as the
    source directory.

    -
  • -
  • <a href="#rights.path_link_target" name="rights.path_link_target"></a> path_link_target
    The right to invoke path_link with the file descriptor as the
    target directory.

    -
  • -
  • <a href="#rights.path_open" name="rights.path_open"></a> path_open
    The right to invoke path_open.

    -
  • -
  • <a href="#rights.fd_readdir" name="rights.fd_readdir"></a> fd_readdir
    The right to invoke fd_readdir.

    -
  • -
  • <a href="#rights.path_readlink" name="rights.path_readlink"></a> path_readlink
    The right to invoke path_readlink.

    -
  • -
  • <a href="#rights.path_rename_source" name="rights.path_rename_source"></a> path_rename_source
    The right to invoke path_rename with the file descriptor as the source directory.

    -
  • -
  • <a href="#rights.path_rename_target" name="rights.path_rename_target"></a> path_rename_target
    The right to invoke path_rename with the file descriptor as the target directory.

    -
  • -
  • <a href="#rights.path_filestat_get" name="rights.path_filestat_get"></a> path_filestat_get
    The right to invoke path_filestat_get.

    -
  • -
  • <a href="#rights.path_filestat_set_size" name="rights.path_filestat_set_size"></a> path_filestat_set_size
    The right to change a file's size (there is no path_filestat_set_size).
    If path_open is set, includes the right to invoke path_open with oflags::trunc.

    -
  • -
  • <a href="#rights.path_filestat_set_times" name="rights.path_filestat_set_times"></a> path_filestat_set_times
    The right to invoke path_filestat_set_times.

    -
  • -
  • <a href="#rights.fd_filestat_get" name="rights.fd_filestat_get"></a> fd_filestat_get
    The right to invoke fd_filestat_get.

    -
  • -
  • <a href="#rights.fd_filestat_set_size" name="rights.fd_filestat_set_size"></a> fd_filestat_set_size
    The right to invoke fd_filestat_set_size.

    -
  • -
  • <a href="#rights.fd_filestat_set_times" name="rights.fd_filestat_set_times"></a> fd_filestat_set_times
    The right to invoke fd_filestat_set_times.

    -
  • -
  • <a href="#rights.path_symlink" name="rights.path_symlink"></a> path_symlink
    The right to invoke path_symlink.

    -
  • -
  • <a href="#rights.path_remove_directory" name="rights.path_remove_directory"></a> path_remove_directory
    The right to invoke path_remove_directory.

    -
  • -
  • <a href="#rights.path_unlink_file" name="rights.path_unlink_file"></a> path_unlink_file
    The right to invoke path_unlink_file.

    -
  • -
  • <a href="#rights.poll_fd_readwrite" name="rights.poll_fd_readwrite"></a> poll_fd_readwrite
    If rights::fd_read is set, includes the right to invoke poll_oneoff to subscribe to eventtype::fd_read.
    If rights::fd_write is set, includes the right to invoke poll_oneoff to subscribe to eventtype::fd_write.

    -
  • -
  • <a href="#rights.sock_shutdown" name="rights.sock_shutdown"></a> sock_shutdown
    The right to invoke sock_shutdown.

    -
  • -
-

<a href="#fd" name="fd"></a> fd

-

A file descriptor handle.
Size: 4
Alignment: 4

-

Supertypes

-

<a href="#iovec" name="iovec"></a> iovec: Struct

-

A region of memory for scatter/gather reads.
Size: 8
Alignment: 4

-

Struct members

-
    -
  • <a href="#iovec.buf" name="iovec.buf"></a> buf: Pointer<u8>
    The address of the buffer to be filled.
    Offset: 0
  • -
  • <a href="#iovec.buf_len" name="iovec.buf_len"></a> buf_len: size
    The length of the buffer to be filled.
    Offset: 4

    <a href="#ciovec" name="ciovec"></a> ciovec: Struct

    -A region of memory for scatter/gather writes.
    Size: 8
    Alignment: 4

    Struct members

    -
  • -
  • <a href="#ciovec.buf" name="ciovec.buf"></a> buf: ConstPointer<u8>
    The address of the buffer to be written.
    Offset: 0
  • -
  • <a href="#ciovec.buf_len" name="ciovec.buf_len"></a> buf_len: size
    The length of the buffer to be written.
    Offset: 4

    <a href="#iovec_array" name="iovec_array"></a> iovec_array: Array<iovec>

    -Size: 8
    Alignment: 4

    <a href="#ciovec_array" name="ciovec_array"></a> ciovec_array: Array<ciovec>

    -Size: 8
    Alignment: 4

    <a href="#filedelta" name="filedelta"></a> filedelta: s64

    -Relative offset within a file.
    Size: 8
    Alignment: 8

    <a href="#whence" name="whence"></a> whence: Enum(u8)

    -The position relative to which to set the offset of the file descriptor.
    Size: 1
    Alignment: 1

    Variants

    -
  • -
  • <a href="#whence.set" name="whence.set"></a> set
    Seek relative to start-of-file.

    -
  • -
  • <a href="#whence.cur" name="whence.cur"></a> cur
    Seek relative to current position.

    -
  • -
  • <a href="#whence.end" name="whence.end"></a> end
    Seek relative to end-of-file.

    -
  • -
-

<a href="#dircookie" name="dircookie"></a> dircookie: u64

-

A reference to the offset of a directory entry.

-

The value 0 signifies the start of the directory.
Size: 8
Alignment: 8

-

<a href="#dirnamlen" name="dirnamlen"></a> dirnamlen: u32

-

The type for the $d_namlen field of $dirent.
Size: 4
Alignment: 4

-

<a href="#inode" name="inode"></a> inode: u64

-

File serial number that is unique within its file system.
Size: 8
Alignment: 8

-

<a href="#filetype" name="filetype"></a> filetype: Enum(u8)

-

The type of a file descriptor or file.
Size: 1
Alignment: 1

-

Variants

-
    -
  • <a href="#filetype.unknown" name="filetype.unknown"></a> unknown
    The type of the file descriptor or file is unknown or is different from any of the other types specified.

    -
  • -
  • <a href="#filetype.block_device" name="filetype.block_device"></a> block_device
    The file descriptor or file refers to a block device inode.

    -
  • -
  • <a href="#filetype.character_device" name="filetype.character_device"></a> character_device
    The file descriptor or file refers to a character device inode.

    -
  • -
  • <a href="#filetype.directory" name="filetype.directory"></a> directory
    The file descriptor or file refers to a directory inode.

    -
  • -
  • <a href="#filetype.regular_file" name="filetype.regular_file"></a> regular_file
    The file descriptor or file refers to a regular file inode.

    -
  • -
  • <a href="#filetype.socket_dgram" name="filetype.socket_dgram"></a> socket_dgram
    The file descriptor or file refers to a datagram socket.

    -
  • -
  • <a href="#filetype.socket_stream" name="filetype.socket_stream"></a> socket_stream
    The file descriptor or file refers to a byte-stream socket.

    -
  • -
  • <a href="#filetype.symbolic_link" name="filetype.symbolic_link"></a> symbolic_link
    The file refers to a symbolic link inode.

    -
  • -
-

<a href="#dirent" name="dirent"></a> dirent: Struct

-

A directory entry.
Size: 24
Alignment: 8

-

Struct members

-
    -
  • <a href="#dirent.d_next" name="dirent.d_next"></a> d_next: dircookie
    The offset of the next directory entry stored in this directory.
    Offset: 0
  • -
  • <a href="#dirent.d_ino" name="dirent.d_ino"></a> d_ino: inode
    The serial number of the file referred to by this directory entry.
    Offset: 8
  • -
  • <a href="#dirent.d_namlen" name="dirent.d_namlen"></a> d_namlen: dirnamlen
    The length of the name of the directory entry.
    Offset: 16
  • -
  • <a href="#dirent.d_type" name="dirent.d_type"></a> d_type: filetype
    The type of the file referred to by this directory entry.
    Offset: 20

    <a href="#advice" name="advice"></a> advice: Enum(u8)

    -File or memory access pattern advisory information.
    Size: 1
    Alignment: 1

    Variants

    -
  • -
  • <a href="#advice.normal" name="advice.normal"></a> normal
    The application has no advice to give on its behavior with respect to the specified data.

    -
  • -
  • <a href="#advice.sequential" name="advice.sequential"></a> sequential
    The application expects to access the specified data sequentially from lower offsets to higher offsets.

    -
  • -
  • <a href="#advice.random" name="advice.random"></a> random
    The application expects to access the specified data in a random order.

    -
  • -
  • <a href="#advice.willneed" name="advice.willneed"></a> willneed
    The application expects to access the specified data in the near future.

    -
  • -
  • <a href="#advice.dontneed" name="advice.dontneed"></a> dontneed
    The application expects that it will not access the specified data in the near future.

    -
  • -
  • <a href="#advice.noreuse" name="advice.noreuse"></a> noreuse
    The application expects to access the specified data once and then not reuse it thereafter.

    -
  • -
-

<a href="#fdflags" name="fdflags"></a> fdflags: Flags(u16)

-

File descriptor flags.
Size: 2
Alignment: 2

-

Flags

-
    -
  • <a href="#fdflags.append" name="fdflags.append"></a> append
    Append mode: Data written to the file is always appended to the file's end.

    -
  • -
  • <a href="#fdflags.dsync" name="fdflags.dsync"></a> dsync
    Write according to synchronized I/O data integrity completion. Only the data stored in the file is synchronized.

    -
  • -
  • <a href="#fdflags.nonblock" name="fdflags.nonblock"></a> nonblock
    Non-blocking mode.

    -
  • -
  • <a href="#fdflags.rsync" name="fdflags.rsync"></a> rsync
    Synchronized read I/O operations.

    -
  • -
  • <a href="#fdflags.sync" name="fdflags.sync"></a> sync
    Write according to synchronized I/O file integrity completion. In
    addition to synchronizing the data stored in the file, the implementation
    may also synchronously update the file's metadata.

    -
  • -
-

<a href="#fdstat" name="fdstat"></a> fdstat: Struct

-

File descriptor attributes.
Size: 24
Alignment: 8

-

Struct members

-
    -
  • <a href="#fdstat.fs_filetype" name="fdstat.fs_filetype"></a> fs_filetype: filetype
    File type.
    Offset: 0
  • -
  • <a href="#fdstat.fs_flags" name="fdstat.fs_flags"></a> fs_flags: fdflags
    File descriptor flags.
    Offset: 2
  • -
  • <a href="#fdstat.fs_rights_base" name="fdstat.fs_rights_base"></a> fs_rights_base: rights
    Rights that apply to this file descriptor.
    Offset: 8
  • -
  • <a href="#fdstat.fs_rights_inheriting" name="fdstat.fs_rights_inheriting"></a> fs_rights_inheriting: rights
    Maximum set of rights that may be installed on new file descriptors that
    are created through this file descriptor, e.g., through path_open.
    Offset: 16

    <a href="#device" name="device"></a> device: u64

    -Identifier for a device containing a file system. Can be used in combination
    with inode to uniquely identify a file or directory in the filesystem.
    Size: 8
    Alignment: 8

    <a href="#fstflags" name="fstflags"></a> fstflags: Flags(u16)

    -Which file time attributes to adjust.
    Size: 2
    Alignment: 2

    Flags

    -
  • -
  • <a href="#fstflags.atim" name="fstflags.atim"></a> atim
    Adjust the last data access timestamp to the value stored in filestat::atim.

    -
  • -
  • <a href="#fstflags.atim_now" name="fstflags.atim_now"></a> atim_now
    Adjust the last data access timestamp to the time of clock clockid::realtime.

    -
  • -
  • <a href="#fstflags.mtim" name="fstflags.mtim"></a> mtim
    Adjust the last data modification timestamp to the value stored in filestat::mtim.

    -
  • -
  • <a href="#fstflags.mtim_now" name="fstflags.mtim_now"></a> mtim_now
    Adjust the last data modification timestamp to the time of clock clockid::realtime.

    -
  • -
-

<a href="#lookupflags" name="lookupflags"></a> lookupflags: Flags(u32)

-

Flags determining the method of how paths are resolved.
Size: 4
Alignment: 4

-

Flags

-
    -
  • <a href="#lookupflags.symlink_follow" name="lookupflags.symlink_follow"></a> symlink_follow
    As long as the resolved path corresponds to a symbolic link, it is expanded.
  • -
-

<a href="#oflags" name="oflags"></a> oflags: Flags(u16)

-

Open flags used by path_open.
Size: 2
Alignment: 2

-

Flags

-
    -
  • <a href="#oflags.creat" name="oflags.creat"></a> creat
    Create file if it does not exist.

    -
  • -
  • <a href="#oflags.directory" name="oflags.directory"></a> directory
    Fail if not a directory.

    -
  • -
  • <a href="#oflags.excl" name="oflags.excl"></a> excl
    Fail if file already exists.

    -
  • -
  • <a href="#oflags.trunc" name="oflags.trunc"></a> trunc
    Truncate file to size 0.

    -
  • -
-

<a href="#linkcount" name="linkcount"></a> linkcount: u64

-

Number of hard links to an inode.
Size: 8
Alignment: 8

-

<a href="#filestat" name="filestat"></a> filestat: Struct

-

File attributes.
Size: 64
Alignment: 8

-

Struct members

-
    -
  • <a href="#filestat.dev" name="filestat.dev"></a> dev: device
    Device ID of device containing the file.
    Offset: 0
  • -
  • <a href="#filestat.ino" name="filestat.ino"></a> ino: inode
    File serial number.
    Offset: 8
  • -
  • <a href="#filestat.filetype" name="filestat.filetype"></a> filetype: filetype
    File type.
    Offset: 16
  • -
  • <a href="#filestat.nlink" name="filestat.nlink"></a> nlink: linkcount
    Number of hard links to the file.
    Offset: 24
  • -
  • <a href="#filestat.size" name="filestat.size"></a> size: filesize
    For regular files, the file size in bytes. For symbolic links, the length in bytes of the pathname contained in the symbolic link.
    Offset: 32
  • -
  • <a href="#filestat.atim" name="filestat.atim"></a> atim: timestamp
    Last data access timestamp.
    Offset: 40
  • -
  • <a href="#filestat.mtim" name="filestat.mtim"></a> mtim: timestamp
    Last data modification timestamp.
    Offset: 48
  • -
  • <a href="#filestat.ctim" name="filestat.ctim"></a> ctim: timestamp
    Last file status change timestamp.
    Offset: 56

    <a href="#userdata" name="userdata"></a> userdata: u64

    -User-provided value that may be attached to objects that is retained when
    extracted from the implementation.
    Size: 8
    Alignment: 8

    <a href="#eventtype" name="eventtype"></a> eventtype: Enum(u8)

    -Type of a subscription to an event or its occurrence.
    Size: 1
    Alignment: 1

    Variants

    -
  • -
  • <a href="#eventtype.clock" name="eventtype.clock"></a> clock
    The time value of clock subscription_clock::id has
    reached timestamp subscription_clock::timeout.

    -
  • -
  • <a href="#eventtype.fd_read" name="eventtype.fd_read"></a> fd_read
    File descriptor subscription_fd_readwrite::file_descriptor has data
    available for reading. This event always triggers for regular files.

    -
  • -
  • <a href="#eventtype.fd_write" name="eventtype.fd_write"></a> fd_write
    File descriptor subscription_fd_readwrite::file_descriptor has capacity
    available for writing. This event always triggers for regular files.

    -
  • -
-

<a href="#eventrwflags" name="eventrwflags"></a> eventrwflags: Flags(u16)

-

The state of the file descriptor subscribed to with
eventtype::fd_read or eventtype::fd_write.
Size: 2
Alignment: 2

-

Flags

-
    -
  • <a href="#eventrwflags.fd_readwrite_hangup" name="eventrwflags.fd_readwrite_hangup"></a> fd_readwrite_hangup
    The peer of this socket has closed or disconnected.
  • -
-

<a href="#event_fd_readwrite" name="event_fd_readwrite"></a> event_fd_readwrite: Struct

-

The contents of an $event when type is eventtype::fd_read or
eventtype::fd_write.
Size: 16
Alignment: 8

-

Struct members

-
    -
  • <a href="#event_fd_readwrite.nbytes" name="event_fd_readwrite.nbytes"></a> nbytes: filesize
    The number of bytes available for reading or writing.
    Offset: 0
  • -
  • <a href="#event_fd_readwrite.flags" name="event_fd_readwrite.flags"></a> flags: eventrwflags
    The state of the file descriptor.
    Offset: 8

    <a href="#event" name="event"></a> event: Struct

    -An event that occurred.
    Size: 32
    Alignment: 8

    Struct members

    -
  • -
  • <a href="#event.userdata" name="event.userdata"></a> userdata: userdata
    User-provided value that got attached to subscription::userdata.
    Offset: 0
  • -
  • <a href="#event.error" name="event.error"></a> error: errno
    If non-zero, an error that occurred while processing the subscription request.
    Offset: 8
  • -
  • <a href="#event.type" name="event.type"></a> type: eventtype
    The type of event that occurred
    Offset: 10
  • -
  • <a href="#event.fd_readwrite" name="event.fd_readwrite"></a> fd_readwrite: event_fd_readwrite
    The contents of the event, if it is an eventtype::fd_read or
    eventtype::fd_write. eventtype::clock events ignore this field.
    Offset: 16

    <a href="#subclockflags" name="subclockflags"></a> subclockflags: Flags(u16)

    -Flags determining how to interpret the timestamp provided in
    subscription_clock::timeout.
    Size: 2
    Alignment: 2

    Flags

    -
  • -
  • <a href="#subclockflags.subscription_clock_abstime" name="subclockflags.subscription_clock_abstime"></a> subscription_clock_abstime
    If set, treat the timestamp provided in
    subscription_clock::timeout as an absolute timestamp of clock
    subscription_clock::id. If clear, treat the timestamp
    provided in subscription_clock::timeout relative to the
    current time value of clock subscription_clock::id.
  • -
-

<a href="#subscription_clock" name="subscription_clock"></a> subscription_clock: Struct

-

The contents of a subscription when type is eventtype::clock.
Size: 32
Alignment: 8

-

Struct members

-
    -
  • <a href="#subscription_clock.id" name="subscription_clock.id"></a> id: clockid
    The clock against which to compare the timestamp.
    Offset: 0
  • -
  • <a href="#subscription_clock.timeout" name="subscription_clock.timeout"></a> timeout: timestamp
    The absolute or relative timestamp.
    Offset: 8
  • -
  • <a href="#subscription_clock.precision" name="subscription_clock.precision"></a> precision: timestamp
    The amount of time that the implementation may wait additionally
    to coalesce with other events.
    Offset: 16
  • -
  • <a href="#subscription_clock.flags" name="subscription_clock.flags"></a> flags: subclockflags
    Flags specifying whether the timeout is absolute or relative
    Offset: 24

    <a href="#subscription_fd_readwrite" name="subscription_fd_readwrite"></a> subscription_fd_readwrite: Struct

    -The contents of a subscription when type is type is
    eventtype::fd_read or eventtype::fd_write.
    Size: 4
    Alignment: 4

    Struct members

    -
  • -
  • <a href="#subscription_fd_readwrite.file_descriptor" name="subscription_fd_readwrite.file_descriptor"></a> file_descriptor: fd
    The file descriptor on which to wait for it to become ready for reading or writing.
    Offset: 0

    <a href="#subscription_u" name="subscription_u"></a> subscription_u: Union

    -The contents of a subscription.
    Size: 40
    Alignment: 8

    Union Layout

    -
  • -
  • tag_size: 1
  • -
  • tag_align: 1
  • -
  • contents_offset: 8
  • -
  • contents_size: 32
  • -
  • contents_align: 8

    Union variants

    -
  • -
  • <a href="#subscription_u.clock" name="subscription_u.clock"></a> clock: subscription_clock

    -
  • -
  • <a href="#subscription_u.fd_read" name="subscription_u.fd_read"></a> fd_read: subscription_fd_readwrite

    -
  • -
  • <a href="#subscription_u.fd_write" name="subscription_u.fd_write"></a> fd_write: subscription_fd_readwrite

    -
  • -
-

<a href="#subscription" name="subscription"></a> subscription: Struct

-

Subscription to an event.
Size: 48
Alignment: 8

-

Struct members

-
    -
  • <a href="#subscription.userdata" name="subscription.userdata"></a> userdata: userdata
    User-provided value that is attached to the subscription in the
    implementation and returned through event::userdata.
    Offset: 0
  • -
  • <a href="#subscription.u" name="subscription.u"></a> u: subscription_u
    The type of the event to which to subscribe, and its contents
    Offset: 8

    <a href="#exitcode" name="exitcode"></a> exitcode: u32

    -Exit code generated by a process when exiting.
    Size: 4
    Alignment: 4

    <a href="#signal" name="signal"></a> signal: Enum(u8)

    -Signal condition.
    Size: 1
    Alignment: 1

    Variants

    -
  • -
  • <a href="#signal.none" name="signal.none"></a> none
    No signal. Note that POSIX has special semantics for kill(pid, 0),
    so this value is reserved.

    -
  • -
  • <a href="#signal.hup" name="signal.hup"></a> hup
    Hangup.
    Action: Terminates the process.

    -
  • -
  • <a href="#signal.int" name="signal.int"></a> int
    Terminate interrupt signal.
    Action: Terminates the process.

    -
  • -
  • <a href="#signal.quit" name="signal.quit"></a> quit
    Terminal quit signal.
    Action: Terminates the process.

    -
  • -
  • <a href="#signal.ill" name="signal.ill"></a> ill
    Illegal instruction.
    Action: Terminates the process.

    -
  • -
  • <a href="#signal.trap" name="signal.trap"></a> trap
    Trace/breakpoint trap.
    Action: Terminates the process.

    -
  • -
  • <a href="#signal.abrt" name="signal.abrt"></a> abrt
    Process abort signal.
    Action: Terminates the process.

    -
  • -
  • <a href="#signal.bus" name="signal.bus"></a> bus
    Access to an undefined portion of a memory object.
    Action: Terminates the process.

    -
  • -
  • <a href="#signal.fpe" name="signal.fpe"></a> fpe
    Erroneous arithmetic operation.
    Action: Terminates the process.

    -
  • -
  • <a href="#signal.kill" name="signal.kill"></a> kill
    Kill.
    Action: Terminates the process.

    -
  • -
  • <a href="#signal.usr1" name="signal.usr1"></a> usr1
    User-defined signal 1.
    Action: Terminates the process.

    -
  • -
  • <a href="#signal.segv" name="signal.segv"></a> segv
    Invalid memory reference.
    Action: Terminates the process.

    -
  • -
  • <a href="#signal.usr2" name="signal.usr2"></a> usr2
    User-defined signal 2.
    Action: Terminates the process.

    -
  • -
  • <a href="#signal.pipe" name="signal.pipe"></a> pipe
    Write on a pipe with no one to read it.
    Action: Ignored.

    -
  • -
  • <a href="#signal.alrm" name="signal.alrm"></a> alrm
    Alarm clock.
    Action: Terminates the process.

    -
  • -
  • <a href="#signal.term" name="signal.term"></a> term
    Termination signal.
    Action: Terminates the process.

    -
  • -
  • <a href="#signal.chld" name="signal.chld"></a> chld
    Child process terminated, stopped, or continued.
    Action: Ignored.

    -
  • -
  • <a href="#signal.cont" name="signal.cont"></a> cont
    Continue executing, if stopped.
    Action: Continues executing, if stopped.

    -
  • -
  • <a href="#signal.stop" name="signal.stop"></a> stop
    Stop executing.
    Action: Stops executing.

    -
  • -
  • <a href="#signal.tstp" name="signal.tstp"></a> tstp
    Terminal stop signal.
    Action: Stops executing.

    -
  • -
  • <a href="#signal.ttin" name="signal.ttin"></a> ttin
    Background process attempting read.
    Action: Stops executing.

    -
  • -
  • <a href="#signal.ttou" name="signal.ttou"></a> ttou
    Background process attempting write.
    Action: Stops executing.

    -
  • -
  • <a href="#signal.urg" name="signal.urg"></a> urg
    High bandwidth data is available at a socket.
    Action: Ignored.

    -
  • -
  • <a href="#signal.xcpu" name="signal.xcpu"></a> xcpu
    CPU time limit exceeded.
    Action: Terminates the process.

    -
  • -
  • <a href="#signal.xfsz" name="signal.xfsz"></a> xfsz
    File size limit exceeded.
    Action: Terminates the process.

    -
  • -
  • <a href="#signal.vtalrm" name="signal.vtalrm"></a> vtalrm
    Virtual timer expired.
    Action: Terminates the process.

    -
  • -
  • <a href="#signal.prof" name="signal.prof"></a> prof
    Profiling timer expired.
    Action: Terminates the process.

    -
  • -
  • <a href="#signal.winch" name="signal.winch"></a> winch
    Window changed.
    Action: Ignored.

    -
  • -
  • <a href="#signal.poll" name="signal.poll"></a> poll
    I/O possible.
    Action: Terminates the process.

    -
  • -
  • <a href="#signal.pwr" name="signal.pwr"></a> pwr
    Power failure.
    Action: Terminates the process.

    -
  • -
  • <a href="#signal.sys" name="signal.sys"></a> sys
    Bad system call.
    Action: Terminates the process.

    -
  • -
-

<a href="#riflags" name="riflags"></a> riflags: Flags(u16)

-

Flags provided to sock_recv.
Size: 2
Alignment: 2

-

Flags

-
    -
  • <a href="#riflags.recv_peek" name="riflags.recv_peek"></a> recv_peek
    Returns the message without removing it from the socket's receive queue.

    -
  • -
  • <a href="#riflags.recv_waitall" name="riflags.recv_waitall"></a> recv_waitall
    On byte-stream sockets, block until the full amount of data can be returned.

    -
  • -
-

<a href="#roflags" name="roflags"></a> roflags: Flags(u16)

-

Flags returned by sock_recv.
Size: 2
Alignment: 2

-

Flags

-
    -
  • <a href="#roflags.recv_data_truncated" name="roflags.recv_data_truncated"></a> recv_data_truncated
    Returned by sock_recv: Message data has been truncated.
  • -
-

<a href="#siflags" name="siflags"></a> siflags: u16

-

Flags provided to sock_send. As there are currently no flags
defined, it must be set to zero.
Size: 2
Alignment: 2

-

<a href="#sdflags" name="sdflags"></a> sdflags: Flags(u8)

-

Which channels on a socket to shut down.
Size: 1
Alignment: 1

-

Flags

-
    -
  • <a href="#sdflags.rd" name="sdflags.rd"></a> rd
    Disables further receive operations.

    -
  • -
  • <a href="#sdflags.wr" name="sdflags.wr"></a> wr
    Disables further send operations.

    -
  • -
-

<a href="#preopentype" name="preopentype"></a> preopentype: Enum(u8)

-

Identifiers for preopened capabilities.
Size: 1
Alignment: 1

-

Variants

-
    -
  • <a href="#preopentype.dir" name="preopentype.dir"></a> dir
    A pre-opened directory.
  • -
-

<a href="#prestat_dir" name="prestat_dir"></a> prestat_dir: Struct

-

The contents of a $prestat when type is preopentype::dir.
Size: 4
Alignment: 4

-

Struct members

-
    -
  • <a href="#prestat_dir.pr_name_len" name="prestat_dir.pr_name_len"></a> pr_name_len: size
    The length of the directory name for use with fd_prestat_dir_name.
    Offset: 0

    <a href="#prestat" name="prestat"></a> prestat: Union

    -Information about a pre-opened capability.
    Size: 8
    Alignment: 4

    Union Layout

    -
  • -
  • tag_size: 1
  • -
  • tag_align: 1
  • -
  • contents_offset: 4
  • -
  • contents_size: 4
  • -
  • contents_align: 4

    Union variants

    -
  • -
  • <a href="#prestat.dir" name="prestat.dir"></a> dir: prestat_dir
  • -
-

Modules

-

<a href="#wasi_snapshot_preview1" name="wasi_snapshot_preview1"></a> wasi_snapshot_preview1

-

Imports

-

Memory

-

Functions

-
-

<a href="#args_get" name="args_get"></a> args_get(argv: Pointer<Pointer<u8>>, argv_buf: Pointer<u8>) -> errno

-

Read command-line argument data.
The size of the array should match that returned by args_sizes_get

-
Params
-
    -
  • <a href="#args_get.argv" name="args_get.argv"></a> argv: Pointer<Pointer<u8>>

    -
  • -
  • <a href="#args_get.argv_buf" name="args_get.argv_buf"></a> argv_buf: Pointer<u8>

    -
  • -
-
Results
-
    -
  • <a href="#args_get.error" name="args_get.error"></a> error: errno
  • -
-
-

<a href="#args_sizes_get" name="args_sizes_get"></a> args_sizes_get() -> (errno, size, size)

-

Return command-line argument data sizes.

-
Params
-
Results
-
    -
  • <a href="#args_sizes_get.error" name="args_sizes_get.error"></a> error: errno

    -
  • -
  • <a href="#args_sizes_get.argc" name="args_sizes_get.argc"></a> argc: size
    The number of arguments.

    -
  • -
  • <a href="#args_sizes_get.argv_buf_size" name="args_sizes_get.argv_buf_size"></a> argv_buf_size: size
    The size of the argument string data.

    -
  • -
-
-

<a href="#environ_get" name="environ_get"></a> environ_get(environ: Pointer<Pointer<u8>>, environ_buf: Pointer<u8>) -> errno

-

Read environment variable data.
The sizes of the buffers should match that returned by environ_sizes_get.

-
Params
-
    -
  • <a href="#environ_get.environ" name="environ_get.environ"></a> environ: Pointer<Pointer<u8>>

    -
  • -
  • <a href="#environ_get.environ_buf" name="environ_get.environ_buf"></a> environ_buf: Pointer<u8>

    -
  • -
-
Results
-
    -
  • <a href="#environ_get.error" name="environ_get.error"></a> error: errno
  • -
-
-

<a href="#environ_sizes_get" name="environ_sizes_get"></a> environ_sizes_get() -> (errno, size, size)

-

Return environment variable data sizes.

-
Params
-
Results
-
    -
  • <a href="#environ_sizes_get.error" name="environ_sizes_get.error"></a> error: errno

    -
  • -
  • <a href="#environ_sizes_get.environc" name="environ_sizes_get.environc"></a> environc: size
    The number of environment variable arguments.

    -
  • -
  • <a href="#environ_sizes_get.environ_buf_size" name="environ_sizes_get.environ_buf_size"></a> environ_buf_size: size
    The size of the environment variable data.

    -
  • -
-
-

<a href="#clock_res_get" name="clock_res_get"></a> clock_res_get(id: clockid) -> (errno, timestamp)

-

Return the resolution of a clock.
Implementations are required to provide a non-zero value for supported clocks. For unsupported clocks,
return errno::inval.
Note: This is similar to clock_getres in POSIX.

-
Params
-
    -
  • <a href="#clock_res_get.id" name="clock_res_get.id"></a> id: clockid
    The clock for which to return the resolution.
  • -
-
Results
-
    -
  • <a href="#clock_res_get.error" name="clock_res_get.error"></a> error: errno

    -
  • -
  • <a href="#clock_res_get.resolution" name="clock_res_get.resolution"></a> resolution: timestamp
    The resolution of the clock.

    -
  • -
-
-

<a href="#clock_time_get" name="clock_time_get"></a> clock_time_get(id: clockid, precision: timestamp) -> (errno, timestamp)

-

Return the time value of a clock.
Note: This is similar to clock_gettime in POSIX.

-
Params
-
    -
  • <a href="#clock_time_get.id" name="clock_time_get.id"></a> id: clockid
    The clock for which to return the time.

    -
  • -
  • <a href="#clock_time_get.precision" name="clock_time_get.precision"></a> precision: timestamp
    The maximum lag (exclusive) that the returned time value may have, compared to its actual value.

    -
  • -
-
Results
-
    -
  • <a href="#clock_time_get.error" name="clock_time_get.error"></a> error: errno

    -
  • -
  • <a href="#clock_time_get.time" name="clock_time_get.time"></a> time: timestamp
    The time value of the clock.

    -
  • -
-
-

<a href="#fd_advise" name="fd_advise"></a> fd_advise(fd: fd, offset: filesize, len: filesize, advice: advice) -> errno

-

Provide file advisory information on a file descriptor.
Note: This is similar to posix_fadvise in POSIX.

-
Params
-
    -
  • <a href="#fd_advise.fd" name="fd_advise.fd"></a> fd: fd

    -
  • -
  • <a href="#fd_advise.offset" name="fd_advise.offset"></a> offset: filesize
    The offset within the file to which the advisory applies.

    -
  • -
  • <a href="#fd_advise.len" name="fd_advise.len"></a> len: filesize
    The length of the region to which the advisory applies.

    -
  • -
  • <a href="#fd_advise.advice" name="fd_advise.advice"></a> advice: advice
    The advice.

    -
  • -
-
Results
-
    -
  • <a href="#fd_advise.error" name="fd_advise.error"></a> error: errno
  • -
-
-

<a href="#fd_allocate" name="fd_allocate"></a> fd_allocate(fd: fd, offset: filesize, len: filesize) -> errno

-

Force the allocation of space in a file.
Note: This is similar to posix_fallocate in POSIX.

-
Params
-
    -
  • <a href="#fd_allocate.fd" name="fd_allocate.fd"></a> fd: fd

    -
  • -
  • <a href="#fd_allocate.offset" name="fd_allocate.offset"></a> offset: filesize
    The offset at which to start the allocation.

    -
  • -
  • <a href="#fd_allocate.len" name="fd_allocate.len"></a> len: filesize
    The length of the area that is allocated.

    -
  • -
-
Results
-
    -
  • <a href="#fd_allocate.error" name="fd_allocate.error"></a> error: errno
  • -
-
-

<a href="#fd_close" name="fd_close"></a> fd_close(fd: fd) -> errno

-

Close a file descriptor.
Note: This is similar to close in POSIX.

-
Params
-
    -
  • <a href="#fd_close.fd" name="fd_close.fd"></a> fd: fd
  • -
-
Results
-
    -
  • <a href="#fd_close.error" name="fd_close.error"></a> error: errno
  • -
-
-

<a href="#fd_datasync" name="fd_datasync"></a> fd_datasync(fd: fd) -> errno

-

Synchronize the data of a file to disk.
Note: This is similar to fdatasync in POSIX.

-
Params
-
    -
  • <a href="#fd_datasync.fd" name="fd_datasync.fd"></a> fd: fd
  • -
-
Results
-
    -
  • <a href="#fd_datasync.error" name="fd_datasync.error"></a> error: errno
  • -
-
-

<a href="#fd_fdstat_get" name="fd_fdstat_get"></a> fd_fdstat_get(fd: fd) -> (errno, fdstat)

-

Get the attributes of a file descriptor.
Note: This returns similar flags to fcntl(fd, F_GETFL) in POSIX, as well as additional fields.

-
Params
-
    -
  • <a href="#fd_fdstat_get.fd" name="fd_fdstat_get.fd"></a> fd: fd
  • -
-
Results
-
    -
  • <a href="#fd_fdstat_get.error" name="fd_fdstat_get.error"></a> error: errno

    -
  • -
  • <a href="#fd_fdstat_get.stat" name="fd_fdstat_get.stat"></a> stat: fdstat
    The buffer where the file descriptor's attributes are stored.

    -
  • -
-
-

<a href="#fd_fdstat_set_flags" name="fd_fdstat_set_flags"></a> fd_fdstat_set_flags(fd: fd, flags: fdflags) -> errno

-

Adjust the flags associated with a file descriptor.
Note: This is similar to fcntl(fd, F_SETFL, flags) in POSIX.

-
Params
-
    -
  • <a href="#fd_fdstat_set_flags.fd" name="fd_fdstat_set_flags.fd"></a> fd: fd

    -
  • -
  • <a href="#fd_fdstat_set_flags.flags" name="fd_fdstat_set_flags.flags"></a> flags: fdflags
    The desired values of the file descriptor flags.

    -
  • -
-
Results
-
    -
  • <a href="#fd_fdstat_set_flags.error" name="fd_fdstat_set_flags.error"></a> error: errno
  • -
-
-

<a href="#fd_fdstat_set_rights" name="fd_fdstat_set_rights"></a> fd_fdstat_set_rights(fd: fd, fs_rights_base: rights, fs_rights_inheriting: rights) -> errno

-

Adjust the rights associated with a file descriptor.
This can only be used to remove rights, and returns errno::notcapable if called in a way that would attempt to add rights

-
Params
-
    -
  • <a href="#fd_fdstat_set_rights.fd" name="fd_fdstat_set_rights.fd"></a> fd: fd

    -
  • -
  • <a href="#fd_fdstat_set_rights.fs_rights_base" name="fd_fdstat_set_rights.fs_rights_base"></a> fs_rights_base: rights
    The desired rights of the file descriptor.

    -
  • -
  • <a href="#fd_fdstat_set_rights.fs_rights_inheriting" name="fd_fdstat_set_rights.fs_rights_inheriting"></a> fs_rights_inheriting: rights

    -
  • -
-
Results
-
    -
  • <a href="#fd_fdstat_set_rights.error" name="fd_fdstat_set_rights.error"></a> error: errno
  • -
-
-

<a href="#fd_filestat_get" name="fd_filestat_get"></a> fd_filestat_get(fd: fd) -> (errno, filestat)

-

Return the attributes of an open file.

-
Params
-
    -
  • <a href="#fd_filestat_get.fd" name="fd_filestat_get.fd"></a> fd: fd
  • -
-
Results
-
    -
  • <a href="#fd_filestat_get.error" name="fd_filestat_get.error"></a> error: errno

    -
  • -
  • <a href="#fd_filestat_get.buf" name="fd_filestat_get.buf"></a> buf: filestat
    The buffer where the file's attributes are stored.

    -
  • -
-
-

<a href="#fd_filestat_set_size" name="fd_filestat_set_size"></a> fd_filestat_set_size(fd: fd, size: filesize) -> errno

-

Adjust the size of an open file. If this increases the file's size, the extra bytes are filled with zeros.
Note: This is similar to ftruncate in POSIX.

-
Params
-
    -
  • <a href="#fd_filestat_set_size.fd" name="fd_filestat_set_size.fd"></a> fd: fd

    -
  • -
  • <a href="#fd_filestat_set_size.size" name="fd_filestat_set_size.size"></a> size: filesize
    The desired file size.

    -
  • -
-
Results
-
    -
  • <a href="#fd_filestat_set_size.error" name="fd_filestat_set_size.error"></a> error: errno
  • -
-
-

<a href="#fd_filestat_set_times" name="fd_filestat_set_times"></a> fd_filestat_set_times(fd: fd, atim: timestamp, mtim: timestamp, fst_flags: fstflags) -> errno

-

Adjust the timestamps of an open file or directory.
Note: This is similar to futimens in POSIX.

-
Params
-
    -
  • <a href="#fd_filestat_set_times.fd" name="fd_filestat_set_times.fd"></a> fd: fd

    -
  • -
  • <a href="#fd_filestat_set_times.atim" name="fd_filestat_set_times.atim"></a> atim: timestamp
    The desired values of the data access timestamp.

    -
  • -
  • <a href="#fd_filestat_set_times.mtim" name="fd_filestat_set_times.mtim"></a> mtim: timestamp
    The desired values of the data modification timestamp.

    -
  • -
  • <a href="#fd_filestat_set_times.fst_flags" name="fd_filestat_set_times.fst_flags"></a> fst_flags: fstflags
    A bitmask indicating which timestamps to adjust.

    -
  • -
-
Results
-
    -
  • <a href="#fd_filestat_set_times.error" name="fd_filestat_set_times.error"></a> error: errno
  • -
-
-

<a href="#fd_pread" name="fd_pread"></a> fd_pread(fd: fd, iovs: iovec_array, offset: filesize) -> (errno, size)

-

Read from a file descriptor, without using and updating the file descriptor's offset.
Note: This is similar to preadv in POSIX.

-
Params
-
    -
  • <a href="#fd_pread.fd" name="fd_pread.fd"></a> fd: fd

    -
  • -
  • <a href="#fd_pread.iovs" name="fd_pread.iovs"></a> iovs: iovec_array
    List of scatter/gather vectors in which to store data.

    -
  • -
  • <a href="#fd_pread.offset" name="fd_pread.offset"></a> offset: filesize
    The offset within the file at which to read.

    -
  • -
-
Results
-
    -
  • <a href="#fd_pread.error" name="fd_pread.error"></a> error: errno

    -
  • -
  • <a href="#fd_pread.nread" name="fd_pread.nread"></a> nread: size
    The number of bytes read.

    -
  • -
-
-

<a href="#fd_prestat_get" name="fd_prestat_get"></a> fd_prestat_get(fd: fd) -> (errno, prestat)

-

Return a description of the given preopened file descriptor.

-
Params
-
    -
  • <a href="#fd_prestat_get.fd" name="fd_prestat_get.fd"></a> fd: fd
  • -
-
Results
-
    -
  • <a href="#fd_prestat_get.error" name="fd_prestat_get.error"></a> error: errno

    -
  • -
  • <a href="#fd_prestat_get.buf" name="fd_prestat_get.buf"></a> buf: prestat
    The buffer where the description is stored.

    -
  • -
-
-

<a href="#fd_prestat_dir_name" name="fd_prestat_dir_name"></a> fd_prestat_dir_name(fd: fd, path: Pointer<u8>, path_len: size) -> errno

-

Return a description of the given preopened file descriptor.

-
Params
-
    -
  • <a href="#fd_prestat_dir_name.fd" name="fd_prestat_dir_name.fd"></a> fd: fd

    -
  • -
  • <a href="#fd_prestat_dir_name.path" name="fd_prestat_dir_name.path"></a> path: Pointer<u8>
    A buffer into which to write the preopened directory name.

    -
  • -
  • <a href="#fd_prestat_dir_name.path_len" name="fd_prestat_dir_name.path_len"></a> path_len: size

    -
  • -
-
Results
-
    -
  • <a href="#fd_prestat_dir_name.error" name="fd_prestat_dir_name.error"></a> error: errno
  • -
-
-

<a href="#fd_pwrite" name="fd_pwrite"></a> fd_pwrite(fd: fd, iovs: ciovec_array, offset: filesize) -> (errno, size)

-

Write to a file descriptor, without using and updating the file descriptor's offset.
Note: This is similar to pwritev in POSIX.

-
Params
-
    -
  • <a href="#fd_pwrite.fd" name="fd_pwrite.fd"></a> fd: fd

    -
  • -
  • <a href="#fd_pwrite.iovs" name="fd_pwrite.iovs"></a> iovs: ciovec_array
    List of scatter/gather vectors from which to retrieve data.

    -
  • -
  • <a href="#fd_pwrite.offset" name="fd_pwrite.offset"></a> offset: filesize
    The offset within the file at which to write.

    -
  • -
-
Results
-
    -
  • <a href="#fd_pwrite.error" name="fd_pwrite.error"></a> error: errno

    -
  • -
  • <a href="#fd_pwrite.nwritten" name="fd_pwrite.nwritten"></a> nwritten: size
    The number of bytes written.

    -
  • -
-
-

<a href="#fd_read" name="fd_read"></a> fd_read(fd: fd, iovs: iovec_array) -> (errno, size)

-

Read from a file descriptor.
Note: This is similar to readv in POSIX.

-
Params
-
    -
  • <a href="#fd_read.fd" name="fd_read.fd"></a> fd: fd

    -
  • -
  • <a href="#fd_read.iovs" name="fd_read.iovs"></a> iovs: iovec_array
    List of scatter/gather vectors to which to store data.

    -
  • -
-
Results
-
    -
  • <a href="#fd_read.error" name="fd_read.error"></a> error: errno

    -
  • -
  • <a href="#fd_read.nread" name="fd_read.nread"></a> nread: size
    The number of bytes read.

    -
  • -
-
- -

Read directory entries from a directory.
When successful, the contents of the output buffer consist of a sequence of
directory entries. Each directory entry consists of a dirent_t object,
followed by dirent_t::d_namlen bytes holding the name of the directory
entry.
This function fills the output buffer as much as possible, potentially
truncating the last directory entry. This allows the caller to grow its
read buffer size in case it's too small to fit a single large directory
entry, or skip the oversized directory entry.

-
Params
-
    -
  • <a href="#fd_readdir.fd" name="fd_readdir.fd"></a> fd: fd

    -
  • -
  • <a href="#fd_readdir.buf" name="fd_readdir.buf"></a> buf: Pointer<u8>
    The buffer where directory entries are stored

    -
  • -
  • <a href="#fd_readdir.buf_len" name="fd_readdir.buf_len"></a> buf_len: size

    -
  • -
  • <a href="#fd_readdir.cookie" name="fd_readdir.cookie"></a> cookie: dircookie
    The location within the directory to start reading

    -
  • -
-
Results
-
    -
  • <a href="#fd_readdir.error" name="fd_readdir.error"></a> error: errno

    -
  • -
  • <a href="#fd_readdir.bufused" name="fd_readdir.bufused"></a> bufused: size
    The number of bytes stored in the read buffer. If less than the size of the read buffer, the end of the directory has been reached.

    -
  • -
-
-

<a href="#fd_renumber" name="fd_renumber"></a> fd_renumber(fd: fd, to: fd) -> errno

-

Atomically replace a file descriptor by renumbering another file descriptor.
Due to the strong focus on thread safety, this environment does not provide
a mechanism to duplicate or renumber a file descriptor to an arbitrary
number, like dup2(). This would be prone to race conditions, as an actual
file descriptor with the same number could be allocated by a different
thread at the same time.
This function provides a way to atomically renumber file descriptors, which
would disappear if dup2() were to be removed entirely.

-
Params
-
    -
  • <a href="#fd_renumber.fd" name="fd_renumber.fd"></a> fd: fd

    -
  • -
  • <a href="#fd_renumber.to" name="fd_renumber.to"></a> to: fd
    The file descriptor to overwrite.

    -
  • -
-
Results
-
    -
  • <a href="#fd_renumber.error" name="fd_renumber.error"></a> error: errno
  • -
-
-

<a href="#fd_seek" name="fd_seek"></a> fd_seek(fd: fd, offset: filedelta, whence: whence) -> (errno, filesize)

-

Move the offset of a file descriptor.
Note: This is similar to lseek in POSIX.

-
Params
-
    -
  • <a href="#fd_seek.fd" name="fd_seek.fd"></a> fd: fd

    -
  • -
  • <a href="#fd_seek.offset" name="fd_seek.offset"></a> offset: filedelta
    The number of bytes to move.

    -
  • -
  • <a href="#fd_seek.whence" name="fd_seek.whence"></a> whence: whence
    The base from which the offset is relative.

    -
  • -
-
Results
-
    -
  • <a href="#fd_seek.error" name="fd_seek.error"></a> error: errno

    -
  • -
  • <a href="#fd_seek.newoffset" name="fd_seek.newoffset"></a> newoffset: filesize
    The new offset of the file descriptor, relative to the start of the file.

    -
  • -
-
-

<a href="#fd_sync" name="fd_sync"></a> fd_sync(fd: fd) -> errno

-

Synchronize the data and metadata of a file to disk.
Note: This is similar to fsync in POSIX.

-
Params
-
    -
  • <a href="#fd_sync.fd" name="fd_sync.fd"></a> fd: fd
  • -
-
Results
-
    -
  • <a href="#fd_sync.error" name="fd_sync.error"></a> error: errno
  • -
-
-

<a href="#fd_tell" name="fd_tell"></a> fd_tell(fd: fd) -> (errno, filesize)

-

Return the current offset of a file descriptor.
Note: This is similar to lseek(fd, 0, SEEK_CUR) in POSIX.

-
Params
-
    -
  • <a href="#fd_tell.fd" name="fd_tell.fd"></a> fd: fd
  • -
-
Results
-
    -
  • <a href="#fd_tell.error" name="fd_tell.error"></a> error: errno

    -
  • -
  • <a href="#fd_tell.offset" name="fd_tell.offset"></a> offset: filesize
    The current offset of the file descriptor, relative to the start of the file.

    -
  • -
-
-

<a href="#fd_write" name="fd_write"></a> fd_write(fd: fd, iovs: ciovec_array) -> (errno, size)

-

Write to a file descriptor.
Note: This is similar to writev in POSIX.

-
Params
-
    -
  • <a href="#fd_write.fd" name="fd_write.fd"></a> fd: fd

    -
  • -
  • <a href="#fd_write.iovs" name="fd_write.iovs"></a> iovs: ciovec_array
    List of scatter/gather vectors from which to retrieve data.

    -
  • -
-
Results
-
    -
  • <a href="#fd_write.error" name="fd_write.error"></a> error: errno

    -
  • -
  • <a href="#fd_write.nwritten" name="fd_write.nwritten"></a> nwritten: size
    The number of bytes written.

    -
  • -
-
-

<a href="#path_create_directory" name="path_create_directory"></a> path_create_directory(fd: fd, path: string) -> errno

-

Create a directory.
Note: This is similar to mkdirat in POSIX.

-
Params
-
    -
  • <a href="#path_create_directory.fd" name="path_create_directory.fd"></a> fd: fd

    -
  • -
  • <a href="#path_create_directory.path" name="path_create_directory.path"></a> path: string
    The path at which to create the directory.

    -
  • -
-
Results
-
    -
  • <a href="#path_create_directory.error" name="path_create_directory.error"></a> error: errno
  • -
-
-

<a href="#path_filestat_get" name="path_filestat_get"></a> path_filestat_get(fd: fd, flags: lookupflags, path: string) -> (errno, filestat)

-

Return the attributes of a file or directory.
Note: This is similar to stat in POSIX.

-
Params
-
    -
  • <a href="#path_filestat_get.fd" name="path_filestat_get.fd"></a> fd: fd

    -
  • -
  • <a href="#path_filestat_get.flags" name="path_filestat_get.flags"></a> flags: lookupflags
    Flags determining the method of how the path is resolved.

    -
  • -
  • <a href="#path_filestat_get.path" name="path_filestat_get.path"></a> path: string
    The path of the file or directory to inspect.

    -
  • -
-
Results
-
    -
  • <a href="#path_filestat_get.error" name="path_filestat_get.error"></a> error: errno

    -
  • -
  • <a href="#path_filestat_get.buf" name="path_filestat_get.buf"></a> buf: filestat
    The buffer where the file's attributes are stored.

    -
  • -
-
-

<a href="#path_filestat_set_times" name="path_filestat_set_times"></a> path_filestat_set_times(fd: fd, flags: lookupflags, path: string, atim: timestamp, mtim: timestamp, fst_flags: fstflags) -> errno

-

Adjust the timestamps of a file or directory.
Note: This is similar to utimensat in POSIX.

-
Params
-
    -
  • <a href="#path_filestat_set_times.fd" name="path_filestat_set_times.fd"></a> fd: fd

    -
  • -
  • <a href="#path_filestat_set_times.flags" name="path_filestat_set_times.flags"></a> flags: lookupflags
    Flags determining the method of how the path is resolved.

    -
  • -
  • <a href="#path_filestat_set_times.path" name="path_filestat_set_times.path"></a> path: string
    The path of the file or directory to operate on.

    -
  • -
  • <a href="#path_filestat_set_times.atim" name="path_filestat_set_times.atim"></a> atim: timestamp
    The desired values of the data access timestamp.

    -
  • -
  • <a href="#path_filestat_set_times.mtim" name="path_filestat_set_times.mtim"></a> mtim: timestamp
    The desired values of the data modification timestamp.

    -
  • -
  • <a href="#path_filestat_set_times.fst_flags" name="path_filestat_set_times.fst_flags"></a> fst_flags: fstflags
    A bitmask indicating which timestamps to adjust.

    -
  • -
-
Results
-
    -
  • <a href="#path_filestat_set_times.error" name="path_filestat_set_times.error"></a> error: errno
  • -
-
- -

Create a hard link.
Note: This is similar to linkat in POSIX.

-
Params
-
    -
  • <a href="#path_link.old_fd" name="path_link.old_fd"></a> old_fd: fd

    -
  • -
  • <a href="#path_link.old_flags" name="path_link.old_flags"></a> old_flags: lookupflags
    Flags determining the method of how the path is resolved.

    -
  • -
  • <a href="#path_link.old_path" name="path_link.old_path"></a> old_path: string
    The source path from which to link.

    -
  • -
  • <a href="#path_link.new_fd" name="path_link.new_fd"></a> new_fd: fd
    The working directory at which the resolution of the new path starts.

    -
  • -
  • <a href="#path_link.new_path" name="path_link.new_path"></a> new_path: string
    The destination path at which to create the hard link.

    -
  • -
-
Results
-
    -
  • <a href="#path_link.error" name="path_link.error"></a> error: errno
  • -
-
-

<a href="#path_open" name="path_open"></a> path_open(fd: fd, dirflags: lookupflags, path: string, oflags: oflags, fs_rights_base: rights, fs_rights_inheriting: rights, fdflags: fdflags) -> (errno, fd)

-

Open a file or directory.
The returned file descriptor is not guaranteed to be the lowest-numbered
file descriptor not currently open; it is randomized to prevent
applications from depending on making assumptions about indexes, since this
is error-prone in multi-threaded contexts. The returned file descriptor is
guaranteed to be less than 2**31.
Note: This is similar to openat in POSIX.

-
Params
-
    -
  • <a href="#path_open.fd" name="path_open.fd"></a> fd: fd

    -
  • -
  • <a href="#path_open.dirflags" name="path_open.dirflags"></a> dirflags: lookupflags
    Flags determining the method of how the path is resolved.

    -
  • -
  • <a href="#path_open.path" name="path_open.path"></a> path: string
    The relative path of the file or directory to open, relative to the
    path_open::fd directory.

    -
  • -
  • <a href="#path_open.oflags" name="path_open.oflags"></a> oflags: oflags
    The method by which to open the file.

    -
  • -
  • <a href="#path_open.fs_rights_base" name="path_open.fs_rights_base"></a> fs_rights_base: rights
    The initial rights of the newly created file descriptor. The
    implementation is allowed to return a file descriptor with fewer rights
    than specified, if and only if those rights do not apply to the type of
    file being opened.
    The base rights are rights that will apply to operations using the file
    descriptor itself, while the inheriting rights are rights that apply to
    file descriptors derived from it.

    -
  • -
  • <a href="#path_open.fs_rights_inheriting" name="path_open.fs_rights_inheriting"></a> fs_rights_inheriting: rights

    -
  • -
  • <a href="#path_open.fdflags" name="path_open.fdflags"></a> fdflags: fdflags

    -
  • -
-
Results
-
    -
  • <a href="#path_open.error" name="path_open.error"></a> error: errno

    -
  • -
  • <a href="#path_open.opened_fd" name="path_open.opened_fd"></a> opened_fd: fd
    The file descriptor of the file that has been opened.

    -
  • -
-
- -

Read the contents of a symbolic link.
Note: This is similar to readlinkat in POSIX.

-
Params
-
    -
  • <a href="#path_readlink.fd" name="path_readlink.fd"></a> fd: fd

    -
  • -
  • <a href="#path_readlink.path" name="path_readlink.path"></a> path: string
    The path of the symbolic link from which to read.

    -
  • -
  • <a href="#path_readlink.buf" name="path_readlink.buf"></a> buf: Pointer<u8>
    The buffer to which to write the contents of the symbolic link.

    -
  • -
  • <a href="#path_readlink.buf_len" name="path_readlink.buf_len"></a> buf_len: size

    -
  • -
-
Results
-
    -
  • <a href="#path_readlink.error" name="path_readlink.error"></a> error: errno

    -
  • -
  • <a href="#path_readlink.bufused" name="path_readlink.bufused"></a> bufused: size
    The number of bytes placed in the buffer.

    -
  • -
-
-

<a href="#path_remove_directory" name="path_remove_directory"></a> path_remove_directory(fd: fd, path: string) -> errno

-

Remove a directory.
Return errno::notempty if the directory is not empty.
Note: This is similar to unlinkat(fd, path, AT_REMOVEDIR) in POSIX.

-
Params
-
    -
  • <a href="#path_remove_directory.fd" name="path_remove_directory.fd"></a> fd: fd

    -
  • -
  • <a href="#path_remove_directory.path" name="path_remove_directory.path"></a> path: string
    The path to a directory to remove.

    -
  • -
-
Results
-
    -
  • <a href="#path_remove_directory.error" name="path_remove_directory.error"></a> error: errno
  • -
-
-

<a href="#path_rename" name="path_rename"></a> path_rename(fd: fd, old_path: string, new_fd: fd, new_path: string) -> errno

-

Rename a file or directory.
Note: This is similar to renameat in POSIX.

-
Params
-
    -
  • <a href="#path_rename.fd" name="path_rename.fd"></a> fd: fd

    -
  • -
  • <a href="#path_rename.old_path" name="path_rename.old_path"></a> old_path: string
    The source path of the file or directory to rename.

    -
  • -
  • <a href="#path_rename.new_fd" name="path_rename.new_fd"></a> new_fd: fd
    The working directory at which the resolution of the new path starts.

    -
  • -
  • <a href="#path_rename.new_path" name="path_rename.new_path"></a> new_path: string
    The destination path to which to rename the file or directory.

    -
  • -
-
Results
-
    -
  • <a href="#path_rename.error" name="path_rename.error"></a> error: errno
  • -
-
- -

Create a symbolic link.
Note: This is similar to symlinkat in POSIX.

-
Params
-
    -
  • <a href="#path_symlink.old_path" name="path_symlink.old_path"></a> old_path: string
    The contents of the symbolic link.

    -
  • -
  • <a href="#path_symlink.fd" name="path_symlink.fd"></a> fd: fd

    -
  • -
  • <a href="#path_symlink.new_path" name="path_symlink.new_path"></a> new_path: string
    The destination path at which to create the symbolic link.

    -
  • -
-
Results
-
    -
  • <a href="#path_symlink.error" name="path_symlink.error"></a> error: errno
  • -
-
- -

Unlink a file.
Return errno::isdir if the path refers to a directory.
Note: This is similar to unlinkat(fd, path, 0) in POSIX.

-
Params
-
    -
  • <a href="#path_unlink_file.fd" name="path_unlink_file.fd"></a> fd: fd

    -
  • -
  • <a href="#path_unlink_file.path" name="path_unlink_file.path"></a> path: string
    The path to a file to unlink.

    -
  • -
-
Results
-
    -
  • <a href="#path_unlink_file.error" name="path_unlink_file.error"></a> error: errno
  • -
-
-

<a href="#poll_oneoff" name="poll_oneoff"></a> poll_oneoff(in: ConstPointer<subscription>, out: Pointer<event>, nsubscriptions: size) -> (errno, size)

-

Concurrently poll for the occurrence of a set of events.

-
Params
-
    -
  • <a href="#poll_oneoff.in" name="poll_oneoff.in"></a> in: ConstPointer<subscription>
    The events to which to subscribe.

    -
  • -
  • <a href="#poll_oneoff.out" name="poll_oneoff.out"></a> out: Pointer<event>
    The events that have occurred.

    -
  • -
  • <a href="#poll_oneoff.nsubscriptions" name="poll_oneoff.nsubscriptions"></a> nsubscriptions: size
    Both the number of subscriptions and events.

    -
  • -
-
Results
-
    -
  • <a href="#poll_oneoff.error" name="poll_oneoff.error"></a> error: errno

    -
  • -
  • <a href="#poll_oneoff.nevents" name="poll_oneoff.nevents"></a> nevents: size
    The number of events stored.

    -
  • -
-
-

<a href="#proc_exit" name="proc_exit"></a> proc_exit(rval: exitcode)

-

Terminate the process normally. An exit code of 0 indicates successful
termination of the program. The meanings of other values is dependent on
the environment.

-
Params
-
    -
  • <a href="#proc_exit.rval" name="proc_exit.rval"></a> rval: exitcode
    The exit code returned by the process.
  • -
-
Results
-
-

<a href="#proc_raise" name="proc_raise"></a> proc_raise(sig: signal) -> errno

-

Send a signal to the process of the calling thread.
Note: This is similar to raise in POSIX.

-
Params
-
    -
  • <a href="#proc_raise.sig" name="proc_raise.sig"></a> sig: signal
    The signal condition to trigger.
  • -
-
Results
-
    -
  • <a href="#proc_raise.error" name="proc_raise.error"></a> error: errno
  • -
-
-

<a href="#sched_yield" name="sched_yield"></a> sched_yield() -> errno

-

Temporarily yield execution of the calling thread.
Note: This is similar to sched_yield in POSIX.

-
Params
-
Results
-
    -
  • <a href="#sched_yield.error" name="sched_yield.error"></a> error: errno
  • -
-
-

<a href="#random_get" name="random_get"></a> random_get(buf: Pointer<u8>, buf_len: size) -> errno

-

Write high-quality random data into a buffer.
This function blocks when the implementation is unable to immediately
provide sufficient high-quality random data.

-
Params
-
    -
  • <a href="#random_get.buf" name="random_get.buf"></a> buf: Pointer<u8>
    The buffer to fill with random data.

    -
  • -
  • <a href="#random_get.buf_len" name="random_get.buf_len"></a> buf_len: size

    -
  • -
-
Results
-
    -
  • <a href="#random_get.error" name="random_get.error"></a> error: errno
  • -
-
-

<a href="#sock_recv" name="sock_recv"></a> sock_recv(fd: fd, ri_data: iovec_array, ri_flags: riflags) -> (errno, size, roflags)

-

Receive a message from a socket.
Note: This is similar to recv in POSIX, though it also supports reading
the data into multiple buffers in the manner of readv.

-
Params
-
    -
  • <a href="#sock_recv.fd" name="sock_recv.fd"></a> fd: fd

    -
  • -
  • <a href="#sock_recv.ri_data" name="sock_recv.ri_data"></a> ri_data: iovec_array
    List of scatter/gather vectors to which to store data.

    -
  • -
  • <a href="#sock_recv.ri_flags" name="sock_recv.ri_flags"></a> ri_flags: riflags
    Message flags.

    -
  • -
-
Results
-
    -
  • <a href="#sock_recv.error" name="sock_recv.error"></a> error: errno

    -
  • -
  • <a href="#sock_recv.ro_datalen" name="sock_recv.ro_datalen"></a> ro_datalen: size
    Number of bytes stored in ri_data.

    -
  • -
  • <a href="#sock_recv.ro_flags" name="sock_recv.ro_flags"></a> ro_flags: roflags
    Message flags.

    -
  • -
-
-

<a href="#sock_send" name="sock_send"></a> sock_send(fd: fd, si_data: ciovec_array, si_flags: siflags) -> (errno, size)

-

Send a message on a socket.
Note: This is similar to send in POSIX, though it also supports writing
the data from multiple buffers in the manner of writev.

-
Params
-
    -
  • <a href="#sock_send.fd" name="sock_send.fd"></a> fd: fd

    -
  • -
  • <a href="#sock_send.si_data" name="sock_send.si_data"></a> si_data: ciovec_array
    List of scatter/gather vectors to which to retrieve data

    -
  • -
  • <a href="#sock_send.si_flags" name="sock_send.si_flags"></a> si_flags: siflags
    Message flags.

    -
  • -
-
Results
-
    -
  • <a href="#sock_send.error" name="sock_send.error"></a> error: errno

    -
  • -
  • <a href="#sock_send.so_datalen" name="sock_send.so_datalen"></a> so_datalen: size
    Number of bytes transmitted.

    -
  • -
-
-

<a href="#sock_shutdown" name="sock_shutdown"></a> sock_shutdown(fd: fd, how: sdflags) -> errno

-

Shut down socket send and receive channels.
Note: This is similar to shutdown in POSIX.

-
Params
-
    -
  • <a href="#sock_shutdown.fd" name="sock_shutdown.fd"></a> fd: fd

    -
  • -
  • <a href="#sock_shutdown.how" name="sock_shutdown.how"></a> how: sdflags
    Which channels on the socket to shut down.

    -
  • -
-
Results
-
    -
  • <a href="#sock_shutdown.error" name="sock_shutdown.error"></a> error: errno
  • -
diff --git a/legacy/preview1/docs.md b/legacy/preview1/docs.md deleted file mode 100644 index f39cedf60..000000000 --- a/legacy/preview1/docs.md +++ /dev/null @@ -1,2564 +0,0 @@ -# Types -## `size`: `u32` - -Size: 4 - -Alignment: 4 - -## `filesize`: `u64` -Non-negative file size or length of a region within a file. - -Size: 8 - -Alignment: 8 - -## `timestamp`: `u64` -Timestamp in nanoseconds. - -Size: 8 - -Alignment: 8 - -## `clockid`: `Variant` -Identifiers for clocks. - -Size: 4 - -Alignment: 4 - -### Variant cases -- `realtime` -The clock measuring real time. Time value zero corresponds with -1970-01-01T00:00:00Z. - -- `monotonic` -The store-wide monotonic clock, which is defined as a clock measuring -real time, whose value cannot be adjusted and which cannot have negative -clock jumps. The epoch of this clock is undefined. The absolute time -value of this clock therefore has no meaning. - -- `process_cputime_id` -The CPU-time clock associated with the current process. - -- `thread_cputime_id` -The CPU-time clock associated with the current thread. - -## `errno`: `Variant` -Error codes returned by functions. -Not all of these error codes are returned by the functions provided by this -API; some are used in higher-level library layers, and others are provided -merely for alignment with POSIX. - -Size: 2 - -Alignment: 2 - -### Variant cases -- `success` -No error occurred. System call completed successfully. - -- `2big` -Argument list too long. - -- `acces` -Permission denied. - -- `addrinuse` -Address in use. - -- `addrnotavail` -Address not available. - -- `afnosupport` -Address family not supported. - -- `again` -Resource unavailable, or operation would block. - -- `already` -Connection already in progress. - -- `badf` -Bad file descriptor. - -- `badmsg` -Bad message. - -- `busy` -Device or resource busy. - -- `canceled` -Operation canceled. - -- `child` -No child processes. - -- `connaborted` -Connection aborted. - -- `connrefused` -Connection refused. - -- `connreset` -Connection reset. - -- `deadlk` -Resource deadlock would occur. - -- `destaddrreq` -Destination address required. - -- `dom` -Mathematics argument out of domain of function. - -- `dquot` -Reserved. - -- `exist` -File exists. - -- `fault` -Bad address. - -- `fbig` -File too large. - -- `hostunreach` -Host is unreachable. - -- `idrm` -Identifier removed. - -- `ilseq` -Illegal byte sequence. - -- `inprogress` -Operation in progress. - -- `intr` -Interrupted function. - -- `inval` -Invalid argument. - -- `io` -I/O error. - -- `isconn` -Socket is connected. - -- `isdir` -Is a directory. - -- `loop` -Too many levels of symbolic links. - -- `mfile` -File descriptor value too large. - -- `mlink` -Too many links. - -- `msgsize` -Message too large. - -- `multihop` -Reserved. - -- `nametoolong` -Filename too long. - -- `netdown` -Network is down. - -- `netreset` -Connection aborted by network. - -- `netunreach` -Network unreachable. - -- `nfile` -Too many files open in system. - -- `nobufs` -No buffer space available. - -- `nodev` -No such device. - -- `noent` -No such file or directory. - -- `noexec` -Executable file format error. - -- `nolck` -No locks available. - -- `nolink` -Reserved. - -- `nomem` -Not enough space. - -- `nomsg` -No message of the desired type. - -- `noprotoopt` -Protocol not available. - -- `nospc` -No space left on device. - -- `nosys` -Function not supported. - -- `notconn` -The socket is not connected. - -- `notdir` -Not a directory or a symbolic link to a directory. - -- `notempty` -Directory not empty. - -- `notrecoverable` -State not recoverable. - -- `notsock` -Not a socket. - -- `notsup` -Not supported, or operation not supported on socket. - -- `notty` -Inappropriate I/O control operation. - -- `nxio` -No such device or address. - -- `overflow` -Value too large to be stored in data type. - -- `ownerdead` -Previous owner died. - -- `perm` -Operation not permitted. - -- `pipe` -Broken pipe. - -- `proto` -Protocol error. - -- `protonosupport` -Protocol not supported. - -- `prototype` -Protocol wrong type for socket. - -- `range` -Result too large. - -- `rofs` -Read-only file system. - -- `spipe` -Invalid seek. - -- `srch` -No such process. - -- `stale` -Reserved. - -- `timedout` -Connection timed out. - -- `txtbsy` -Text file busy. - -- `xdev` -Cross-device link. - -- `notcapable` -Extension: Capabilities insufficient. - -## `rights`: `Record` -File descriptor rights, determining which actions may be performed. - -Size: 8 - -Alignment: 8 - -### Record members -- `fd_datasync`: `bool` -The right to invoke [`fd_datasync`](#fd_datasync). -If [`path_open`](#path_open) is set, includes the right to invoke -[`path_open`](#path_open) with [`fdflags::dsync`](#fdflags.dsync). - -Bit: 0 - -- `fd_read`: `bool` -The right to invoke [`fd_read`](#fd_read) and [`sock_recv`](#sock_recv). -If [`rights::fd_seek`](#rights.fd_seek) is set, includes the right to invoke [`fd_pread`](#fd_pread). - -Bit: 1 - -- `fd_seek`: `bool` -The right to invoke [`fd_seek`](#fd_seek). This flag implies [`rights::fd_tell`](#rights.fd_tell). - -Bit: 2 - -- `fd_fdstat_set_flags`: `bool` -The right to invoke [`fd_fdstat_set_flags`](#fd_fdstat_set_flags). - -Bit: 3 - -- `fd_sync`: `bool` -The right to invoke [`fd_sync`](#fd_sync). -If [`path_open`](#path_open) is set, includes the right to invoke -[`path_open`](#path_open) with [`fdflags::rsync`](#fdflags.rsync) and [`fdflags::dsync`](#fdflags.dsync). - -Bit: 4 - -- `fd_tell`: `bool` -The right to invoke [`fd_seek`](#fd_seek) in such a way that the file offset -remains unaltered (i.e., [`whence::cur`](#whence.cur) with offset zero), or to -invoke [`fd_tell`](#fd_tell). - -Bit: 5 - -- `fd_write`: `bool` -The right to invoke [`fd_write`](#fd_write) and [`sock_send`](#sock_send). -If [`rights::fd_seek`](#rights.fd_seek) is set, includes the right to invoke [`fd_pwrite`](#fd_pwrite). - -Bit: 6 - -- `fd_advise`: `bool` -The right to invoke [`fd_advise`](#fd_advise). - -Bit: 7 - -- `fd_allocate`: `bool` -The right to invoke [`fd_allocate`](#fd_allocate). - -Bit: 8 - -- `path_create_directory`: `bool` -The right to invoke [`path_create_directory`](#path_create_directory). - -Bit: 9 - -- `path_create_file`: `bool` -If [`path_open`](#path_open) is set, the right to invoke [`path_open`](#path_open) with [`oflags::creat`](#oflags.creat). - -Bit: 10 - -- `path_link_source`: `bool` -The right to invoke [`path_link`](#path_link) with the file descriptor as the -source directory. - -Bit: 11 - -- `path_link_target`: `bool` -The right to invoke [`path_link`](#path_link) with the file descriptor as the -target directory. - -Bit: 12 - -- `path_open`: `bool` -The right to invoke [`path_open`](#path_open). - -Bit: 13 - -- `fd_readdir`: `bool` -The right to invoke [`fd_readdir`](#fd_readdir). - -Bit: 14 - -- `path_readlink`: `bool` -The right to invoke [`path_readlink`](#path_readlink). - -Bit: 15 - -- `path_rename_source`: `bool` -The right to invoke [`path_rename`](#path_rename) with the file descriptor as the source directory. - -Bit: 16 - -- `path_rename_target`: `bool` -The right to invoke [`path_rename`](#path_rename) with the file descriptor as the target directory. - -Bit: 17 - -- `path_filestat_get`: `bool` -The right to invoke [`path_filestat_get`](#path_filestat_get). - -Bit: 18 - -- `path_filestat_set_size`: `bool` -The right to change a file's size. -If [`path_open`](#path_open) is set, includes the right to invoke [`path_open`](#path_open) with [`oflags::trunc`](#oflags.trunc). -Note: there is no function named `path_filestat_set_size`. This follows POSIX design, -which only has `ftruncate` and does not provide `ftruncateat`. -While such function would be desirable from the API design perspective, there are virtually -no use cases for it since no code written for POSIX systems would use it. -Moreover, implementing it would require multiple syscalls, leading to inferior performance. - -Bit: 19 - -- `path_filestat_set_times`: `bool` -The right to invoke [`path_filestat_set_times`](#path_filestat_set_times). - -Bit: 20 - -- `fd_filestat_get`: `bool` -The right to invoke [`fd_filestat_get`](#fd_filestat_get). - -Bit: 21 - -- `fd_filestat_set_size`: `bool` -The right to invoke [`fd_filestat_set_size`](#fd_filestat_set_size). - -Bit: 22 - -- `fd_filestat_set_times`: `bool` -The right to invoke [`fd_filestat_set_times`](#fd_filestat_set_times). - -Bit: 23 - -- `path_symlink`: `bool` -The right to invoke [`path_symlink`](#path_symlink). - -Bit: 24 - -- `path_remove_directory`: `bool` -The right to invoke [`path_remove_directory`](#path_remove_directory). - -Bit: 25 - -- `path_unlink_file`: `bool` -The right to invoke [`path_unlink_file`](#path_unlink_file). - -Bit: 26 - -- `poll_fd_readwrite`: `bool` -If [`rights::fd_read`](#rights.fd_read) is set, includes the right to invoke [`poll_oneoff`](#poll_oneoff) to subscribe to [`eventtype::fd_read`](#eventtype.fd_read). -If [`rights::fd_write`](#rights.fd_write) is set, includes the right to invoke [`poll_oneoff`](#poll_oneoff) to subscribe to [`eventtype::fd_write`](#eventtype.fd_write). - -Bit: 27 - -- `sock_shutdown`: `bool` -The right to invoke [`sock_shutdown`](#sock_shutdown). - -Bit: 28 - -- `sock_accept`: `bool` -The right to invoke [`sock_accept`](#sock_accept). - -Bit: 29 - -## `fd`: `Handle` -A file descriptor handle. - -Size: 4 - -Alignment: 4 - -### Supertypes -## `iovec`: `Record` -A region of memory for scatter/gather reads. - -Size: 8 - -Alignment: 4 - -### Record members -- `buf`: `Pointer` -The address of the buffer to be filled. - -Offset: 0 - -- `buf_len`: [`size`](#size) -The length of the buffer to be filled. - -Offset: 4 - -## `ciovec`: `Record` -A region of memory for scatter/gather writes. - -Size: 8 - -Alignment: 4 - -### Record members -- `buf`: `ConstPointer` -The address of the buffer to be written. - -Offset: 0 - -- `buf_len`: [`size`](#size) -The length of the buffer to be written. - -Offset: 4 - -## `iovec_array`: `List` - -Size: 8 - -Alignment: 4 - -## `ciovec_array`: `List` - -Size: 8 - -Alignment: 4 - -## `filedelta`: `s64` -Relative offset within a file. - -Size: 8 - -Alignment: 8 - -## `whence`: `Variant` -The position relative to which to set the offset of the file descriptor. - -Size: 1 - -Alignment: 1 - -### Variant cases -- `set` -Seek relative to start-of-file. - -- `cur` -Seek relative to current position. - -- `end` -Seek relative to end-of-file. - -## `dircookie`: `u64` -A reference to the offset of a directory entry. - -The value 0 signifies the start of the directory. - -Size: 8 - -Alignment: 8 - -## `dirnamlen`: `u32` -The type for the [`dirent::d_namlen`](#dirent.d_namlen) field of [`dirent`](#dirent) struct. - -Size: 4 - -Alignment: 4 - -## `inode`: `u64` -File serial number that is unique within its file system. - -Size: 8 - -Alignment: 8 - -## `filetype`: `Variant` -The type of a file descriptor or file. - -Size: 1 - -Alignment: 1 - -### Variant cases -- `unknown` -The type of the file descriptor or file is unknown or is different from any of the other types specified. - -- `block_device` -The file descriptor or file refers to a block device inode. - -- `character_device` -The file descriptor or file refers to a character device inode. - -- `directory` -The file descriptor or file refers to a directory inode. - -- `regular_file` -The file descriptor or file refers to a regular file inode. - -- `socket_dgram` -The file descriptor or file refers to a datagram socket. - -- `socket_stream` -The file descriptor or file refers to a byte-stream socket. - -- `symbolic_link` -The file refers to a symbolic link inode. - -## `dirent`: `Record` -A directory entry. - -Size: 24 - -Alignment: 8 - -### Record members -- `d_next`: [`dircookie`](#dircookie) -The offset of the next directory entry stored in this directory. - -Offset: 0 - -- `d_ino`: [`inode`](#inode) -The serial number of the file referred to by this directory entry. - -Offset: 8 - -- `d_namlen`: [`dirnamlen`](#dirnamlen) -The length of the name of the directory entry. - -Offset: 16 - -- `d_type`: [`filetype`](#filetype) -The type of the file referred to by this directory entry. - -Offset: 20 - -## `advice`: `Variant` -File or memory access pattern advisory information. - -Size: 1 - -Alignment: 1 - -### Variant cases -- `normal` -The application has no advice to give on its behavior with respect to the specified data. - -- `sequential` -The application expects to access the specified data sequentially from lower offsets to higher offsets. - -- `random` -The application expects to access the specified data in a random order. - -- `willneed` -The application expects to access the specified data in the near future. - -- `dontneed` -The application expects that it will not access the specified data in the near future. - -- `noreuse` -The application expects to access the specified data once and then not reuse it thereafter. - -## `fdflags`: `Record` -File descriptor flags. - -Size: 2 - -Alignment: 2 - -### Record members -- `append`: `bool` -Append mode: Data written to the file is always appended to the file's end. - -Bit: 0 - -- `dsync`: `bool` -Write according to synchronized I/O data integrity completion. Only the data -stored in the file is synchronized. This feature is not available on all -platforms and therefore [`path_open`](#path_open) and other such functions which -accept [`fdflags`](#fdflags) may return [`errno.notsup`](#errno.notsup) in the -case that this flag is set. - -Bit: 1 - -- `nonblock`: `bool` -Non-blocking mode. - -Bit: 2 - -- `rsync`: `bool` -Synchronized read I/O operations. -This feature is not available on all platforms and therefore -[`path_open`](#path_open) and other such functions which accept -[`fdflags`](#fdflags) may return [`errno.notsup`](#errno.notsup) in the case -that this flag is set. - -Bit: 3 - -- `sync`: `bool` -Write according to synchronized I/O file integrity completion. In addition to -synchronizing the data stored in the file, the implementation may also -synchronously update the file's metadata. This feature is not available on all -platforms and therefore [`path_open`](#path_open) and other such functions which -accept [`fdflags`](#fdflags) may return [`errno.notsup`](#errno.notsup) in the -case that this flag is set. - -Bit: 4 - -## `fdstat`: `Record` -File descriptor attributes. - -Size: 24 - -Alignment: 8 - -### Record members -- `fs_filetype`: [`filetype`](#filetype) -File type. - -Offset: 0 - -- `fs_flags`: [`fdflags`](#fdflags) -File descriptor flags. - -Offset: 2 - -- `fs_rights_base`: [`rights`](#rights) -Rights that apply to this file descriptor. - -Offset: 8 - -- `fs_rights_inheriting`: [`rights`](#rights) -Maximum set of rights that may be installed on new file descriptors that -are created through this file descriptor, e.g., through [`path_open`](#path_open). - -Offset: 16 - -## `device`: `u64` -Identifier for a device containing a file system. Can be used in combination -with [`inode`](#inode) to uniquely identify a file or directory in the filesystem. - -Size: 8 - -Alignment: 8 - -## `fstflags`: `Record` -Which file time attributes to adjust. - -Size: 2 - -Alignment: 2 - -### Record members -- `atim`: `bool` -Adjust the last data access timestamp to the value stored in [`filestat::atim`](#filestat.atim). - -Bit: 0 - -- `atim_now`: `bool` -Adjust the last data access timestamp to the time of clock [`clockid::realtime`](#clockid.realtime). - -Bit: 1 - -- `mtim`: `bool` -Adjust the last data modification timestamp to the value stored in [`filestat::mtim`](#filestat.mtim). - -Bit: 2 - -- `mtim_now`: `bool` -Adjust the last data modification timestamp to the time of clock [`clockid::realtime`](#clockid.realtime). - -Bit: 3 - -## `lookupflags`: `Record` -Flags determining the method of how paths are resolved. - -Size: 4 - -Alignment: 4 - -### Record members -- `symlink_follow`: `bool` -As long as the resolved path corresponds to a symbolic link, it is expanded. - -Bit: 0 - -## `oflags`: `Record` -Open flags used by [`path_open`](#path_open). - -Size: 2 - -Alignment: 2 - -### Record members -- `creat`: `bool` -Create file if it does not exist. - -Bit: 0 - -- `directory`: `bool` -Fail if not a directory. - -Bit: 1 - -- `excl`: `bool` -Fail if file already exists. - -Bit: 2 - -- `trunc`: `bool` -Truncate file to size 0. - -Bit: 3 - -## `linkcount`: `u64` -Number of hard links to an inode. - -Size: 8 - -Alignment: 8 - -## `filestat`: `Record` -File attributes. - -Size: 64 - -Alignment: 8 - -### Record members -- `dev`: [`device`](#device) -Device ID of device containing the file. - -Offset: 0 - -- `ino`: [`inode`](#inode) -File serial number. - -Offset: 8 - -- `filetype`: [`filetype`](#filetype) -File type. - -Offset: 16 - -- `nlink`: [`linkcount`](#linkcount) -Number of hard links to the file. - -Offset: 24 - -- `size`: [`filesize`](#filesize) -For regular files, the file size in bytes. For symbolic links, the length in bytes of the pathname contained in the symbolic link. - -Offset: 32 - -- `atim`: [`timestamp`](#timestamp) -Last data access timestamp. - -Offset: 40 - -- `mtim`: [`timestamp`](#timestamp) -Last data modification timestamp. - -Offset: 48 - -- `ctim`: [`timestamp`](#timestamp) -Last file status change timestamp. - -Offset: 56 - -## `userdata`: `u64` -User-provided value that may be attached to objects that is retained when -extracted from the implementation. - -Size: 8 - -Alignment: 8 - -## `eventtype`: `Variant` -Type of a subscription to an event or its occurrence. - -Size: 1 - -Alignment: 1 - -### Variant cases -- `clock` -The time value of clock [`subscription_clock::id`](#subscription_clock.id) has -reached timestamp [`subscription_clock::timeout`](#subscription_clock.timeout). - -- `fd_read` -File descriptor [`subscription_fd_readwrite::file_descriptor`](#subscription_fd_readwrite.file_descriptor) has data -available for reading. This event always triggers for regular files. - -- `fd_write` -File descriptor [`subscription_fd_readwrite::file_descriptor`](#subscription_fd_readwrite.file_descriptor) has capacity -available for writing. This event always triggers for regular files. - -## `eventrwflags`: `Record` -The state of the file descriptor subscribed to with -[`eventtype::fd_read`](#eventtype.fd_read) or [`eventtype::fd_write`](#eventtype.fd_write). - -Size: 2 - -Alignment: 2 - -### Record members -- `fd_readwrite_hangup`: `bool` -The peer of this socket has closed or disconnected. - -Bit: 0 - -## `event_fd_readwrite`: `Record` -The contents of an [`event`](#event) when type is [`eventtype::fd_read`](#eventtype.fd_read) or -[`eventtype::fd_write`](#eventtype.fd_write). - -Size: 16 - -Alignment: 8 - -### Record members -- `nbytes`: [`filesize`](#filesize) -The number of bytes available for reading or writing. - -Offset: 0 - -- `flags`: [`eventrwflags`](#eventrwflags) -The state of the file descriptor. - -Offset: 8 - -## `event`: `Record` -An event that occurred. - -Size: 32 - -Alignment: 8 - -### Record members -- `userdata`: [`userdata`](#userdata) -User-provided value that got attached to [`subscription::userdata`](#subscription.userdata). - -Offset: 0 - -- `error`: [`errno`](#errno) -If non-zero, an error that occurred while processing the subscription request. - -Offset: 8 - -- `type`: [`eventtype`](#eventtype) -The type of event that occurred - -Offset: 10 - -- `fd_readwrite`: [`event_fd_readwrite`](#event_fd_readwrite) -The contents of the event, if it is an [`eventtype::fd_read`](#eventtype.fd_read) or -[`eventtype::fd_write`](#eventtype.fd_write). [`eventtype::clock`](#eventtype.clock) events ignore this field. - -Offset: 16 - -## `subclockflags`: `Record` -Flags determining how to interpret the timestamp provided in -[`subscription_clock::timeout`](#subscription_clock.timeout). - -Size: 2 - -Alignment: 2 - -### Record members -- `subscription_clock_abstime`: `bool` -If set, treat the timestamp provided in -[`subscription_clock::timeout`](#subscription_clock.timeout) as an absolute timestamp of clock -[`subscription_clock::id`](#subscription_clock.id). If clear, treat the timestamp -provided in [`subscription_clock::timeout`](#subscription_clock.timeout) relative to the -current time value of clock [`subscription_clock::id`](#subscription_clock.id). - -Bit: 0 - -## `subscription_clock`: `Record` -The contents of a [`subscription`](#subscription) when type is [`eventtype::clock`](#eventtype.clock). - -Size: 32 - -Alignment: 8 - -### Record members -- `id`: [`clockid`](#clockid) -The clock against which to compare the timestamp. - -Offset: 0 - -- `timeout`: [`timestamp`](#timestamp) -The absolute or relative timestamp. - -Offset: 8 - -- `precision`: [`timestamp`](#timestamp) -The amount of time that the implementation may wait additionally -to coalesce with other events. - -Offset: 16 - -- `flags`: [`subclockflags`](#subclockflags) -Flags specifying whether the timeout is absolute or relative - -Offset: 24 - -## `subscription_fd_readwrite`: `Record` -The contents of a [`subscription`](#subscription) when type is type is -[`eventtype::fd_read`](#eventtype.fd_read) or [`eventtype::fd_write`](#eventtype.fd_write). - -Size: 4 - -Alignment: 4 - -### Record members -- `file_descriptor`: [`fd`](#fd) -The file descriptor on which to wait for it to become ready for reading or writing. - -Offset: 0 - -## `subscription_u`: `Variant` -The contents of a [`subscription`](#subscription). - -Size: 40 - -Alignment: 8 - -### Variant Layout -- size: 40 -- align: 8 -- tag_size: 1 -### Variant cases -- `clock`: [`subscription_clock`](#subscription_clock) - -- `fd_read`: [`subscription_fd_readwrite`](#subscription_fd_readwrite) - -- `fd_write`: [`subscription_fd_readwrite`](#subscription_fd_readwrite) - -## `subscription`: `Record` -Subscription to an event. - -Size: 48 - -Alignment: 8 - -### Record members -- `userdata`: [`userdata`](#userdata) -User-provided value that is attached to the subscription in the -implementation and returned through [`event::userdata`](#event.userdata). - -Offset: 0 - -- `u`: [`subscription_u`](#subscription_u) -The type of the event to which to subscribe, and its contents - -Offset: 8 - -## `exitcode`: `u32` -Exit code generated by a process when exiting. - -Size: 4 - -Alignment: 4 - -## `signal`: `Variant` -Signal condition. - -Size: 1 - -Alignment: 1 - -### Variant cases -- `none` -No signal. Note that POSIX has special semantics for `kill(pid, 0)`, -so this value is reserved. - -- `hup` -Hangup. -Action: Terminates the process. - -- `int` -Terminate interrupt signal. -Action: Terminates the process. - -- `quit` -Terminal quit signal. -Action: Terminates the process. - -- `ill` -Illegal instruction. -Action: Terminates the process. - -- `trap` -Trace/breakpoint trap. -Action: Terminates the process. - -- `abrt` -Process abort signal. -Action: Terminates the process. - -- `bus` -Access to an undefined portion of a memory object. -Action: Terminates the process. - -- `fpe` -Erroneous arithmetic operation. -Action: Terminates the process. - -- `kill` -Kill. -Action: Terminates the process. - -- `usr1` -User-defined signal 1. -Action: Terminates the process. - -- `segv` -Invalid memory reference. -Action: Terminates the process. - -- `usr2` -User-defined signal 2. -Action: Terminates the process. - -- `pipe` -Write on a pipe with no one to read it. -Action: Ignored. - -- `alrm` -Alarm clock. -Action: Terminates the process. - -- `term` -Termination signal. -Action: Terminates the process. - -- `chld` -Child process terminated, stopped, or continued. -Action: Ignored. - -- `cont` -Continue executing, if stopped. -Action: Continues executing, if stopped. - -- `stop` -Stop executing. -Action: Stops executing. - -- `tstp` -Terminal stop signal. -Action: Stops executing. - -- `ttin` -Background process attempting read. -Action: Stops executing. - -- `ttou` -Background process attempting write. -Action: Stops executing. - -- `urg` -High bandwidth data is available at a socket. -Action: Ignored. - -- `xcpu` -CPU time limit exceeded. -Action: Terminates the process. - -- `xfsz` -File size limit exceeded. -Action: Terminates the process. - -- `vtalrm` -Virtual timer expired. -Action: Terminates the process. - -- `prof` -Profiling timer expired. -Action: Terminates the process. - -- `winch` -Window changed. -Action: Ignored. - -- `poll` -I/O possible. -Action: Terminates the process. - -- `pwr` -Power failure. -Action: Terminates the process. - -- `sys` -Bad system call. -Action: Terminates the process. - -## `riflags`: `Record` -Flags provided to [`sock_recv`](#sock_recv). - -Size: 2 - -Alignment: 2 - -### Record members -- `recv_peek`: `bool` -Returns the message without removing it from the socket's receive queue. - -Bit: 0 - -- `recv_waitall`: `bool` -On byte-stream sockets, block until the full amount of data can be returned. - -Bit: 1 - -## `roflags`: `Record` -Flags returned by [`sock_recv`](#sock_recv). - -Size: 2 - -Alignment: 2 - -### Record members -- `recv_data_truncated`: `bool` -Returned by [`sock_recv`](#sock_recv): Message data has been truncated. - -Bit: 0 - -## `siflags`: `u16` -Flags provided to [`sock_send`](#sock_send). As there are currently no flags -defined, it must be set to zero. - -Size: 2 - -Alignment: 2 - -## `sdflags`: `Record` -Which channels on a socket to shut down. - -Size: 1 - -Alignment: 1 - -### Record members -- `rd`: `bool` -Disables further receive operations. - -Bit: 0 - -- `wr`: `bool` -Disables further send operations. - -Bit: 1 - -## `preopentype`: `Variant` -Identifiers for preopened capabilities. - -Size: 1 - -Alignment: 1 - -### Variant cases -- `dir` -A pre-opened directory. - -## `prestat_dir`: `Record` -The contents of a $prestat when type is [`preopentype::dir`](#preopentype.dir). - -Size: 4 - -Alignment: 4 - -### Record members -- `pr_name_len`: [`size`](#size) -The length of the directory name for use with [`fd_prestat_dir_name`](#fd_prestat_dir_name). - -Offset: 0 - -## `prestat`: `Variant` -Information about a pre-opened capability. - -Size: 8 - -Alignment: 4 - -### Variant Layout -- size: 8 -- align: 4 -- tag_size: 1 -### Variant cases -- `dir`: [`prestat_dir`](#prestat_dir) - -# Modules -## wasi_snapshot_preview1 -### Imports -#### Memory -### Functions - ---- - -#### `args_get(argv: Pointer>, argv_buf: Pointer) -> Result<(), errno>` -Read command-line argument data. -The size of the array should match that returned by [`args_sizes_get`](#args_sizes_get). -Each argument is expected to be `\0` terminated. - -##### Params -- `argv`: `Pointer>` - -- `argv_buf`: `Pointer` - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `args_sizes_get() -> Result<(size, size), errno>` -Return command-line argument data sizes. - -##### Params -##### Results -- `error`: `Result<(size, size), errno>` -Returns the number of arguments and the size of the argument string -data, or an error. - -###### Variant Layout -- size: 12 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: `(size, size)` - -####### Record members -- `0`: [`size`](#size) - -Offset: 0 - -- `1`: [`size`](#size) - -Offset: 4 - -- `err`: [`errno`](#errno) - - ---- - -#### `environ_get(environ: Pointer>, environ_buf: Pointer) -> Result<(), errno>` -Read environment variable data. -The sizes of the buffers should match that returned by [`environ_sizes_get`](#environ_sizes_get). -Key/value pairs are expected to be joined with `=`s, and terminated with `\0`s. - -##### Params -- `environ`: `Pointer>` - -- `environ_buf`: `Pointer` - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `environ_sizes_get() -> Result<(size, size), errno>` -Return environment variable data sizes. - -##### Params -##### Results -- `error`: `Result<(size, size), errno>` -Returns the number of environment variable arguments and the size of the -environment variable data. - -###### Variant Layout -- size: 12 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: `(size, size)` - -####### Record members -- `0`: [`size`](#size) - -Offset: 0 - -- `1`: [`size`](#size) - -Offset: 4 - -- `err`: [`errno`](#errno) - - ---- - -#### `clock_res_get(id: clockid) -> Result` -Return the resolution of a clock. -Implementations are required to provide a non-zero value for supported clocks. For unsupported clocks, -return [`errno::inval`](#errno.inval). -Note: This is similar to `clock_getres` in POSIX. - -##### Params -- `id`: [`clockid`](#clockid) -The clock for which to return the resolution. - -##### Results -- `error`: `Result` -The resolution of the clock, or an error if one happened. - -###### Variant Layout -- size: 16 -- align: 8 -- tag_size: 4 -###### Variant cases -- `ok`: [`timestamp`](#timestamp) - -- `err`: [`errno`](#errno) - - ---- - -#### `clock_time_get(id: clockid, precision: timestamp) -> Result` -Return the time value of a clock. -Note: This is similar to `clock_gettime` in POSIX. - -##### Params -- `id`: [`clockid`](#clockid) -The clock for which to return the time. - -- `precision`: [`timestamp`](#timestamp) -The maximum lag (exclusive) that the returned time value may have, compared to its actual value. - -##### Results -- `error`: `Result` -The time value of the clock. - -###### Variant Layout -- size: 16 -- align: 8 -- tag_size: 4 -###### Variant cases -- `ok`: [`timestamp`](#timestamp) - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_advise(fd: fd, offset: filesize, len: filesize, advice: advice) -> Result<(), errno>` -Provide file advisory information on a file descriptor. -Note: This is similar to `posix_fadvise` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `offset`: [`filesize`](#filesize) -The offset within the file to which the advisory applies. - -- `len`: [`filesize`](#filesize) -The length of the region to which the advisory applies. - -- `advice`: [`advice`](#advice) -The advice. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_allocate(fd: fd, offset: filesize, len: filesize) -> Result<(), errno>` -Force the allocation of space in a file. -Note: This is similar to `posix_fallocate` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `offset`: [`filesize`](#filesize) -The offset at which to start the allocation. - -- `len`: [`filesize`](#filesize) -The length of the area that is allocated. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_close(fd: fd) -> Result<(), errno>` -Close a file descriptor. -Note: This is similar to `close` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_datasync(fd: fd) -> Result<(), errno>` -Synchronize the data of a file to disk. -Note: This is similar to `fdatasync` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_fdstat_get(fd: fd) -> Result` -Get the attributes of a file descriptor. -Note: This returns similar flags to `fcntl(fd, F_GETFL)` in POSIX, as well as additional fields. - -##### Params -- `fd`: [`fd`](#fd) - -##### Results -- `error`: `Result` -The buffer where the file descriptor's attributes are stored. - -###### Variant Layout -- size: 32 -- align: 8 -- tag_size: 4 -###### Variant cases -- `ok`: [`fdstat`](#fdstat) - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_fdstat_set_flags(fd: fd, flags: fdflags) -> Result<(), errno>` -Adjust the flags associated with a file descriptor. -Note: This is similar to `fcntl(fd, F_SETFL, flags)` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `flags`: [`fdflags`](#fdflags) -The desired values of the file descriptor flags. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_fdstat_set_rights(fd: fd, fs_rights_base: rights, fs_rights_inheriting: rights) -> Result<(), errno>` -Adjust the rights associated with a file descriptor. -This can only be used to remove rights, and returns [`errno::notcapable`](#errno.notcapable) if called in a way that would attempt to add rights - -##### Params -- `fd`: [`fd`](#fd) - -- `fs_rights_base`: [`rights`](#rights) -The desired rights of the file descriptor. - -- `fs_rights_inheriting`: [`rights`](#rights) - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_filestat_get(fd: fd) -> Result` -Return the attributes of an open file. - -##### Params -- `fd`: [`fd`](#fd) - -##### Results -- `error`: `Result` -The buffer where the file's attributes are stored. - -###### Variant Layout -- size: 72 -- align: 8 -- tag_size: 4 -###### Variant cases -- `ok`: [`filestat`](#filestat) - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_filestat_set_size(fd: fd, size: filesize) -> Result<(), errno>` -Adjust the size of an open file. If this increases the file's size, the extra bytes are filled with zeros. -Note: This is similar to `ftruncate` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `size`: [`filesize`](#filesize) -The desired file size. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_filestat_set_times(fd: fd, atim: timestamp, mtim: timestamp, fst_flags: fstflags) -> Result<(), errno>` -Adjust the timestamps of an open file or directory. -Note: This is similar to `futimens` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `atim`: [`timestamp`](#timestamp) -The desired values of the data access timestamp. - -- `mtim`: [`timestamp`](#timestamp) -The desired values of the data modification timestamp. - -- `fst_flags`: [`fstflags`](#fstflags) -A bitmask indicating which timestamps to adjust. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_pread(fd: fd, iovs: iovec_array, offset: filesize) -> Result` -Read from a file descriptor, without using and updating the file descriptor's offset. -Note: This is similar to `preadv` in Linux (and other Unix-es). - -##### Params -- `fd`: [`fd`](#fd) - -- `iovs`: [`iovec_array`](#iovec_array) -List of scatter/gather vectors in which to store data. - -- `offset`: [`filesize`](#filesize) -The offset within the file at which to read. - -##### Results -- `error`: `Result` -The number of bytes read. - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`size`](#size) - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_prestat_get(fd: fd) -> Result` -Return a description of the given preopened file descriptor. - -##### Params -- `fd`: [`fd`](#fd) - -##### Results -- `error`: `Result` -The buffer where the description is stored. - -###### Variant Layout -- size: 12 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`prestat`](#prestat) - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_prestat_dir_name(fd: fd, path: Pointer, path_len: size) -> Result<(), errno>` -Return a description of the given preopened file descriptor. - -##### Params -- `fd`: [`fd`](#fd) - -- `path`: `Pointer` -A buffer into which to write the preopened directory name. - -- `path_len`: [`size`](#size) - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_pwrite(fd: fd, iovs: ciovec_array, offset: filesize) -> Result` -Write to a file descriptor, without using and updating the file descriptor's offset. -Note: This is similar to `pwritev` in Linux (and other Unix-es). - -Like Linux (and other Unix-es), any calls of `pwrite` (and other -functions to read or write) for a regular file by other threads in the -WASI process should not be interleaved while `pwrite` is executed. - -##### Params -- `fd`: [`fd`](#fd) - -- `iovs`: [`ciovec_array`](#ciovec_array) -List of scatter/gather vectors from which to retrieve data. - -- `offset`: [`filesize`](#filesize) -The offset within the file at which to write. - -##### Results -- `error`: `Result` -The number of bytes written. - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`size`](#size) - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_read(fd: fd, iovs: iovec_array) -> Result` -Read from a file descriptor. -Note: This is similar to `readv` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `iovs`: [`iovec_array`](#iovec_array) -List of scatter/gather vectors to which to store data. - -##### Results -- `error`: `Result` -The number of bytes read. - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`size`](#size) - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_readdir(fd: fd, buf: Pointer, buf_len: size, cookie: dircookie) -> Result` -Read directory entries from a directory. -When successful, the contents of the output buffer consist of a sequence of -directory entries. Each directory entry consists of a [`dirent`](#dirent) object, -followed by [`dirent::d_namlen`](#dirent.d_namlen) bytes holding the name of the directory -entry. -This function fills the output buffer as much as possible, potentially -truncating the last directory entry. This allows the caller to grow its -read buffer size in case it's too small to fit a single large directory -entry, or skip the oversized directory entry. - -##### Params -- `fd`: [`fd`](#fd) - -- `buf`: `Pointer` -The buffer where directory entries are stored - -- `buf_len`: [`size`](#size) - -- `cookie`: [`dircookie`](#dircookie) -The location within the directory to start reading - -##### Results -- `error`: `Result` -The number of bytes stored in the read buffer. If less than the size of the read buffer, the end of the directory has been reached. - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`size`](#size) - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_renumber(fd: fd, to: fd) -> Result<(), errno>` -Atomically replace a file descriptor by renumbering another file descriptor. -Due to the strong focus on thread safety, this environment does not provide -a mechanism to duplicate or renumber a file descriptor to an arbitrary -number, like `dup2()`. This would be prone to race conditions, as an actual -file descriptor with the same number could be allocated by a different -thread at the same time. -This function provides a way to atomically renumber file descriptors, which -would disappear if `dup2()` were to be removed entirely. - -##### Params -- `fd`: [`fd`](#fd) - -- `to`: [`fd`](#fd) -The file descriptor to overwrite. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_seek(fd: fd, offset: filedelta, whence: whence) -> Result` -Move the offset of a file descriptor. -Note: This is similar to `lseek` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `offset`: [`filedelta`](#filedelta) -The number of bytes to move. - -- `whence`: [`whence`](#whence) -The base from which the offset is relative. - -##### Results -- `error`: `Result` -The new offset of the file descriptor, relative to the start of the file. - -###### Variant Layout -- size: 16 -- align: 8 -- tag_size: 4 -###### Variant cases -- `ok`: [`filesize`](#filesize) - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_sync(fd: fd) -> Result<(), errno>` -Synchronize the data and metadata of a file to disk. -Note: This is similar to `fsync` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_tell(fd: fd) -> Result` -Return the current offset of a file descriptor. -Note: This is similar to `lseek(fd, 0, SEEK_CUR)` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -##### Results -- `error`: `Result` -The current offset of the file descriptor, relative to the start of the file. - -###### Variant Layout -- size: 16 -- align: 8 -- tag_size: 4 -###### Variant cases -- `ok`: [`filesize`](#filesize) - -- `err`: [`errno`](#errno) - - ---- - -#### `fd_write(fd: fd, iovs: ciovec_array) -> Result` -Write to a file descriptor. -Note: This is similar to `writev` in POSIX. - -Like POSIX, any calls of `write` (and other functions to read or write) -for a regular file by other threads in the WASI process should not be -interleaved while `write` is executed. - -##### Params -- `fd`: [`fd`](#fd) - -- `iovs`: [`ciovec_array`](#ciovec_array) -List of scatter/gather vectors from which to retrieve data. - -##### Results -- `error`: `Result` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`size`](#size) - -- `err`: [`errno`](#errno) - - ---- - -#### `path_create_directory(fd: fd, path: string) -> Result<(), errno>` -Create a directory. -Note: This is similar to `mkdirat` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `path`: `string` -The path at which to create the directory. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `path_filestat_get(fd: fd, flags: lookupflags, path: string) -> Result` -Return the attributes of a file or directory. -Note: This is similar to `stat` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `flags`: [`lookupflags`](#lookupflags) -Flags determining the method of how the path is resolved. - -- `path`: `string` -The path of the file or directory to inspect. - -##### Results -- `error`: `Result` -The buffer where the file's attributes are stored. - -###### Variant Layout -- size: 72 -- align: 8 -- tag_size: 4 -###### Variant cases -- `ok`: [`filestat`](#filestat) - -- `err`: [`errno`](#errno) - - ---- - -#### `path_filestat_set_times(fd: fd, flags: lookupflags, path: string, atim: timestamp, mtim: timestamp, fst_flags: fstflags) -> Result<(), errno>` -Adjust the timestamps of a file or directory. -Note: This is similar to `utimensat` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `flags`: [`lookupflags`](#lookupflags) -Flags determining the method of how the path is resolved. - -- `path`: `string` -The path of the file or directory to operate on. - -- `atim`: [`timestamp`](#timestamp) -The desired values of the data access timestamp. - -- `mtim`: [`timestamp`](#timestamp) -The desired values of the data modification timestamp. - -- `fst_flags`: [`fstflags`](#fstflags) -A bitmask indicating which timestamps to adjust. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `path_link(old_fd: fd, old_flags: lookupflags, old_path: string, new_fd: fd, new_path: string) -> Result<(), errno>` -Create a hard link. -Note: This is similar to `linkat` in POSIX. - -##### Params -- `old_fd`: [`fd`](#fd) - -- `old_flags`: [`lookupflags`](#lookupflags) -Flags determining the method of how the path is resolved. - -- `old_path`: `string` -The source path from which to link. - -- `new_fd`: [`fd`](#fd) -The working directory at which the resolution of the new path starts. - -- `new_path`: `string` -The destination path at which to create the hard link. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `path_open(fd: fd, dirflags: lookupflags, path: string, oflags: oflags, fs_rights_base: rights, fs_rights_inheriting: rights, fdflags: fdflags) -> Result` -Open a file or directory. -The returned file descriptor is not guaranteed to be the lowest-numbered -file descriptor not currently open; it is randomized to prevent -applications from depending on making assumptions about indexes, since this -is error-prone in multi-threaded contexts. The returned file descriptor is -guaranteed to be less than 2**31. -Note: This is similar to `openat` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `dirflags`: [`lookupflags`](#lookupflags) -Flags determining the method of how the path is resolved. - -- `path`: `string` -The relative path of the file or directory to open, relative to the -[`path_open::fd`](#path_open.fd) directory. - -- `oflags`: [`oflags`](#oflags) -The method by which to open the file. - -- `fs_rights_base`: [`rights`](#rights) -The initial rights of the newly created file descriptor. The -implementation is allowed to return a file descriptor with fewer rights -than specified, if and only if those rights do not apply to the type of -file being opened. -The *base* rights are rights that will apply to operations using the file -descriptor itself, while the *inheriting* rights are rights that apply to -file descriptors derived from it. - -- `fs_rights_inheriting`: [`rights`](#rights) - -- `fdflags`: [`fdflags`](#fdflags) - -##### Results -- `error`: `Result` -The file descriptor of the file that has been opened. - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`fd`](#fd) - -- `err`: [`errno`](#errno) - - ---- - -#### `path_readlink(fd: fd, path: string, buf: Pointer, buf_len: size) -> Result` -Read the contents of a symbolic link. -Note: This is similar to `readlinkat` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `path`: `string` -The path of the symbolic link from which to read. - -- `buf`: `Pointer` -The buffer to which to write the contents of the symbolic link. - -- `buf_len`: [`size`](#size) - -##### Results -- `error`: `Result` -The number of bytes placed in the buffer. - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`size`](#size) - -- `err`: [`errno`](#errno) - - ---- - -#### `path_remove_directory(fd: fd, path: string) -> Result<(), errno>` -Remove a directory. -Return [`errno::notempty`](#errno.notempty) if the directory is not empty. -Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `path`: `string` -The path to a directory to remove. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `path_rename(fd: fd, old_path: string, new_fd: fd, new_path: string) -> Result<(), errno>` -Rename a file or directory. -Note: This is similar to `renameat` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `old_path`: `string` -The source path of the file or directory to rename. - -- `new_fd`: [`fd`](#fd) -The working directory at which the resolution of the new path starts. - -- `new_path`: `string` -The destination path to which to rename the file or directory. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `path_symlink(old_path: string, fd: fd, new_path: string) -> Result<(), errno>` -Create a symbolic link. -Note: This is similar to `symlinkat` in POSIX. - -##### Params -- `old_path`: `string` -The contents of the symbolic link. - -- `fd`: [`fd`](#fd) - -- `new_path`: `string` -The destination path at which to create the symbolic link. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `path_unlink_file(fd: fd, path: string) -> Result<(), errno>` -Unlink a file. -Return [`errno::isdir`](#errno.isdir) if the path refers to a directory. -Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `path`: `string` -The path to a file to unlink. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `poll_oneoff(in: ConstPointer, out: Pointer, nsubscriptions: size) -> Result` -Concurrently poll for the occurrence of a set of events. - -If `nsubscriptions` is 0, returns [`errno::inval`](#errno.inval). - -##### Params -- `in`: `ConstPointer` -The events to which to subscribe. - -- `out`: `Pointer` -The events that have occurred. - -- `nsubscriptions`: [`size`](#size) -Both the number of subscriptions and events. - -##### Results -- `error`: `Result` -The number of events stored. - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`size`](#size) - -- `err`: [`errno`](#errno) - - ---- - -#### `proc_exit(rval: exitcode)` -Terminate the process normally. An exit code of 0 indicates successful -termination of the program. The meanings of other values is dependent on -the environment. - -##### Params -- `rval`: [`exitcode`](#exitcode) -The exit code returned by the process. - -##### Results - ---- - -#### `proc_raise(sig: signal) -> Result<(), errno>` -Send a signal to the process of the calling thread. -Note: This is similar to `raise` in POSIX. - -##### Params -- `sig`: [`signal`](#signal) -The signal condition to trigger. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `sched_yield() -> Result<(), errno>` -Temporarily yield execution of the calling thread. -Note: This is similar to [`sched_yield`](#sched_yield) in POSIX. - -##### Params -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `random_get(buf: Pointer, buf_len: size) -> Result<(), errno>` -Write high-quality random data into a buffer. -This function blocks when the implementation is unable to immediately -provide sufficient high-quality random data. - -##### Params -- `buf`: `Pointer` -The buffer to fill with random data. - -- `buf_len`: [`size`](#size) - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - - ---- - -#### `sock_accept(fd: fd, flags: fdflags) -> Result` -Accept a new incoming connection. -Note: This is similar to `accept` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) -The listening socket. - -- `flags`: [`fdflags`](#fdflags) -The desired values of the file descriptor flags. - -##### Results -- `error`: `Result` -New socket connection - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`fd`](#fd) - -- `err`: [`errno`](#errno) - - ---- - -#### `sock_recv(fd: fd, ri_data: iovec_array, ri_flags: riflags) -> Result<(size, roflags), errno>` -Receive a message from a socket. -Note: This is similar to `recv` in POSIX, though it also supports reading -the data into multiple buffers in the manner of `readv`. - -##### Params -- `fd`: [`fd`](#fd) - -- `ri_data`: [`iovec_array`](#iovec_array) -List of scatter/gather vectors to which to store data. - -- `ri_flags`: [`riflags`](#riflags) -Message flags. - -##### Results -- `error`: `Result<(size, roflags), errno>` -Number of bytes stored in ri_data and message flags. - -###### Variant Layout -- size: 12 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: `(size, roflags)` - -####### Record members -- `0`: [`size`](#size) - -Offset: 0 - -- `1`: [`roflags`](#roflags) - -Offset: 4 - -- `err`: [`errno`](#errno) - - ---- - -#### `sock_send(fd: fd, si_data: ciovec_array, si_flags: siflags) -> Result` -Send a message on a socket. -Note: This is similar to `send` in POSIX, though it also supports writing -the data from multiple buffers in the manner of `writev`. - -##### Params -- `fd`: [`fd`](#fd) - -- `si_data`: [`ciovec_array`](#ciovec_array) -List of scatter/gather vectors to which to retrieve data - -- `si_flags`: [`siflags`](#siflags) -Message flags. - -##### Results -- `error`: `Result` -Number of bytes transmitted. - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok`: [`size`](#size) - -- `err`: [`errno`](#errno) - - ---- - -#### `sock_shutdown(fd: fd, how: sdflags) -> Result<(), errno>` -Shut down socket send and receive channels. -Note: This is similar to `shutdown` in POSIX. - -##### Params -- `fd`: [`fd`](#fd) - -- `how`: [`sdflags`](#sdflags) -Which channels on the socket to shut down. - -##### Results -- `error`: `Result<(), errno>` - -###### Variant Layout -- size: 8 -- align: 4 -- tag_size: 4 -###### Variant cases -- `ok` - -- `err`: [`errno`](#errno) - diff --git a/legacy/preview1/witx/typenames.witx b/legacy/preview1/witx/typenames.witx deleted file mode 100644 index 6545c98b5..000000000 --- a/legacy/preview1/witx/typenames.witx +++ /dev/null @@ -1,761 +0,0 @@ -;; Type names used by low-level WASI interfaces. -;; -;; Some content here is derived from [CloudABI](https://github.com/NuxiNL/cloudabi). -;; -;; This is a `witx` file. See [here](https://github.com/WebAssembly/WASI/blob/main/legacy/tools/witx-docs.md) -;; for an explanation of what that means. - -(typename $size u32) - -;;; Non-negative file size or length of a region within a file. -(typename $filesize u64) - -;;; Timestamp in nanoseconds. -(typename $timestamp u64) - -;;; Identifiers for clocks. -(typename $clockid - (enum (@witx tag u32) - ;;; The clock measuring real time. Time value zero corresponds with - ;;; 1970-01-01T00:00:00Z. - $realtime - ;;; The store-wide monotonic clock, which is defined as a clock measuring - ;;; real time, whose value cannot be adjusted and which cannot have negative - ;;; clock jumps. The epoch of this clock is undefined. The absolute time - ;;; value of this clock therefore has no meaning. - $monotonic - ;;; The CPU-time clock associated with the current process. - $process_cputime_id - ;;; The CPU-time clock associated with the current thread. - $thread_cputime_id - ) -) - -;;; Error codes returned by functions. -;;; Not all of these error codes are returned by the functions provided by this -;;; API; some are used in higher-level library layers, and others are provided -;;; merely for alignment with POSIX. -(typename $errno - (enum (@witx tag u16) - ;;; No error occurred. System call completed successfully. - $success - ;;; Argument list too long. - $2big - ;;; Permission denied. - $acces - ;;; Address in use. - $addrinuse - ;;; Address not available. - $addrnotavail - ;;; Address family not supported. - $afnosupport - ;;; Resource unavailable, or operation would block. - $again - ;;; Connection already in progress. - $already - ;;; Bad file descriptor. - $badf - ;;; Bad message. - $badmsg - ;;; Device or resource busy. - $busy - ;;; Operation canceled. - $canceled - ;;; No child processes. - $child - ;;; Connection aborted. - $connaborted - ;;; Connection refused. - $connrefused - ;;; Connection reset. - $connreset - ;;; Resource deadlock would occur. - $deadlk - ;;; Destination address required. - $destaddrreq - ;;; Mathematics argument out of domain of function. - $dom - ;;; Reserved. - $dquot - ;;; File exists. - $exist - ;;; Bad address. - $fault - ;;; File too large. - $fbig - ;;; Host is unreachable. - $hostunreach - ;;; Identifier removed. - $idrm - ;;; Illegal byte sequence. - $ilseq - ;;; Operation in progress. - $inprogress - ;;; Interrupted function. - $intr - ;;; Invalid argument. - $inval - ;;; I/O error. - $io - ;;; Socket is connected. - $isconn - ;;; Is a directory. - $isdir - ;;; Too many levels of symbolic links. - $loop - ;;; File descriptor value too large. - $mfile - ;;; Too many links. - $mlink - ;;; Message too large. - $msgsize - ;;; Reserved. - $multihop - ;;; Filename too long. - $nametoolong - ;;; Network is down. - $netdown - ;;; Connection aborted by network. - $netreset - ;;; Network unreachable. - $netunreach - ;;; Too many files open in system. - $nfile - ;;; No buffer space available. - $nobufs - ;;; No such device. - $nodev - ;;; No such file or directory. - $noent - ;;; Executable file format error. - $noexec - ;;; No locks available. - $nolck - ;;; Reserved. - $nolink - ;;; Not enough space. - $nomem - ;;; No message of the desired type. - $nomsg - ;;; Protocol not available. - $noprotoopt - ;;; No space left on device. - $nospc - ;;; Function not supported. - $nosys - ;;; The socket is not connected. - $notconn - ;;; Not a directory or a symbolic link to a directory. - $notdir - ;;; Directory not empty. - $notempty - ;;; State not recoverable. - $notrecoverable - ;;; Not a socket. - $notsock - ;;; Not supported, or operation not supported on socket. - $notsup - ;;; Inappropriate I/O control operation. - $notty - ;;; No such device or address. - $nxio - ;;; Value too large to be stored in data type. - $overflow - ;;; Previous owner died. - $ownerdead - ;;; Operation not permitted. - $perm - ;;; Broken pipe. - $pipe - ;;; Protocol error. - $proto - ;;; Protocol not supported. - $protonosupport - ;;; Protocol wrong type for socket. - $prototype - ;;; Result too large. - $range - ;;; Read-only file system. - $rofs - ;;; Invalid seek. - $spipe - ;;; No such process. - $srch - ;;; Reserved. - $stale - ;;; Connection timed out. - $timedout - ;;; Text file busy. - $txtbsy - ;;; Cross-device link. - $xdev - ;;; Extension: Capabilities insufficient. - $notcapable - ) -) - -;;; File descriptor rights, determining which actions may be performed. -(typename $rights - (flags (@witx repr u64) - ;;; The right to invoke `fd_datasync`. - ;; - ;;; If `path_open` is set, includes the right to invoke - ;;; `path_open` with `fdflags::dsync`. - $fd_datasync - ;;; The right to invoke `fd_read` and `sock_recv`. - ;; - ;;; If `rights::fd_seek` is set, includes the right to invoke `fd_pread`. - $fd_read - ;;; The right to invoke `fd_seek`. This flag implies `rights::fd_tell`. - $fd_seek - ;;; The right to invoke `fd_fdstat_set_flags`. - $fd_fdstat_set_flags - ;;; The right to invoke `fd_sync`. - ;; - ;;; If `path_open` is set, includes the right to invoke - ;;; `path_open` with `fdflags::rsync` and `fdflags::dsync`. - $fd_sync - ;;; The right to invoke `fd_seek` in such a way that the file offset - ;;; remains unaltered (i.e., `whence::cur` with offset zero), or to - ;;; invoke `fd_tell`. - $fd_tell - ;;; The right to invoke `fd_write` and `sock_send`. - ;;; If `rights::fd_seek` is set, includes the right to invoke `fd_pwrite`. - $fd_write - ;;; The right to invoke `fd_advise`. - $fd_advise - ;;; The right to invoke `fd_allocate`. - $fd_allocate - ;;; The right to invoke `path_create_directory`. - $path_create_directory - ;;; If `path_open` is set, the right to invoke `path_open` with `oflags::creat`. - $path_create_file - ;;; The right to invoke `path_link` with the file descriptor as the - ;;; source directory. - $path_link_source - ;;; The right to invoke `path_link` with the file descriptor as the - ;;; target directory. - $path_link_target - ;;; The right to invoke `path_open`. - $path_open - ;;; The right to invoke `fd_readdir`. - $fd_readdir - ;;; The right to invoke `path_readlink`. - $path_readlink - ;;; The right to invoke `path_rename` with the file descriptor as the source directory. - $path_rename_source - ;;; The right to invoke `path_rename` with the file descriptor as the target directory. - $path_rename_target - ;;; The right to invoke `path_filestat_get`. - $path_filestat_get - ;;; The right to change a file's size. - ;;; If `path_open` is set, includes the right to invoke `path_open` with `oflags::trunc`. - ;;; Note: there is no function named `path_filestat_set_size`. This follows POSIX design, - ;;; which only has `ftruncate` and does not provide `ftruncateat`. - ;;; While such function would be desirable from the API design perspective, there are virtually - ;;; no use cases for it since no code written for POSIX systems would use it. - ;;; Moreover, implementing it would require multiple syscalls, leading to inferior performance. - $path_filestat_set_size - ;;; The right to invoke `path_filestat_set_times`. - $path_filestat_set_times - ;;; The right to invoke `fd_filestat_get`. - $fd_filestat_get - ;;; The right to invoke `fd_filestat_set_size`. - $fd_filestat_set_size - ;;; The right to invoke `fd_filestat_set_times`. - $fd_filestat_set_times - ;;; The right to invoke `path_symlink`. - $path_symlink - ;;; The right to invoke `path_remove_directory`. - $path_remove_directory - ;;; The right to invoke `path_unlink_file`. - $path_unlink_file - ;;; If `rights::fd_read` is set, includes the right to invoke `poll_oneoff` to subscribe to `eventtype::fd_read`. - ;;; If `rights::fd_write` is set, includes the right to invoke `poll_oneoff` to subscribe to `eventtype::fd_write`. - $poll_fd_readwrite - ;;; The right to invoke `sock_shutdown`. - $sock_shutdown - ;;; The right to invoke `sock_accept`. - $sock_accept - ) -) - -;;; A file descriptor handle. -(typename $fd (handle)) - -;;; A region of memory for scatter/gather reads. -(typename $iovec - (record - ;;; The address of the buffer to be filled. - (field $buf (@witx pointer u8)) - ;;; The length of the buffer to be filled. - (field $buf_len $size) - ) -) - -;;; A region of memory for scatter/gather writes. -(typename $ciovec - (record - ;;; The address of the buffer to be written. - (field $buf (@witx const_pointer u8)) - ;;; The length of the buffer to be written. - (field $buf_len $size) - ) -) - -(typename $iovec_array (list $iovec)) -(typename $ciovec_array (list $ciovec)) - -;;; Relative offset within a file. -(typename $filedelta s64) - -;;; The position relative to which to set the offset of the file descriptor. -(typename $whence - (enum (@witx tag u8) - ;;; Seek relative to start-of-file. - $set - ;;; Seek relative to current position. - $cur - ;;; Seek relative to end-of-file. - $end - ) -) - -;;; A reference to the offset of a directory entry. -;;; -;;; The value 0 signifies the start of the directory. -(typename $dircookie u64) - -;;; The type for the `dirent::d_namlen` field of `dirent` struct. -(typename $dirnamlen u32) - -;;; File serial number that is unique within its file system. -(typename $inode u64) - -;;; The type of a file descriptor or file. -(typename $filetype - (enum (@witx tag u8) - ;;; The type of the file descriptor or file is unknown or is different from any of the other types specified. - $unknown - ;;; The file descriptor or file refers to a block device inode. - $block_device - ;;; The file descriptor or file refers to a character device inode. - $character_device - ;;; The file descriptor or file refers to a directory inode. - $directory - ;;; The file descriptor or file refers to a regular file inode. - $regular_file - ;;; The file descriptor or file refers to a datagram socket. - $socket_dgram - ;;; The file descriptor or file refers to a byte-stream socket. - $socket_stream - ;;; The file refers to a symbolic link inode. - $symbolic_link - ) -) - -;;; A directory entry. -(typename $dirent - (record - ;;; The offset of the next directory entry stored in this directory. - (field $d_next $dircookie) - ;;; The serial number of the file referred to by this directory entry. - (field $d_ino $inode) - ;;; The length of the name of the directory entry. - (field $d_namlen $dirnamlen) - ;;; The type of the file referred to by this directory entry. - (field $d_type $filetype) - ) -) - -;;; File or memory access pattern advisory information. -(typename $advice - (enum (@witx tag u8) - ;;; The application has no advice to give on its behavior with respect to the specified data. - $normal - ;;; The application expects to access the specified data sequentially from lower offsets to higher offsets. - $sequential - ;;; The application expects to access the specified data in a random order. - $random - ;;; The application expects to access the specified data in the near future. - $willneed - ;;; The application expects that it will not access the specified data in the near future. - $dontneed - ;;; The application expects to access the specified data once and then not reuse it thereafter. - $noreuse - ) -) - -;;; File descriptor flags. -(typename $fdflags - (flags (@witx repr u16) - ;;; Append mode: Data written to the file is always appended to the file's end. - $append - ;;; Write according to synchronized I/O data integrity completion. Only the data stored in the file is synchronized. - $dsync - ;;; Non-blocking mode. - $nonblock - ;;; Synchronized read I/O operations. - $rsync - ;;; Write according to synchronized I/O file integrity completion. In - ;;; addition to synchronizing the data stored in the file, the implementation - ;;; may also synchronously update the file's metadata. - $sync - ) -) - -;;; File descriptor attributes. -(typename $fdstat - (record - ;;; File type. - (field $fs_filetype $filetype) - ;;; File descriptor flags. - (field $fs_flags $fdflags) - ;;; Rights that apply to this file descriptor. - (field $fs_rights_base $rights) - ;;; Maximum set of rights that may be installed on new file descriptors that - ;;; are created through this file descriptor, e.g., through `path_open`. - (field $fs_rights_inheriting $rights) - ) -) - -;;; Identifier for a device containing a file system. Can be used in combination -;;; with `inode` to uniquely identify a file or directory in the filesystem. -(typename $device u64) - -;;; Which file time attributes to adjust. -(typename $fstflags - (flags (@witx repr u16) - ;;; Adjust the last data access timestamp to the value stored in `filestat::atim`. - $atim - ;;; Adjust the last data access timestamp to the time of clock `clockid::realtime`. - $atim_now - ;;; Adjust the last data modification timestamp to the value stored in `filestat::mtim`. - $mtim - ;;; Adjust the last data modification timestamp to the time of clock `clockid::realtime`. - $mtim_now - ) -) - -;;; Flags determining the method of how paths are resolved. -(typename $lookupflags - (flags (@witx repr u32) - ;;; As long as the resolved path corresponds to a symbolic link, it is expanded. - $symlink_follow - ) -) - -;;; Open flags used by `path_open`. -(typename $oflags - (flags (@witx repr u16) - ;;; Create file if it does not exist. - $creat - ;;; Fail if not a directory. - $directory - ;;; Fail if file already exists. - $excl - ;;; Truncate file to size 0. - $trunc - ) -) - -;;; Number of hard links to an inode. -(typename $linkcount u64) - -;;; File attributes. -(typename $filestat - (record - ;;; Device ID of device containing the file. - (field $dev $device) - ;;; File serial number. - (field $ino $inode) - ;;; File type. - (field $filetype $filetype) - ;;; Number of hard links to the file. - (field $nlink $linkcount) - ;;; For regular files, the file size in bytes. For symbolic links, the length in bytes of the pathname contained in the symbolic link. - (field $size $filesize) - ;;; Last data access timestamp. - ;;; This can be 0 if the underlying platform doesn't provide suitable - ;;; timestamp for this file. - (field $atim $timestamp) - ;;; Last data modification timestamp. - ;;; This can be 0 if the underlying platform doesn't provide suitable - ;;; timestamp for this file. - (field $mtim $timestamp) - ;;; Last file status change timestamp. - ;;; This can be 0 if the underlying platform doesn't provide suitable - ;;; timestamp for this file. - (field $ctim $timestamp) - ) -) - -;;; User-provided value that may be attached to objects that is retained when -;;; extracted from the implementation. -(typename $userdata u64) - -;;; Type of a subscription to an event or its occurrence. -(typename $eventtype - (enum (@witx tag u8) - ;;; The time value of clock `subscription_clock::id` has - ;;; reached timestamp `subscription_clock::timeout`. - $clock - ;;; File descriptor `subscription_fd_readwrite::file_descriptor` has data - ;;; available for reading. This event always triggers for regular files. - $fd_read - ;;; File descriptor `subscription_fd_readwrite::file_descriptor` has capacity - ;;; available for writing. This event always triggers for regular files. - $fd_write - ) -) - -;;; The state of the file descriptor subscribed to with -;;; `eventtype::fd_read` or `eventtype::fd_write`. -(typename $eventrwflags - (flags (@witx repr u16) - ;;; The peer of this socket has closed or disconnected. - $fd_readwrite_hangup - ) -) - -;;; The contents of an `event` when type is `eventtype::fd_read` or -;;; `eventtype::fd_write`. -(typename $event_fd_readwrite - (record - ;;; The number of bytes available for reading or writing. - (field $nbytes $filesize) - ;;; The state of the file descriptor. - (field $flags $eventrwflags) - ) -) - -;;; An event that occurred. -(typename $event - (record - ;;; User-provided value that got attached to `subscription::userdata`. - (field $userdata $userdata) - ;;; If non-zero, an error that occurred while processing the subscription request. - (field $error $errno) - ;;; The type of event that occurred - (field $type $eventtype) - ;;; The contents of the event, if it is an `eventtype::fd_read` or - ;;; `eventtype::fd_write`. `eventtype::clock` events ignore this field. - (field $fd_readwrite $event_fd_readwrite) - ) -) - -;;; Flags determining how to interpret the timestamp provided in -;;; `subscription_clock::timeout`. -(typename $subclockflags - (flags (@witx repr u16) - ;;; If set, treat the timestamp provided in - ;;; `subscription_clock::timeout` as an absolute timestamp of clock - ;;; `subscription_clock::id`. If clear, treat the timestamp - ;;; provided in `subscription_clock::timeout` relative to the - ;;; current time value of clock `subscription_clock::id`. - $subscription_clock_abstime - ) -) - -;;; The contents of a `subscription` when type is `eventtype::clock`. -(typename $subscription_clock - (record - ;;; The clock against which to compare the timestamp. - (field $id $clockid) - ;;; The absolute or relative timestamp. - (field $timeout $timestamp) - ;;; The amount of time that the implementation may wait additionally - ;;; to coalesce with other events. - (field $precision $timestamp) - ;;; Flags specifying whether the timeout is absolute or relative - (field $flags $subclockflags) - ) -) - -;;; The contents of a `subscription` when type is type is -;;; `eventtype::fd_read` or `eventtype::fd_write`. -(typename $subscription_fd_readwrite - (record - ;;; The file descriptor on which to wait for it to become ready for reading or writing. - (field $file_descriptor $fd) - ) -) - -;;; The contents of a `subscription`. -(typename $subscription_u - (union - (@witx tag $eventtype) - $subscription_clock - $subscription_fd_readwrite - $subscription_fd_readwrite - ) -) - -;;; Subscription to an event. -(typename $subscription - (record - ;;; User-provided value that is attached to the subscription in the - ;;; implementation and returned through `event::userdata`. - (field $userdata $userdata) - ;;; The type of the event to which to subscribe, and its contents - (field $u $subscription_u) - ) -) - -;;; Exit code generated by a process when exiting. -(typename $exitcode u32) - -;;; Signal condition. -(typename $signal - (enum (@witx tag u8) - ;;; No signal. Note that POSIX has special semantics for `kill(pid, 0)`, - ;;; so this value is reserved. - $none - ;;; Hangup. - ;;; Action: Terminates the process. - $hup - ;;; Terminate interrupt signal. - ;;; Action: Terminates the process. - $int - ;;; Terminal quit signal. - ;;; Action: Terminates the process. - $quit - ;;; Illegal instruction. - ;;; Action: Terminates the process. - $ill - ;;; Trace/breakpoint trap. - ;;; Action: Terminates the process. - $trap - ;;; Process abort signal. - ;;; Action: Terminates the process. - $abrt - ;;; Access to an undefined portion of a memory object. - ;;; Action: Terminates the process. - $bus - ;;; Erroneous arithmetic operation. - ;;; Action: Terminates the process. - $fpe - ;;; Kill. - ;;; Action: Terminates the process. - $kill - ;;; User-defined signal 1. - ;;; Action: Terminates the process. - $usr1 - ;;; Invalid memory reference. - ;;; Action: Terminates the process. - $segv - ;;; User-defined signal 2. - ;;; Action: Terminates the process. - $usr2 - ;;; Write on a pipe with no one to read it. - ;;; Action: Ignored. - $pipe - ;;; Alarm clock. - ;;; Action: Terminates the process. - $alrm - ;;; Termination signal. - ;;; Action: Terminates the process. - $term - ;;; Child process terminated, stopped, or continued. - ;;; Action: Ignored. - $chld - ;;; Continue executing, if stopped. - ;;; Action: Continues executing, if stopped. - $cont - ;;; Stop executing. - ;;; Action: Stops executing. - $stop - ;;; Terminal stop signal. - ;;; Action: Stops executing. - $tstp - ;;; Background process attempting read. - ;;; Action: Stops executing. - $ttin - ;;; Background process attempting write. - ;;; Action: Stops executing. - $ttou - ;;; High bandwidth data is available at a socket. - ;;; Action: Ignored. - $urg - ;;; CPU time limit exceeded. - ;;; Action: Terminates the process. - $xcpu - ;;; File size limit exceeded. - ;;; Action: Terminates the process. - $xfsz - ;;; Virtual timer expired. - ;;; Action: Terminates the process. - $vtalrm - ;;; Profiling timer expired. - ;;; Action: Terminates the process. - $prof - ;;; Window changed. - ;;; Action: Ignored. - $winch - ;;; I/O possible. - ;;; Action: Terminates the process. - $poll - ;;; Power failure. - ;;; Action: Terminates the process. - $pwr - ;;; Bad system call. - ;;; Action: Terminates the process. - $sys - ) -) - -;;; Flags provided to `sock_recv`. -(typename $riflags - (flags (@witx repr u16) - ;;; Returns the message without removing it from the socket's receive queue. - $recv_peek - ;;; On byte-stream sockets, block until the full amount of data can be returned. - $recv_waitall - ) -) - -;;; Flags returned by `sock_recv`. -(typename $roflags - (flags (@witx repr u16) - ;;; Returned by `sock_recv`: Message data has been truncated. - $recv_data_truncated - ) -) - -;;; Flags provided to `sock_send`. As there are currently no flags -;;; defined, it must be set to zero. -(typename $siflags u16) - -;;; Which channels on a socket to shut down. -(typename $sdflags - (flags (@witx repr u8) - ;;; Disables further receive operations. - $rd - ;;; Disables further send operations. - $wr - ) -) - -;;; Identifiers for preopened capabilities. -(typename $preopentype - (enum (@witx tag u8) - ;;; A pre-opened directory. - $dir - ) -) - -;;; The contents of a `prestat` when type is `preopentype::dir`. -(typename $prestat_dir - (record - ;;; The length of the directory name for use with `fd_prestat_dir_name`. - (field $pr_name_len $size) - ) -) - -;;; Information about a pre-opened capability. -(typename $prestat - (union (@witx tag $preopentype) - $prestat_dir - ) -) - diff --git a/legacy/preview1/witx/wasi_snapshot_preview1.witx b/legacy/preview1/witx/wasi_snapshot_preview1.witx deleted file mode 100644 index 0c2067dba..000000000 --- a/legacy/preview1/witx/wasi_snapshot_preview1.witx +++ /dev/null @@ -1,540 +0,0 @@ -;; WASI Preview. This is an evolution of the API that WASI initially -;; launched with. -;; -;; Some content here is derived from [CloudABI](https://github.com/NuxiNL/cloudabi). -;; -;; This is a `witx` file. See [here](https://github.com/WebAssembly/WASI/blob/main/legacy/tools/witx-docs.md) -;; for an explanation of what that means. - -(use "typenames.witx") - -(module $wasi_snapshot_preview1 - ;;; Linear memory to be accessed by WASI functions that need it. - (import "memory" (memory)) - - ;;; Read command-line argument data. - ;;; - ;;; The size of the array should match that returned by `args_sizes_get`. - ;;; - ;;; Each argument is expected to be `\0` terminated. - ;;; - ;;; The first argument should be a string containing the "name" of the - ;;; program. This need not be a usable filesystem path or even file name, - ;;; and may even be a fixed string. Subsequent arguments are the arguments - ;;; passed to the program by the user. - (@interface func (export "args_get") - (param $argv (@witx pointer (@witx pointer u8))) - (param $argv_buf (@witx pointer u8)) - (result $error (expected (error $errno))) - ) - ;;; Return command-line argument data sizes. - (@interface func (export "args_sizes_get") - ;;; Returns the number of arguments and the size of the argument string - ;;; data, or an error. - (result $error (expected (tuple $size $size) (error $errno))) - ) - - ;;; Read environment variable data. - ;;; The sizes of the buffers should match that returned by `environ_sizes_get`. - ;;; Key/value pairs are expected to be joined with `=`s, and terminated with `\0`s. - (@interface func (export "environ_get") - (param $environ (@witx pointer (@witx pointer u8))) - (param $environ_buf (@witx pointer u8)) - (result $error (expected (error $errno))) - ) - ;;; Return environment variable data sizes. - (@interface func (export "environ_sizes_get") - ;;; Returns the number of environment variable arguments and the size of the - ;;; environment variable data. - (result $error (expected (tuple $size $size) (error $errno))) - ) - - ;;; Return the resolution of a clock. - ;;; Implementations are required to provide a non-zero value for supported clocks. For unsupported clocks, - ;;; return `errno::inval`. - ;;; Note: This is similar to `clock_getres` in POSIX. - (@interface func (export "clock_res_get") - ;;; The clock for which to return the resolution. - (param $id $clockid) - ;;; The resolution of the clock, or an error if one happened. - (result $error (expected $timestamp (error $errno))) - ) - ;;; Return the time value of a clock. - ;;; Note: This is similar to `clock_gettime` in POSIX. - (@interface func (export "clock_time_get") - ;;; The clock for which to return the time. - (param $id $clockid) - ;;; The maximum lag (exclusive) that the returned time value may have, compared to its actual value. - (param $precision $timestamp) - ;;; The time value of the clock. - (result $error (expected $timestamp (error $errno))) - ) - - ;;; Provide file advisory information on a file descriptor. - ;;; Note: This is similar to `posix_fadvise` in POSIX. - (@interface func (export "fd_advise") - (param $fd $fd) - ;;; The offset within the file to which the advisory applies. - (param $offset $filesize) - ;;; The length of the region to which the advisory applies. - (param $len $filesize) - ;;; The advice. - (param $advice $advice) - (result $error (expected (error $errno))) - ) - - ;;; Force the allocation of space in a file. - ;;; Note: This is similar to `posix_fallocate` in POSIX. - (@interface func (export "fd_allocate") - (param $fd $fd) - ;;; The offset at which to start the allocation. - (param $offset $filesize) - ;;; The length of the area that is allocated. - (param $len $filesize) - (result $error (expected (error $errno))) - ) - - ;;; Close a file descriptor. - ;;; Note: This is similar to `close` in POSIX. - (@interface func (export "fd_close") - (param $fd $fd) - (result $error (expected (error $errno))) - ) - - ;;; Synchronize the data of a file to disk. - ;;; Note: This is similar to `fdatasync` in POSIX. - (@interface func (export "fd_datasync") - (param $fd $fd) - (result $error (expected (error $errno))) - ) - - ;;; Get the attributes of a file descriptor. - ;;; Note: This returns similar flags to `fcntl(fd, F_GETFL)` in POSIX, as well as additional fields. - (@interface func (export "fd_fdstat_get") - (param $fd $fd) - ;;; The buffer where the file descriptor's attributes are stored. - (result $error (expected $fdstat (error $errno))) - ) - - ;;; Adjust the flags associated with a file descriptor. - ;;; Note: This is similar to `fcntl(fd, F_SETFL, flags)` in POSIX. - (@interface func (export "fd_fdstat_set_flags") - (param $fd $fd) - ;;; The desired values of the file descriptor flags. - (param $flags $fdflags) - (result $error (expected (error $errno))) - ) - - ;;; Adjust the rights associated with a file descriptor. - ;;; This can only be used to remove rights, and returns `errno::notcapable` if called in a way that would attempt to add rights - (@interface func (export "fd_fdstat_set_rights") - (param $fd $fd) - ;;; The desired rights of the file descriptor. - (param $fs_rights_base $rights) - (param $fs_rights_inheriting $rights) - (result $error (expected (error $errno))) - ) - - ;;; Return the attributes of an open file. - (@interface func (export "fd_filestat_get") - (param $fd $fd) - ;;; The buffer where the file's attributes are stored. - (result $error (expected $filestat (error $errno))) - ) - - ;;; Adjust the size of an open file. If this increases the file's size, the extra bytes are filled with zeros. - ;;; Note: This is similar to `ftruncate` in POSIX. - (@interface func (export "fd_filestat_set_size") - (param $fd $fd) - ;;; The desired file size. - (param $size $filesize) - (result $error (expected (error $errno))) - ) - - ;;; Adjust the timestamps of an open file or directory. - ;;; Note: This is similar to `futimens` in POSIX. - (@interface func (export "fd_filestat_set_times") - (param $fd $fd) - ;;; The desired values of the data access timestamp. - (param $atim $timestamp) - ;;; The desired values of the data modification timestamp. - (param $mtim $timestamp) - ;;; A bitmask indicating which timestamps to adjust. - (param $fst_flags $fstflags) - (result $error (expected (error $errno))) - ) - - ;;; Read from a file descriptor, without using and updating the file descriptor's offset. - ;;; Note: This is similar to `preadv` in Linux (and other Unix-es). - (@interface func (export "fd_pread") - (param $fd $fd) - ;;; List of scatter/gather vectors in which to store data. - (param $iovs $iovec_array) - ;;; The offset within the file at which to read. - (param $offset $filesize) - ;;; The number of bytes read. - (result $error (expected $size (error $errno))) - ) - - ;;; Return a description of the given preopened file descriptor. - (@interface func (export "fd_prestat_get") - (param $fd $fd) - ;;; The buffer where the description is stored. - (result $error (expected $prestat (error $errno))) - ) - - ;;; Return a description of the given preopened file descriptor. - (@interface func (export "fd_prestat_dir_name") - (param $fd $fd) - ;;; A buffer into which to write the preopened directory name. - (param $path (@witx pointer u8)) - (param $path_len $size) - (result $error (expected (error $errno))) - ) - - ;;; Write to a file descriptor, without using and updating the file descriptor's offset. - ;;; Note: This is similar to `pwritev` in Linux (and other Unix-es). - ;;; - ;;; Like Linux (and other Unix-es), any calls of `pwrite` (and other - ;;; functions to read or write) for a regular file by other threads in the - ;;; WASI process should not be interleaved while `pwrite` is executed. - (@interface func (export "fd_pwrite") - (param $fd $fd) - ;;; List of scatter/gather vectors from which to retrieve data. - (param $iovs $ciovec_array) - ;;; The offset within the file at which to write. - (param $offset $filesize) - ;;; The number of bytes written. - (result $error (expected $size (error $errno))) - ) - - ;;; Read from a file descriptor. - ;;; Note: This is similar to `readv` in POSIX. - (@interface func (export "fd_read") - (param $fd $fd) - ;;; List of scatter/gather vectors to which to store data. - (param $iovs $iovec_array) - ;;; The number of bytes read. - (result $error (expected $size (error $errno))) - ) - - ;;; Read directory entries from a directory. - ;;; When successful, the contents of the output buffer consist of a sequence of - ;;; directory entries. Each directory entry consists of a `dirent` object, - ;;; followed by `dirent::d_namlen` bytes holding the name of the directory - ;;; entry. - ;; - ;;; This function fills the output buffer as much as possible, potentially - ;;; truncating the last directory entry. This allows the caller to grow its - ;;; read buffer size in case it's too small to fit a single large directory - ;;; entry, or skip the oversized directory entry. - ;;; - ;;; Entries for the special `.` and `..` directory entries are included in the - ;;; sequence. - (@interface func (export "fd_readdir") - (param $fd $fd) - ;;; The buffer where directory entries are stored - (param $buf (@witx pointer u8)) - (param $buf_len $size) - ;;; The location within the directory to start reading - (param $cookie $dircookie) - ;;; The number of bytes stored in the read buffer. If less than the size of the read buffer, the end of the directory has been reached. - (result $error (expected $size (error $errno))) - ) - - ;;; Atomically replace a file descriptor by renumbering another file descriptor. - ;; - ;;; Due to the strong focus on thread safety, this environment does not provide - ;;; a mechanism to duplicate or renumber a file descriptor to an arbitrary - ;;; number, like `dup2()`. This would be prone to race conditions, as an actual - ;;; file descriptor with the same number could be allocated by a different - ;;; thread at the same time. - ;; - ;;; This function provides a way to atomically renumber file descriptors, which - ;;; would disappear if `dup2()` were to be removed entirely. - (@interface func (export "fd_renumber") - (param $fd $fd) - ;;; The file descriptor to overwrite. - (param $to $fd) - (result $error (expected (error $errno))) - ) - - ;;; Move the offset of a file descriptor. - ;;; Note: This is similar to `lseek` in POSIX. - (@interface func (export "fd_seek") - (param $fd $fd) - ;;; The number of bytes to move. - (param $offset $filedelta) - ;;; The base from which the offset is relative. - (param $whence $whence) - ;;; The new offset of the file descriptor, relative to the start of the file. - (result $error (expected $filesize (error $errno))) - ) - - ;;; Synchronize the data and metadata of a file to disk. - ;;; Note: This is similar to `fsync` in POSIX. - (@interface func (export "fd_sync") - (param $fd $fd) - (result $error (expected (error $errno))) - ) - - ;;; Return the current offset of a file descriptor. - ;;; Note: This is similar to `lseek(fd, 0, SEEK_CUR)` in POSIX. - (@interface func (export "fd_tell") - (param $fd $fd) - ;;; The current offset of the file descriptor, relative to the start of the file. - (result $error (expected $filesize (error $errno))) - ) - - ;;; Write to a file descriptor. - ;;; Note: This is similar to `writev` in POSIX. - ;;; - ;;; Like POSIX, any calls of `write` (and other functions to read or write) - ;;; for a regular file by other threads in the WASI process should not be - ;;; interleaved while `write` is executed. - (@interface func (export "fd_write") - (param $fd $fd) - ;;; List of scatter/gather vectors from which to retrieve data. - (param $iovs $ciovec_array) - (result $error (expected $size (error $errno))) - ) - - ;;; Create a directory. - ;;; Note: This is similar to `mkdirat` in POSIX. - (@interface func (export "path_create_directory") - (param $fd $fd) - ;;; The path at which to create the directory. - (param $path string) - (result $error (expected (error $errno))) - ) - - ;;; Return the attributes of a file or directory. - ;;; Note: This is similar to `stat` in POSIX. - (@interface func (export "path_filestat_get") - (param $fd $fd) - ;;; Flags determining the method of how the path is resolved. - (param $flags $lookupflags) - ;;; The path of the file or directory to inspect. - (param $path string) - ;;; The buffer where the file's attributes are stored. - (result $error (expected $filestat (error $errno))) - ) - - ;;; Adjust the timestamps of a file or directory. - ;;; Note: This is similar to `utimensat` in POSIX. - (@interface func (export "path_filestat_set_times") - (param $fd $fd) - ;;; Flags determining the method of how the path is resolved. - (param $flags $lookupflags) - ;;; The path of the file or directory to operate on. - (param $path string) - ;;; The desired values of the data access timestamp. - (param $atim $timestamp) - ;;; The desired values of the data modification timestamp. - (param $mtim $timestamp) - ;;; A bitmask indicating which timestamps to adjust. - (param $fst_flags $fstflags) - (result $error (expected (error $errno))) - ) - - ;;; Create a hard link. - ;;; Note: This is similar to `linkat` in POSIX. - (@interface func (export "path_link") - (param $old_fd $fd) - ;;; Flags determining the method of how the path is resolved. - (param $old_flags $lookupflags) - ;;; The source path from which to link. - (param $old_path string) - ;;; The working directory at which the resolution of the new path starts. - (param $new_fd $fd) - ;;; The destination path at which to create the hard link. - (param $new_path string) - (result $error (expected (error $errno))) - ) - - ;;; Open a file or directory. - ;; - ;;; The returned file descriptor is not guaranteed to be the lowest-numbered - ;;; file descriptor not currently open; it is randomized to prevent - ;;; applications from depending on making assumptions about indexes, since this - ;;; is error-prone in multi-threaded contexts. The returned file descriptor is - ;;; guaranteed to be less than 2**31. - ;; - ;;; Note: This is similar to `openat` in POSIX. - (@interface func (export "path_open") - (param $fd $fd) - ;;; Flags determining the method of how the path is resolved. - (param $dirflags $lookupflags) - ;;; The relative path of the file or directory to open, relative to the - ;;; `path_open::fd` directory. - (param $path string) - ;;; The method by which to open the file. - (param $oflags $oflags) - ;;; The initial rights of the newly created file descriptor. The - ;;; implementation is allowed to return a file descriptor with fewer rights - ;;; than specified, if and only if those rights do not apply to the type of - ;;; file being opened. - ;; - ;;; The *base* rights are rights that will apply to operations using the file - ;;; descriptor itself, while the *inheriting* rights are rights that apply to - ;;; file descriptors derived from it. - (param $fs_rights_base $rights) - (param $fs_rights_inheriting $rights) - (param $fdflags $fdflags) - ;;; The file descriptor of the file that has been opened. - (result $error (expected $fd (error $errno))) - ) - - ;;; Read the contents of a symbolic link. - ;;; Note: This is similar to `readlinkat` in POSIX. If `buf` is not large - ;;; enough to contain the contents of the link, the first `buf_len` bytes will be - ;;; be written to `buf`. - (@interface func (export "path_readlink") - (param $fd $fd) - ;;; The path of the symbolic link from which to read. - (param $path string) - ;;; The buffer to which to write the contents of the symbolic link. - (param $buf (@witx pointer u8)) - (param $buf_len $size) - ;;; The number of bytes placed in the buffer. - (result $error (expected $size (error $errno))) - ) - - ;;; Remove a directory. - ;;; Return `errno::notempty` if the directory is not empty. - ;;; Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. - (@interface func (export "path_remove_directory") - (param $fd $fd) - ;;; The path to a directory to remove. - (param $path string) - (result $error (expected (error $errno))) - ) - - ;;; Rename a file or directory. - ;;; Note: This is similar to `renameat` in POSIX. - (@interface func (export "path_rename") - (param $fd $fd) - ;;; The source path of the file or directory to rename. - (param $old_path string) - ;;; The working directory at which the resolution of the new path starts. - (param $new_fd $fd) - ;;; The destination path to which to rename the file or directory. - (param $new_path string) - (result $error (expected (error $errno))) - ) - - ;;; Create a symbolic link. - ;;; Note: This is similar to `symlinkat` in POSIX. - (@interface func (export "path_symlink") - ;;; The contents of the symbolic link. - (param $old_path string) - (param $fd $fd) - ;;; The destination path at which to create the symbolic link. - (param $new_path string) - (result $error (expected (error $errno))) - ) - - - ;;; Unlink a file. - ;;; Return `errno::isdir` if the path refers to a directory. - ;;; Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. - (@interface func (export "path_unlink_file") - (param $fd $fd) - ;;; The path to a file to unlink. - (param $path string) - (result $error (expected (error $errno))) - ) - - ;;; Concurrently poll for the occurrence of a set of events. - ;;; - ;;; If `nsubscriptions` is 0, returns `errno::inval`. - (@interface func (export "poll_oneoff") - ;;; The events to which to subscribe. - (param $in (@witx const_pointer $subscription)) - ;;; The events that have occurred. - (param $out (@witx pointer $event)) - ;;; Both the number of subscriptions and events. - (param $nsubscriptions $size) - ;;; The number of events stored. - (result $error (expected $size (error $errno))) - ) - - ;;; Terminate the process normally. An exit code of 0 indicates successful - ;;; termination of the program. The meanings of other values is dependent on - ;;; the environment. - (@interface func (export "proc_exit") - ;;; The exit code returned by the process. - (param $rval $exitcode) - (@witx noreturn) - ) - - ;;; Send a signal to the process of the calling thread. - ;;; Note: This is similar to `raise` in POSIX. - (@interface func (export "proc_raise") - ;;; The signal condition to trigger. - (param $sig $signal) - (result $error (expected (error $errno))) - ) - - ;;; Temporarily yield execution of the calling thread. - ;;; Note: This is similar to `sched_yield` in POSIX. - (@interface func (export "sched_yield") - (result $error (expected (error $errno))) - ) - - ;;; Write high-quality random data into a buffer. - ;;; This function blocks when the implementation is unable to immediately - ;;; provide sufficient high-quality random data. - (@interface func (export "random_get") - ;;; The buffer to fill with random data. - (param $buf (@witx pointer u8)) - (param $buf_len $size) - (result $error (expected (error $errno))) - ) - - ;;; Accept a new incoming connection. - ;;; Note: This is similar to `accept` in POSIX. - (@interface func (export "sock_accept") - ;;; The listening socket. - (param $fd $fd) - ;;; The desired values of the file descriptor flags. - (param $flags $fdflags) - ;;; New socket connection - (result $error (expected $fd (error $errno))) - ) - - ;;; Receive a message from a socket. - ;;; Note: This is similar to `recv` in POSIX, though it also supports reading - ;;; the data into multiple buffers in the manner of `readv`. - (@interface func (export "sock_recv") - (param $fd $fd) - ;;; List of scatter/gather vectors to which to store data. - (param $ri_data $iovec_array) - ;;; Message flags. - (param $ri_flags $riflags) - ;;; Number of bytes stored in ri_data and message flags. - (result $error (expected (tuple $size $roflags) (error $errno))) - ) - - ;;; Send a message on a socket. - ;;; Note: This is similar to `send` in POSIX, though it also supports writing - ;;; the data from multiple buffers in the manner of `writev`. - (@interface func (export "sock_send") - (param $fd $fd) - ;;; List of scatter/gather vectors to which to retrieve data - (param $si_data $ciovec_array) - ;;; Message flags. - (param $si_flags $siflags) - ;;; Number of bytes transmitted. - (result $error (expected $size (error $errno))) - ) - - ;;; Shut down socket send and receive channels. - ;;; Note: This is similar to `shutdown` in POSIX. - (@interface func (export "sock_shutdown") - (param $fd $fd) - ;;; Which channels on the socket to shut down. - (param $how $sdflags) - (result $error (expected (error $errno))) - ) -) diff --git a/legacy/tools/repo_docs.sh b/legacy/tools/repo_docs.sh deleted file mode 100755 index 8c9f10f03..000000000 --- a/legacy/tools/repo_docs.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash -set -ex -cd $(dirname $(realpath $0))/witx-cli -cargo run -- docs $1 ../../preview1/witx/wasi_snapshot_preview1.witx --output ../../preview1/docs.md -cargo run -- docs $1 ../../preview0/witx/wasi_unstable.witx --output ../../preview0/docs.md diff --git a/legacy/tools/witx-cli/.gitignore b/legacy/tools/witx-cli/.gitignore deleted file mode 100644 index a9d37c560..000000000 --- a/legacy/tools/witx-cli/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -target -Cargo.lock diff --git a/legacy/tools/witx-cli/Cargo.toml b/legacy/tools/witx-cli/Cargo.toml deleted file mode 100644 index 064364482..000000000 --- a/legacy/tools/witx-cli/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "witx-cli" -version = "0.9.1" -description = "CLI for operating on witx file format" -homepage = "https://github.com/WebAssembly/WASI" -repository = "https://github.com/WebAssembly/WASI" -license = "Apache-2.0" -categories = ["wasm"] -keywords = ["webassembly", "wasm"] -authors = ["Pat Hickey ", "Alex Crichton "] -edition = "2018" - -[[bin]] -name = "witx" -path = "src/main.rs" - -[dependencies] -witx = { path = "../witx", version = "0.9.1" } -anyhow = "1" -log = "0.4" -thiserror = "1.0" -diff = "0.1.11" -pretty_env_logger = "0.4" -structopt = "0.3" -rayon = "1.0" diff --git a/legacy/tools/witx-cli/src/main.rs b/legacy/tools/witx-cli/src/main.rs deleted file mode 100644 index 62156c525..000000000 --- a/legacy/tools/witx-cli/src/main.rs +++ /dev/null @@ -1,268 +0,0 @@ -use anyhow::{anyhow, bail, Result}; -use std::fs::File; -use std::io::Write; -use std::path::{Path, PathBuf}; -use std::process; -use structopt::{clap::AppSettings, StructOpt}; -use witx::{load, Document, Documentation}; - -/// Validate and process witx files -#[derive(StructOpt, Debug)] -#[structopt( - name = "witx", - version = env!("CARGO_PKG_VERSION"), - global_settings = &[ - AppSettings::VersionlessSubcommands, - AppSettings::ColoredHelp - ] -)] -struct Args { - #[structopt(short = "v", long = "verbose")] - verbose: bool, - - #[structopt(subcommand)] - cmd: Command, -} - -#[derive(StructOpt, Debug)] -enum Command { - /// Output documentation - Docs { - /// Path to root of witx document - #[structopt(number_of_values = 1, value_name = "INPUT", parse(from_os_str))] - input: Vec, - /// Perform check that output matches witx documents - #[structopt(long = "check")] - check: bool, - /// Path to generated documentation in Markdown format - #[structopt( - short = "o", - long = "output", - value_name = "OUTPUT", - parse(from_os_str) - )] - output: Option, - }, - /// Examine differences between interfaces - Polyfill { - /// Path to root of witx document - #[structopt( - required = true, - number_of_values = 1, - value_name = "INPUT", - parse(from_os_str) - )] - input: Vec, - /// Path to root of witx document describing interface to polyfill - #[structopt( - required = true, - number_of_values = 1, - value_name = "OLDER_INTERFACE", - parse(from_os_str) - )] - older_interface: Vec, - /// Module to examine (use newname=oldname syntax if name is different - /// between new and old interfaces) - #[structopt( - short = "m", - long = "module_mapping", - required = true, - number_of_values = 1, - value_name = "NEWNAME=OLDNAME", - parse(try_from_str = parse_module_mapping) - )] - module_mapping: Vec<(String, String)>, - }, -} - -pub fn main() { - let args = Args::from_args(); - pretty_env_logger::init(); - let verbose = args.verbose; - - match args.cmd { - Command::Docs { - input, - check, - output, - } => { - let doc = load_witx(&input, "input", verbose); - if check { - let output = output.expect("output argument required in docs --check mode"); - if diff_against_filesystem(&doc.to_md(), &output).is_err() { - println!("Docs in tree are out-of-date with witx files. Re-run this executable with the following arguments to re-generate:"); - println!( - "> witx docs {} --output {}", - input - .iter() - .map(|p| p.to_string_lossy().into_owned()) - .collect::>() - .join(" "), - output.to_string_lossy(), - ); - } - } else { - if let Some(output) = output { - write_docs(&doc, output) - } else { - println!("{}", doc.to_md()) - } - } - } - Command::Polyfill { - input, - older_interface, - module_mapping, - } => { - use std::{collections::HashMap, iter::FromIterator}; - use witx::polyfill::Polyfill; - - let doc = load_witx(&input, "input", verbose); - let older_doc = load_witx(&older_interface, "older_interface", verbose); - let module_mapping = HashMap::from_iter(module_mapping.into_iter()); - let polyfill = match Polyfill::new(&doc, &older_doc, &module_mapping) { - Ok(polyfill) => polyfill, - Err(e) => { - eprintln!("couldn't calculate polyfill"); - if verbose { - println!("{:?}", e); - } - process::exit(1); - } - }; - println!("{}", polyfill.to_md()); - if verbose { - println!("{:?}", polyfill); - } - } - } -} - -fn load_witx(input: &[PathBuf], field_name: &str, verbose: bool) -> Document { - match load(input) { - Ok(doc) => { - if verbose { - println!("{}: {:?}", field_name, doc); - } - doc - } - Err(e) => { - eprintln!("{}", e.report()); - if verbose { - println!("{:?}", e); - } - process::exit(1) - } - } -} - -fn write_docs>(document: &Document, path: P) { - let mut file = File::create(path.as_ref()).expect("create output file"); - file.write_all(document.to_md().as_bytes()) - .expect("write output file"); -} - -fn parse_module_mapping(m: &str) -> Result<(String, String)> { - let s: Vec<_> = m.split('=').collect(); - let (n, o) = match s.len() { - 1 => { - let mname = s - .get(0) - .ok_or(anyhow!("module name cannot be an empty string"))?; - (mname, mname) - } - 2 => { - let newname = s - .get(0) - .ok_or(anyhow!("new module name cannot be an empty string"))?; - let oldname = s - .get(1) - .ok_or(anyhow!("old module name cannot be an empty string"))?; - (newname, oldname) - } - _ => bail!("invalid module mapping: '{}'", m), - }; - Ok((n.to_string(), o.to_string())) -} - -fn dos2unix(s: &str) -> String { - let mut t = String::new(); - t.reserve(s.len()); - for c in s.chars() { - if c != '\r' { - t.push(c) - } - } - t -} - -fn diff_against_filesystem(expected: &str, path: &Path) -> Result<(), ()> { - let actual = std::fs::read_to_string(path) - .unwrap_or_else(|e| panic!("couldn't read {}: {:?}", Path::display(path), e)); - // Git may checkout the file with dos line endings on windows. Strip all \r: - let actual = dos2unix(&actual); - if &actual == expected { - return Ok(()); - } - - eprintln!("The following diff was found between the docs generated from .witx and the"); - eprintln!("source {:?} in the tree:", path); - eprintln!(); - - let mut expected_line = 1; - let mut actual_line = 1; - let mut separated = false; - let mut any_lines = false; - for diff in diff::lines(&expected, &actual) { - match diff { - diff::Result::Left(l) => { - eprintln!("line {}: -{}", expected_line, l); - expected_line += 1; - separated = false; - any_lines = true; - } - diff::Result::Both(_, _) => { - expected_line += 1; - actual_line += 1; - if !separated { - eprintln!("..."); - separated = true; - } - } - diff::Result::Right(r) => { - eprintln!("line {}: +{}", actual_line, r); - actual_line += 1; - separated = false; - any_lines = true; - } - } - } - - if !any_lines { - eprintln!(); - eprintln!( - "Somehow there was a diff with no lines differing. Lengths: {} and {}.", - expected.len(), - actual.len() - ); - for (index, (a, b)) in actual.chars().zip(expected.chars()).enumerate() { - if a != b { - eprintln!("char difference at index {}: '{}' != '{}'", index, a, b); - } - } - for (index, (a, b)) in actual.bytes().zip(expected.bytes()).enumerate() { - if a != b { - eprintln!("byte difference at index {}: b'{}' != b'{}'", index, a, b); - } - } - eprintln!(); - eprintln!("actual: {}", actual); - eprintln!(); - eprintln!("expected: {}", expected); - } - - eprintln!(); - eprintln!("To regenerate the files, run `tools/repo_docs.sh`."); - eprintln!(); - Err(()) -} diff --git a/legacy/tools/witx-docs.md b/legacy/tools/witx-docs.md deleted file mode 100644 index b694135ff..000000000 --- a/legacy/tools/witx-docs.md +++ /dev/null @@ -1,93 +0,0 @@ -# Know your `witx` - -`Witx` is an experimental IDL. The text format is based on a text format -associated with an early version of the [module linking proposal] text -format, which at the time was called `wit`, though it is a different language -than what we now call [Wit]. And that `wit` was in turn based on the -[wat format], which is based on [S-expressions]. - -Witx adds some features inspired by [interface types], such as limited -`string` and `array` arguments, and some features using for working with -IDL files such as the ability to include one IDL file in another. - -The initial goal for `witx` was just to have a language suitable for -expressing [WASI] APIs in, to serve as the vocabulary for proposing changes -to existing APIs and proposing new APIs. - -The WASI Subgroup is [migrating] away from `witx` and toward [Wit], because -Wit provides much better support for non-C-like languages, better support for -API virtualization, it has a path to integrating async behavior into WASI -APIs in a comprehensive way, and it supports much more expressive APIs, such -as the ability to have `string`s and other types as return types in addition -to just argument types. At this point, the tooling for Wit is also a lot more -sophisticated and the [Wit language] and [Canonical ABI] have much more -documentation. - -This document focused on the witx format. - -## Return types - -Function declarations in witx can have a special `expected` type, which is -a variant which represents either success or failure, and can return a -specific type off value for each. - -For example, the `fd_read` function declaration in Preview1 contains this: - -```witx - (result $error (expected $size (error $errno))) -``` - -This declares a result named `$error` which returns a value with type -`$size` on success, and a value with type `$errno` on failure. - -The `expected` mechanism assumes that the error value is an enum where 0 -indicates success, and as such it doesn't return an explicit descriminant -value. In the ABI, the `error` type is returned as the return value and -the success value is handled by adding an argument of pointer type for -the function to store the result into. - -The resulting ABI for `fd_read` looks like this: - -```c -__wasi_errno_t __wasi_fd_read( - __wasi_fd_t fd, - const __wasi_iovec_t *iovs, - size_t iovs_len, - __wasi_size_t *retptr0 -); -``` - -## Pointers - -Witx supports two pointer types, `pointer` and `const_pointer`, which represent -pointers into the exported linear memory named "memory". `const_pointer` in a -function declaration documents that the function does not use the pointer for -mutating memory. Similar to C, they can point to either a single value or an -contiguous array of values. - -Pointer arguments use the `@witx` syntax inspired by the [annotations proposal]. - -For example, the `poll_oneoff` function has these arguments: - -```witx - (param $in (@witx const_pointer $subscription)) - (param $out (@witx pointer $event)) -``` - -Pointer values are expected to be aligned, to the alignment of their pointee -type. If a misaligned pointer is passed to a function, the function shall trap. - -If an out-of-bounds pointer is passed to a function and the function needs -to dereference it, the function shall trap rather than returning -`errno.fault`. - -[module linking proposal]: https://github.com/WebAssembly/module-linking/ -[interface types]: https://github.com/WebAssembly/interface-types/blob/main/proposals/interface-types/Explainer.md -[wat format]: https://webassembly.github.io/spec/core/bikeshed/index.html#text-format%E2%91%A0 -[S-expressions]: https://en.wikipedia.org/wiki/S-expression -[WASI]: https://github.com/WebAssembly/WASI -[Wit]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md -[Wit language]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md -[Canonical ABI]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md -[migrating]: https://github.com/WebAssembly/wasi#important-note-wasi-is-in-transition -[annotations proposal]: https://github.com/WebAssembly/annotations diff --git a/legacy/tools/witx/.gitignore b/legacy/tools/witx/.gitignore deleted file mode 100644 index a9d37c560..000000000 --- a/legacy/tools/witx/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -target -Cargo.lock diff --git a/legacy/tools/witx/Cargo.toml b/legacy/tools/witx/Cargo.toml deleted file mode 100644 index 9ab6ac28c..000000000 --- a/legacy/tools/witx/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "witx" -version = "0.9.1" -description = "Parse and validate witx file format" -homepage = "https://github.com/WebAssembly/WASI" -repository = "https://github.com/WebAssembly/WASI" -license = "Apache-2.0" -categories = ["wasm"] -keywords = ["webassembly", "wasm"] -authors = ["Pat Hickey ", "Alex Crichton "] -edition = "2018" - -[lib] -crate-type=["rlib"] - -[dependencies] -anyhow = "1" -log = "0.4" -thiserror = "1.0" -wast = { version = "35.0.2", default-features = false } - -[dev-dependencies] -rayon = "1.0" - -[[test]] -name = "witxt" -harness = false diff --git a/legacy/tools/witx/LICENSE b/legacy/tools/witx/LICENSE deleted file mode 100644 index e061f56ab..000000000 --- a/legacy/tools/witx/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright 2019 WebAssembly Community Group participants - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/legacy/tools/witx/src/abi.rs b/legacy/tools/witx/src/abi.rs deleted file mode 100644 index 0e1ca9cb4..000000000 --- a/legacy/tools/witx/src/abi.rs +++ /dev/null @@ -1,925 +0,0 @@ -//! Definition of the ABI of witx functions -//! -//! This module is intended to assist with code generators which are binding or -//! implementing APIs defined by `*.witx` files. THis module contains all -//! details necessary to implement the actual ABI of these functions so wasm -//! modules and hosts can communicate with one another. -//! -//! Each interface types function (a function defined in `*.witx`) currently has -//! a well-known wasm signature associated with it. There's then also a standard -//! way to convert from interface-types values (whose representation is defined -//! per-language) into this wasm API. This module is intended to assist with -//! this definition. -//! -//! Contained within are two primary functions, [`InterfaceFunc::call_wasm`] and -//! [`InterfaceFunc::call_interface`]. These functions implement the two ways to -//! interact with an interface types function, namely calling the raw wasm -//! version and calling the high-level version with interface types. These two -//! functions are fed a structure that implements [`Bindgen`]. An instance of -//! [`Bindgen`] receives instructions which are low-level implementation details -//! of how to convert to and from wasm types and interface types. Code -//! generators will need to implement the various instructions to support APIs. - -use crate::{ - BuiltinType, Id, IntRepr, InterfaceFunc, InterfaceFuncParam, NamedType, Type, TypeRef, -}; - -/// Enumerates wasm types used by interface types when lowering/lifting. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum WasmType { - I32, - I64, - F32, - F64, - // NOTE: we don't lower interface types to any other Wasm type, - // e.g. externref, so we don't need to define them here. -} - -impl From for WasmType { - fn from(i: IntRepr) -> WasmType { - match i { - IntRepr::U8 | IntRepr::U16 | IntRepr::U32 => WasmType::I32, - IntRepr::U64 => WasmType::I64, - } - } -} - -/// Possible ABIs for interface functions to have. -/// -/// Note that this is a stopgap until we have more of interface types. Interface -/// types functions do not have ABIs, they have APIs. For the meantime, however, -/// we mandate ABIs to ensure we can all talk to each other. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum Abi { - /// Only stable ABI currently, and is the historical WASI ABI since it was - /// first created. - /// - /// Note that this ABI is limited notably in its return values where it can - /// only return 0 results or one `Result` lookalike. - Preview1, -} - -// Helper macro for defining instructions without having to have tons of -// exhaustive `match` statements to update -macro_rules! def_instruction { - ( - $( #[$enum_attr:meta] )* - pub enum Instruction<'a> { - $( - $( #[$attr:meta] )* - $variant:ident $( { - $($field:ident : $field_ty:ty $(,)* )* - } )? - : - [$num_popped:expr] => [$num_pushed:expr], - )* - } - ) => { - $( #[$enum_attr] )* - pub enum Instruction<'a> { - $( - $( #[$attr] )* - $variant $( { - $( - $field : $field_ty, - )* - } )? , - )* - } - - impl Instruction<'_> { - /// How many operands does this instruction pop from the stack? - #[allow(unused_variables)] - pub fn operands_len(&self) -> usize { - match self { - $( - Self::$variant $( { - $( - $field, - )* - } )? => $num_popped, - )* - } - } - - /// How many results does this instruction push onto the stack? - #[allow(unused_variables)] - pub fn results_len(&self) -> usize { - match self { - $( - Self::$variant $( { - $( - $field, - )* - } )? => $num_pushed, - )* - } - } - } - }; -} - -def_instruction! { - #[derive(Debug)] - pub enum Instruction<'a> { - /// Acquires the specified parameter and places it on the stack. - /// Depending on the context this may refer to wasm parameters or - /// interface types parameters. - GetArg { nth: usize } : [0] => [1], - /// Takes the value off the top of the stack and writes it into linear - /// memory. Pushes the address in linear memory as an `i32`. - AddrOf : [1] => [1], - /// Converts an interface type `char` value to a 32-bit integer - /// representing the unicode scalar value. - I32FromChar : [1] => [1], - /// Converts an interface type `u64` value to a wasm `i64`. - I64FromU64 : [1] => [1], - /// Converts an interface type `s64` value to a wasm `i64`. - I64FromS64 : [1] => [1], - /// Converts an interface type `u32` value to a wasm `i32`. - I32FromU32 : [1] => [1], - /// Converts an interface type `s32` value to a wasm `i32`. - I32FromS32 : [1] => [1], - /// Converts a language-specific `usize` value to a wasm `i32`. - I32FromUsize : [1] => [1], - /// Converts an interface type `u16` value to a wasm `i32`. - I32FromU16 : [1] => [1], - /// Converts an interface type `s16` value to a wasm `i32`. - I32FromS16 : [1] => [1], - /// Converts an interface type `u8` value to a wasm `i32`. - I32FromU8 : [1] => [1], - /// Converts an interface type `s8` value to a wasm `i32`. - I32FromS8 : [1] => [1], - /// Converts a language-specific C `char` value to a wasm `i32`. - I32FromChar8 : [1] => [1], - /// Converts a language-specific pointer value to a wasm `i32`. - I32FromPointer : [1] => [1], - /// Converts a language-specific pointer value to a wasm `i32`. - I32FromConstPointer : [1] => [1], - /// Converts a language-specific handle value to a wasm `i32`. - I32FromHandle { ty: &'a NamedType } : [1] => [1], - /// Converts a language-specific record-of-bools to the packed - /// representation as an `i32`. - I32FromBitflags { ty: &'a NamedType } : [1] => [1], - /// Converts a language-specific record-of-bools to the packed - /// representation as an `i64`. - I64FromBitflags { ty: &'a NamedType } : [1] => [1], - /// Converts an interface type list into its pointer/length, pushing - /// them both on the stack. - ListPointerLength : [1] => [2], - /// Pops two `i32` values from the stack and creates a list from them of - /// the specified type. The first operand is the pointer in linear - /// memory to the start of the list and the second operand is the - /// length. - ListFromPointerLength { ty: &'a TypeRef } : [2] => [1], - /// Conversion an interface type `f32` value to a wasm `f32`. - /// - /// This may be a noop for some implementations, but it's here in case the - /// native language representation of `f32` is different than the wasm - /// representation of `f32`. - F32FromIf32 : [1] => [1], - /// Conversion an interface type `f64` value to a wasm `f64`. - /// - /// This may be a noop for some implementations, but it's here in case the - /// native language representation of `f64` is different than the wasm - /// representation of `f64`. - F64FromIf64 : [1] => [1], - - /// Represents a call to a raw WebAssembly API. The module/name are - /// provided inline as well as the types if necessary. - CallWasm { - module: &'a str, - name: &'a str, - params: &'a [WasmType], - results: &'a [WasmType], - } : [params.len()] => [results.len()], - - /// Same as `CallWasm`, except the dual where an interface is being - /// called rather than a raw wasm function. - CallInterface { - module: &'a str, - func: &'a InterfaceFunc, - } : [func.params.len()] => [func.results.len()], - - /// Converts a native wasm `i32` to an interface type `s8`. - /// - /// This will truncate the upper bits of the `i32`. - S8FromI32 : [1] => [1], - /// Converts a native wasm `i32` to an interface type `u8`. - /// - /// This will truncate the upper bits of the `i32`. - U8FromI32 : [1] => [1], - /// Converts a native wasm `i32` to an interface type `s16`. - /// - /// This will truncate the upper bits of the `i32`. - S16FromI32 : [1] => [1], - /// Converts a native wasm `i32` to an interface type `u16`. - /// - /// This will truncate the upper bits of the `i32`. - U16FromI32 : [1] => [1], - /// Converts a native wasm `i32` to an interface type `s32`. - S32FromI32 : [1] => [1], - /// Converts a native wasm `i32` to an interface type `u32`. - U32FromI32 : [1] => [1], - /// Converts a native wasm `i64` to an interface type `s64`. - S64FromI64 : [1] => [1], - /// Converts a native wasm `i64` to an interface type `u64`. - U64FromI64 : [1] => [1], - /// Converts a native wasm `i32` to an interface type `char`. - /// - /// It's safe to assume that the `i32` is indeed a valid unicode code point. - CharFromI32 : [1] => [1], - /// Converts a native wasm `i32` to a language-specific C `char`. - /// - /// This will truncate the upper bits of the `i32`. - Char8FromI32 : [1] => [1], - /// Converts a native wasm `i32` to a language-specific `usize`. - UsizeFromI32 : [1] => [1], - /// Converts a native wasm `f32` to an interface type `f32`. - If32FromF32 : [1] => [1], - /// Converts a native wasm `f64` to an interface type `f64`. - If64FromF64 : [1] => [1], - /// Converts a native wasm `i32` to an interface type `handle`. - HandleFromI32 { ty: &'a NamedType } : [1] => [1], - /// Converts a native wasm `i32` to a language-specific pointer. - PointerFromI32 { ty: &'a TypeRef }: [1] => [1], - /// Converts a native wasm `i32` to a language-specific pointer. - ConstPointerFromI32 { ty: &'a TypeRef } : [1] => [1], - /// Converts a native wasm `i32` to a language-specific record-of-bools. - BitflagsFromI32 { ty: &'a NamedType } : [1] => [1], - /// Converts a native wasm `i64` to a language-specific record-of-bools. - BitflagsFromI64 { ty: &'a NamedType } : [1] => [1], - /// Acquires the return pointer `n` and pushes an `i32` on the stack. - /// - /// Implementations of [`Bindgen`] may have [`Bindgen::allocate_space`] - /// called to reserve space in memory for the result of a computation to - /// get written. This instruction acquires a pointer to the space - /// reserved in `allocate_space`. - ReturnPointerGet { n: usize } : [0] => [1], - /// Loads the interface types value from an `i32` pointer popped from - /// the stack. - Load { ty: &'a NamedType } : [1] => [1], - /// Stores an interface types value into linear memory. The first - /// operand is the value to store and the second operand is the pointer - /// in linear memory to store it at. - Store { ty: &'a NamedType } : [2] => [0], - /// Pops a native wasm `i32` from the stack, as well as two blocks - /// internally from the code generator. - /// - /// If the value is 0 then the first "ok" block value should be used. - /// If the value is anything else then the second "err" block value - /// should be used, and the value is used as the error enum. - /// - /// Note that this is a special instruction matching the current ABI of - /// WASI and intentionally differs from the type-level grammar of - /// interface types results. - ResultLift : [1] => [1], - /// Pops a native interface value from the stack as well as two blocks - /// internally from the code generator. - /// - /// A `match` is performed on the value popped and the corresponding - /// block for ok/err is used depending on value. This pushes a single - /// `i32` onto the stack representing the error code for this result. - /// - /// Note that like `ResultLift` this is specialized to the current WASI - /// ABI. - ResultLower { - ok: Option<&'a TypeRef>, - err: Option<&'a TypeRef>, - } : [1] => [1], - /// Converts a native wasm `i32` to an interface type `enum` value. - /// - /// It's guaranteed that the interface type integer value is within - /// range for this enum's type. Additionally `ty` is guaranteed to be - /// enum-like as a `Variant` where all `case` arms have no associated - /// type with them. The purpose of this instruction is to convert a - /// native wasm integer into the enum type for the interface. - EnumLift { ty: &'a NamedType } : [1] => [1], - /// Converts an interface types enum value into a wasm `i32`. - EnumLower { ty: &'a NamedType } : [1] => [1], - /// Creates a tuple from the top `n` elements on the stack, pushing the - /// tuple onto the stack. - TupleLift { amt: usize } : [*amt] => [1], - /// Splits a tuple at the top of the stack into its `n` components, - /// pushing them all onto the stack. - TupleLower { amt: usize } : [1] => [*amt], - /// This is a special instruction specifically for the original ABI of - /// WASI. The raw return `i32` of a function is re-pushed onto the - /// stack for reuse. - ReuseReturn : [0] => [1], - /// Returns `amt` values on the stack. This is always the last - /// instruction. - Return { amt: usize } : [*amt] => [0], - /// This is a special instruction used at the entry of blocks used as - /// part of `ResultLower`, representing that the payload of that variant - /// being matched on should be pushed onto the stack. - VariantPayload : [0] => [1], - } -} - -impl Abi { - /// Validates the parameters/results are representable in this ABI. - /// - /// Returns an error string if they're not representable or returns `Ok` if - /// they're indeed representable. - pub fn validate( - &self, - _params: &[InterfaceFuncParam], - results: &[InterfaceFuncParam], - ) -> Result<(), String> { - assert_eq!(*self, Abi::Preview1); - match results.len() { - 0 => {} - 1 => match &**results[0].tref.type_() { - Type::Handle(_) | Type::Builtin(_) | Type::ConstPointer(_) | Type::Pointer(_) => {} - Type::Variant(v) => { - let (ok, err) = match v.as_expected() { - Some(pair) => pair, - None => return Err("invalid return type".to_string()), - }; - if let Some(ty) = ok { - match &**ty.type_() { - Type::Record(r) if r.is_tuple() => { - for member in r.members.iter() { - if !member.tref.named() { - return Err( - "only named types are allowed in results".to_string() - ); - } - } - } - _ => { - if !ty.named() { - return Err( - "only named types are allowed in results".to_string() - ); - } - } - } - } - if let Some(ty) = err { - if !ty.named() { - return Err("only named types are allowed in results".to_string()); - } - if let Type::Variant(v) = &**ty.type_() { - if v.is_enum() { - return Ok(()); - } - } - } - } - Type::Record(r) if r.bitflags_repr().is_some() => {} - Type::Record(_) | Type::List(_) => return Err("invalid return type".to_string()), - }, - _ => return Err("more than one result".to_string()), - } - Ok(()) - } -} - -/// Trait for language implementors to use to generate glue code between native -/// WebAssembly signatures and interface types signatures. -/// -/// This is used as an implementation detail in interpreting the ABI between -/// interface types and wasm types. Eventually this will be driven by interface -/// types adapters themselves, but for now the ABI of a function dictates what -/// instructions are fed in. -/// -/// Types implementing `Bindgen` are incrementally fed `Instruction` values to -/// generate code for. Instructions operate like a stack machine where each -/// instruction has a list of inputs and a list of outputs (provided by the -/// `emit` function). -pub trait Bindgen { - /// The intermediate type for fragments of code for this type. - /// - /// For most languages `String` is a suitable intermediate type. - type Operand; - - /// Emit code to implement the given instruction. - /// - /// Each operand is given in `operands` and can be popped off if ownership - /// is required. It's guaranteed that `operands` has the appropriate length - /// for the `inst` given, as specified with [`Instruction`]. - /// - /// Each result variable should be pushed onto `results`. This function must - /// push the appropriate number of results or binding generation will panic. - fn emit( - &mut self, - inst: &Instruction<'_>, - operands: &mut Vec, - results: &mut Vec, - ); - - /// Allocates temporary space in linear memory indexed by `slot` with enough - /// space to store `ty`. - /// - /// This is called when calling some wasm functions where a return pointer - /// is needed. - fn allocate_space(&mut self, slot: usize, ty: &NamedType); - - /// Enters a new block of code to generate code for. - /// - /// This is currently exclusively used for constructing variants. When a - /// variant is constructed a block here will be pushed for each case of a - /// variant, generating the code necessary to translate a variant case. - /// - /// Blocks are completed with `finish_block` below. It's expected that `emit` - /// will always push code (if necessary) into the "current block", which is - /// updated by calling this method and `finish_block` below. - fn push_block(&mut self); - - /// Indicates to the code generator that a block is completed, and the - /// `operand` specified was the resulting value of the block. - /// - /// This method will be used to compute the value of each arm of lifting a - /// variant. The `operand` will be `None` if the variant case didn't - /// actually have any type associated with it. Otherwise it will be `Some` - /// as the last value remaining on the stack representing the value - /// associated with a variant's `case`. - /// - /// It's expected that this will resume code generation in the previous - /// block before `push_block` was called. This must also save the results - /// of the current block internally for instructions like `ResultLift` to - /// use later. - fn finish_block(&mut self, operand: Option); -} - -impl InterfaceFunc { - /// Get the WebAssembly type signature for this interface function - /// - /// The first entry returned is the list of parameters and the second entry - /// is the list of results for the wasm function signature. - pub fn wasm_signature(&self) -> (Vec, Vec) { - assert_eq!(self.abi, Abi::Preview1); - let mut params = Vec::new(); - let mut results = Vec::new(); - for param in self.params.iter() { - match &**param.tref.type_() { - Type::Builtin(BuiltinType::S8) - | Type::Builtin(BuiltinType::U8 { .. }) - | Type::Builtin(BuiltinType::S16) - | Type::Builtin(BuiltinType::U16) - | Type::Builtin(BuiltinType::S32) - | Type::Builtin(BuiltinType::U32 { .. }) - | Type::Builtin(BuiltinType::Char) - | Type::Pointer(_) - | Type::ConstPointer(_) - | Type::Handle(_) - | Type::Variant(_) => params.push(WasmType::I32), - - Type::Record(r) => match r.bitflags_repr() { - Some(repr) => params.push(WasmType::from(repr)), - None => params.push(WasmType::I32), - }, - - Type::Builtin(BuiltinType::S64) | Type::Builtin(BuiltinType::U64) => { - params.push(WasmType::I64) - } - - Type::Builtin(BuiltinType::F32) => params.push(WasmType::F32), - Type::Builtin(BuiltinType::F64) => params.push(WasmType::F64), - - Type::List(_) => { - params.push(WasmType::I32); - params.push(WasmType::I32); - } - } - } - - for param in self.results.iter() { - match &**param.tref.type_() { - Type::Builtin(BuiltinType::S8) - | Type::Builtin(BuiltinType::U8 { .. }) - | Type::Builtin(BuiltinType::S16) - | Type::Builtin(BuiltinType::U16) - | Type::Builtin(BuiltinType::S32) - | Type::Builtin(BuiltinType::U32 { .. }) - | Type::Builtin(BuiltinType::Char) - | Type::Pointer(_) - | Type::ConstPointer(_) - | Type::Handle(_) => results.push(WasmType::I32), - - Type::Builtin(BuiltinType::S64) | Type::Builtin(BuiltinType::U64) => { - results.push(WasmType::I64) - } - - Type::Builtin(BuiltinType::F32) => results.push(WasmType::F32), - Type::Builtin(BuiltinType::F64) => results.push(WasmType::F64), - - Type::Record(r) => match r.bitflags_repr() { - Some(repr) => results.push(WasmType::from(repr)), - None => unreachable!(), - }, - Type::List(_) => unreachable!(), - - Type::Variant(v) => { - results.push(match v.tag_repr { - IntRepr::U64 => WasmType::I64, - IntRepr::U32 | IntRepr::U16 | IntRepr::U8 => WasmType::I32, - }); - if v.is_enum() { - continue; - } - // return pointer - if let Some(ty) = &v.cases[0].tref { - match &**ty.type_() { - Type::Record(r) if r.is_tuple() => { - for _ in 0..r.members.len() { - params.push(WasmType::I32); - } - } - _ => params.push(WasmType::I32), - } - } - } - } - } - (params, results) - } - - /// Generates an abstract sequence of instructions which represents this - /// function being adapted as an imported function. - /// - /// The instructions here, when executed, will emulate a language with - /// interface types calling the concrete wasm implementation. The parameters - /// for the returned instruction sequence are the language's own - /// interface-types parameters. One instruction in the instruction stream - /// will be a `Call` which represents calling the actual raw wasm function - /// signature. - /// - /// This function is useful, for example, if you're building a language - /// generator for WASI bindings. This will document how to translate - /// language-specific values into the wasm types to call a WASI function, - /// and it will also automatically convert the results of the WASI function - /// back to a language-specific value. - pub fn call_wasm(&self, module: &Id, bindgen: &mut impl Bindgen) { - assert_eq!(self.abi, Abi::Preview1); - Generator { - bindgen, - operands: vec![], - results: vec![], - stack: vec![], - } - .call_wasm(module, self); - } - - /// This is the dual of [`InterfaceFunc::call_wasm`], except that instead of - /// calling a wasm signature it generates code to come from a wasm signature - /// and call an interface types signature. - pub fn call_interface(&self, module: &Id, bindgen: &mut impl Bindgen) { - assert_eq!(self.abi, Abi::Preview1); - Generator { - bindgen, - operands: vec![], - results: vec![], - stack: vec![], - } - .call_interface(module, self); - } -} - -struct Generator<'a, B: Bindgen> { - bindgen: &'a mut B, - operands: Vec, - results: Vec, - stack: Vec, -} - -impl Generator<'_, B> { - fn call_wasm(&mut self, module: &Id, func: &InterfaceFunc) { - // Translate all parameters which are interface values by lowering them - // to their wasm types. - for (nth, param) in func.params.iter().enumerate() { - self.emit(&Instruction::GetArg { nth }); - self.lower(¶m.tref, None); - } - - // If necessary for our ABI, insert return pointers for any returned - // values through a result. - assert!(func.results.len() < 2); - if let Some(result) = func.results.get(0) { - self.prep_return_pointer(&result.tref.type_()); - } - - let (params, results) = func.wasm_signature(); - self.emit(&Instruction::CallWasm { - module: module.as_str(), - name: func.name.as_str(), - params: ¶ms, - results: &results, - }); - - // Lift the return value if one is present. - if let Some(result) = func.results.get(0) { - self.lift(&result.tref, true); - } - - self.emit(&Instruction::Return { - amt: func.results.len(), - }); - } - - fn call_interface(&mut self, module: &Id, func: &InterfaceFunc) { - // Lift all wasm parameters into interface types first. - // - // Note that consuming arguments is somewhat janky right now by manually - // giving lists a second argument for their length. In the future we'll - // probably want to refactor the `lift` function to internally know how - // to consume arguments. - let mut nth = 0; - for param in func.params.iter() { - self.emit(&Instruction::GetArg { nth }); - nth += 1; - if let Type::List(_) = &**param.tref.type_() { - self.emit(&Instruction::GetArg { nth }); - nth += 1; - } - self.lift(¶m.tref, false); - } - - self.emit(&Instruction::CallInterface { - module: module.as_str(), - func, - }); - - // Like above the current ABI only has at most one result, so lower it - // here if necessary. - if let Some(result) = func.results.get(0) { - self.lower(&result.tref, Some(&mut nth)); - } - - let (_params, results) = func.wasm_signature(); - self.emit(&Instruction::Return { amt: results.len() }); - } - - fn emit(&mut self, inst: &Instruction<'_>) { - self.operands.clear(); - self.results.clear(); - - let operands_len = inst.operands_len(); - assert!( - self.stack.len() >= operands_len, - "not enough operands on stack for {:?}", - inst - ); - self.operands - .extend(self.stack.drain((self.stack.len() - operands_len)..)); - self.results.reserve(inst.results_len()); - - self.bindgen - .emit(inst, &mut self.operands, &mut self.results); - - assert_eq!( - self.results.len(), - inst.results_len(), - "{:?} expected {} results, got {}", - inst, - inst.results_len(), - self.results.len() - ); - self.stack.extend(self.results.drain(..)); - } - - fn lower(&mut self, ty: &TypeRef, retptr: Option<&mut usize>) { - use Instruction::*; - match &**ty.type_() { - Type::Builtin(BuiltinType::S8) => self.emit(&I32FromS8), - Type::Builtin(BuiltinType::U8 { lang_c_char: true }) => self.emit(&I32FromChar8), - Type::Builtin(BuiltinType::U8 { lang_c_char: false }) => self.emit(&I32FromU8), - Type::Builtin(BuiltinType::S16) => self.emit(&I32FromS16), - Type::Builtin(BuiltinType::U16) => self.emit(&I32FromU16), - Type::Builtin(BuiltinType::S32) => self.emit(&I32FromS32), - Type::Builtin(BuiltinType::U32 { - lang_ptr_size: true, - }) => self.emit(&I32FromUsize), - Type::Builtin(BuiltinType::U32 { - lang_ptr_size: false, - }) => self.emit(&I32FromU32), - Type::Builtin(BuiltinType::S64) => self.emit(&I64FromS64), - Type::Builtin(BuiltinType::U64) => self.emit(&I64FromU64), - Type::Builtin(BuiltinType::Char) => self.emit(&I32FromChar), - Type::Pointer(_) => self.emit(&I32FromPointer), - Type::ConstPointer(_) => self.emit(&I32FromConstPointer), - Type::Handle(_) => self.emit(&I32FromHandle { - ty: match ty { - TypeRef::Name(ty) => ty, - _ => unreachable!(), - }, - }), - Type::Record(r) => { - let ty = match ty { - TypeRef::Name(ty) => ty, - _ => unreachable!(), - }; - match r.bitflags_repr() { - Some(IntRepr::U64) => self.emit(&I64FromBitflags { ty }), - Some(_) => self.emit(&I32FromBitflags { ty }), - None => self.emit(&AddrOf), - } - } - Type::Variant(v) => { - // Enum-like variants are simply lowered to their discriminant. - if v.is_enum() { - return self.emit(&EnumLower { - ty: match ty { - TypeRef::Name(n) => n, - _ => unreachable!(), - }, - }); - } - - // If this variant is in the return position then it's special, - // otherwise it's an argument and we just pass the address. - let retptr = match retptr { - Some(ptr) => ptr, - None => return self.emit(&AddrOf), - }; - - // For the return position we emit some blocks to lower the - // ok/err payloads which means that in the ok branch we're - // storing to out-params and in the err branch we're simply - // lowering the error enum. - // - // Note that this is all very specific to the current WASI ABI. - let (ok, err) = v.as_expected().unwrap(); - self.bindgen.push_block(); - if let Some(ok) = ok { - self.emit(&VariantPayload); - let store = |me: &mut Self, ty: &TypeRef, n| { - me.emit(&GetArg { nth: *retptr + n }); - match ty { - TypeRef::Name(ty) => me.emit(&Store { ty }), - _ => unreachable!(), - } - }; - match &**ok.type_() { - Type::Record(r) if r.is_tuple() => { - self.emit(&TupleLower { - amt: r.members.len(), - }); - // Note that `rev()` is used here due to the order - // that tuples are pushed onto the stack and how we - // consume the last item first from the stack. - for (i, member) in r.members.iter().enumerate().rev() { - store(self, &member.tref, i); - } - } - _ => store(self, ok, 0), - } - }; - self.bindgen.finish_block(None); - - self.bindgen.push_block(); - let err_expr = if let Some(ty) = err { - self.emit(&VariantPayload); - self.lower(ty, None); - Some(self.stack.pop().unwrap()) - } else { - None - }; - self.bindgen.finish_block(err_expr); - - self.emit(&ResultLower { ok, err }); - } - Type::Builtin(BuiltinType::F32) => self.emit(&F32FromIf32), - Type::Builtin(BuiltinType::F64) => self.emit(&F64FromIf64), - Type::List(_) => self.emit(&ListPointerLength), - } - } - - fn prep_return_pointer(&mut self, ty: &Type) { - // Return pointers are only needed for `Result`... - let variant = match ty { - Type::Variant(v) => v, - _ => return, - }; - // ... and only if `T` is actually present in `Result` - let ok = match &variant.cases[0].tref { - Some(t) => t, - None => return, - }; - - // Tuples have each individual item in a separate return pointer while - // all other types go through a singular return pointer. - let mut n = 0; - let mut prep = |ty: &TypeRef| { - match ty { - TypeRef::Name(ty) => self.bindgen.allocate_space(n, ty), - _ => unreachable!(), - } - self.emit(&Instruction::ReturnPointerGet { n }); - n += 1; - }; - match &**ok.type_() { - Type::Record(r) if r.is_tuple() => { - for member in r.members.iter() { - prep(&member.tref); - } - } - _ => prep(ok), - } - } - - // Note that in general everything in this function is the opposite of the - // `lower` function above. This is intentional and should be kept this way! - fn lift(&mut self, ty: &TypeRef, is_return: bool) { - use Instruction::*; - match &**ty.type_() { - Type::Builtin(BuiltinType::S8) => self.emit(&S8FromI32), - Type::Builtin(BuiltinType::U8 { lang_c_char: true }) => self.emit(&Char8FromI32), - Type::Builtin(BuiltinType::U8 { lang_c_char: false }) => self.emit(&U8FromI32), - Type::Builtin(BuiltinType::S16) => self.emit(&S16FromI32), - Type::Builtin(BuiltinType::U16) => self.emit(&U16FromI32), - Type::Builtin(BuiltinType::S32) => self.emit(&S32FromI32), - Type::Builtin(BuiltinType::U32 { - lang_ptr_size: true, - }) => self.emit(&UsizeFromI32), - Type::Builtin(BuiltinType::U32 { - lang_ptr_size: false, - }) => self.emit(&U32FromI32), - Type::Builtin(BuiltinType::S64) => self.emit(&S64FromI64), - Type::Builtin(BuiltinType::U64) => self.emit(&U64FromI64), - Type::Builtin(BuiltinType::Char) => self.emit(&CharFromI32), - Type::Builtin(BuiltinType::F32) => self.emit(&If32FromF32), - Type::Builtin(BuiltinType::F64) => self.emit(&If64FromF64), - Type::Pointer(ty) => self.emit(&PointerFromI32 { ty }), - Type::ConstPointer(ty) => self.emit(&ConstPointerFromI32 { ty }), - Type::Handle(_) => self.emit(&HandleFromI32 { - ty: match ty { - TypeRef::Name(ty) => ty, - _ => unreachable!(), - }, - }), - Type::Variant(v) => { - if v.is_enum() { - return self.emit(&EnumLift { - ty: match ty { - TypeRef::Name(n) => n, - _ => unreachable!(), - }, - }); - } else if !is_return { - return self.emit(&Load { - ty: match ty { - TypeRef::Name(n) => n, - _ => unreachable!(), - }, - }); - } - - let (ok, err) = v.as_expected().unwrap(); - self.bindgen.push_block(); - let ok_expr = if let Some(ok) = ok { - let mut n = 0; - let mut load = |ty: &TypeRef| { - self.emit(&ReturnPointerGet { n }); - n += 1; - match ty { - TypeRef::Name(ty) => self.emit(&Load { ty }), - _ => unreachable!(), - } - }; - match &**ok.type_() { - Type::Record(r) if r.is_tuple() => { - for member in r.members.iter() { - load(&member.tref); - } - self.emit(&TupleLift { - amt: r.members.len(), - }); - } - _ => load(ok), - } - Some(self.stack.pop().unwrap()) - } else { - None - }; - self.bindgen.finish_block(ok_expr); - - self.bindgen.push_block(); - let err_expr = if let Some(ty) = err { - self.emit(&ReuseReturn); - self.lift(ty, false); - Some(self.stack.pop().unwrap()) - } else { - None - }; - self.bindgen.finish_block(err_expr); - - self.emit(&ResultLift); - } - Type::Record(r) => { - let ty = match ty { - TypeRef::Name(ty) => ty, - _ => unreachable!(), - }; - match r.bitflags_repr() { - Some(IntRepr::U64) => self.emit(&BitflagsFromI64 { ty }), - Some(_) => self.emit(&BitflagsFromI32 { ty }), - None => self.emit(&Load { ty }), - } - } - Type::List(ty) => self.emit(&ListFromPointerLength { ty }), - } - } -} diff --git a/legacy/tools/witx/src/ast.rs b/legacy/tools/witx/src/ast.rs deleted file mode 100644 index ee985d302..000000000 --- a/legacy/tools/witx/src/ast.rs +++ /dev/null @@ -1,591 +0,0 @@ -use crate::Abi; -use std::collections::{HashMap, HashSet}; -use std::rc::{Rc, Weak}; - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Id(String); - -impl Id { - pub fn new>(s: S) -> Self { - Id(s.as_ref().to_string()) - } - pub fn as_str(&self) -> &str { - self.0.as_str() - } -} - -impl AsRef for Id { - fn as_ref(&self) -> &str { - self.0.as_ref() - } -} - -impl PartialEq<&str> for Id { - fn eq(&self, rhs: &&str) -> bool { - PartialEq::eq(self.as_ref(), *rhs) - } -} - -impl PartialEq for &str { - fn eq(&self, rhs: &Id) -> bool { - PartialEq::eq(*self, rhs.as_ref()) - } -} - -impl From<&str> for Id { - fn from(s: &str) -> Self { - Self::new(s) - } -} - -#[derive(Debug, Clone)] -pub struct Document { - definitions: Vec, - entries: HashMap, -} - -impl Document { - pub(crate) fn new(definitions: Vec, entries: HashMap) -> Self { - Document { - definitions, - entries, - } - } - pub fn typename(&self, name: &Id) -> Option> { - self.entries.get(name).and_then(|e| match e { - Entry::Typename(nt) => Some(nt.upgrade().expect("always possible to upgrade entry")), - _ => None, - }) - } - pub fn typenames<'a>(&'a self) -> impl Iterator> + 'a { - self.definitions.iter().filter_map(|d| match d { - Definition::Typename(nt) => Some(nt.clone()), - _ => None, - }) - } - /// All of the (unique) types used as "err" variant of results returned from - /// functions. - pub fn error_types<'a>(&'a self) -> impl Iterator + 'a { - let errors: HashSet = self - .modules() - .flat_map(|m| { - m.funcs() - .filter_map(|f| { - if f.results.len() == 1 { - Some(f.results[0].tref.type_().clone()) - } else { - None - } - }) - .filter_map(|t| match &*t { - Type::Variant(v) => { - let (_ok, err) = v.as_expected()?; - Some(err?.clone()) - } - _ => None, - }) - .collect::>() - }) - .collect(); - errors.into_iter() - } - pub fn module(&self, name: &Id) -> Option> { - self.entries.get(&name).and_then(|e| match e { - Entry::Module(m) => Some(m.upgrade().expect("always possible to upgrade entry")), - _ => None, - }) - } - pub fn modules<'a>(&'a self) -> impl Iterator> + 'a { - self.definitions.iter().filter_map(|d| match d { - Definition::Module(m) => Some(m.clone()), - _ => None, - }) - } - - pub fn constants<'a>(&'a self) -> impl Iterator + 'a { - self.definitions.iter().filter_map(|d| match d { - Definition::Constant(c) => Some(c), - _ => None, - }) - } -} - -impl PartialEq for Document { - fn eq(&self, rhs: &Document) -> bool { - // For equality, we don't care about the ordering of definitions, - // so we only need to check that the entries map is equal - self.entries == rhs.entries - } -} -impl Eq for Document {} - -impl std::hash::Hash for Document { - fn hash(&self, state: &mut H) { - std::hash::Hash::hash(&self.definitions, state); - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum Definition { - Typename(Rc), - Module(Rc), - Constant(Constant), -} - -#[derive(Debug, Clone)] -pub enum Entry { - Typename(Weak), - Module(Weak), -} - -impl Entry { - pub fn kind(&self) -> &'static str { - match self { - Entry::Typename { .. } => "typename", - Entry::Module { .. } => "module", - } - } -} - -impl PartialEq for Entry { - fn eq(&self, rhs: &Entry) -> bool { - match (self, rhs) { - (Entry::Typename(t), Entry::Typename(t_rhs)) => { - t.upgrade() - .expect("possible to upgrade entry when part of document") - == t_rhs - .upgrade() - .expect("possible to upgrade entry when part of document") - } - (Entry::Module(m), Entry::Module(m_rhs)) => { - m.upgrade() - .expect("possible to upgrade entry when part of document") - == m_rhs - .upgrade() - .expect("possible to upgrade entry when part of document") - } - _ => false, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum TypeRef { - Name(Rc), - Value(Rc), -} - -impl TypeRef { - pub fn type_(&self) -> &Rc { - match self { - TypeRef::Name(named) => named.type_(), - TypeRef::Value(v) => v, - } - } - - pub fn named(&self) -> bool { - match self { - TypeRef::Name(_) => true, - TypeRef::Value(_) => false, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct NamedType { - pub name: Id, - pub tref: TypeRef, - pub docs: String, -} - -impl NamedType { - pub fn type_(&self) -> &Rc { - self.tref.type_() - } -} - -/// Structure of all possible interface types. -/// -/// Note that this is intended to match the interface types proposal itself. -/// Currently this is relatively close to that with just a few `*.witx` -/// extensions for now. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum Type { - /// A structure with named field. - Record(RecordDatatype), - /// An enumeration where a value is one of a number of variants. - Variant(Variant), - /// A "handle" which is an un-forgeable reference. Today this is an `i32` - /// where a module can't forge and use integers it was not already given - /// access to. - Handle(HandleDatatype), - /// A list of a type, stored in linear memory. - /// - /// Note that lists of `char` are specialized to indicate strings. - List(TypeRef), - /// A `witx`-specific type representing a raw mutable pointer into linear - /// memory - Pointer(TypeRef), - /// A `witx`-specific type representing a raw const pointer into linear - /// memory - ConstPointer(TypeRef), - /// A builtin base-case type. - Builtin(BuiltinType), -} - -impl Type { - /// Returns a human-readable string to describe this type. - pub fn kind(&self) -> &'static str { - use Type::*; - match self { - Record(_) => "record", - Variant(_) => "variant", - Handle(_) => "handle", - List(_) => "list", - Pointer(_) => "pointer", - ConstPointer(_) => "constpointer", - Builtin(_) => "builtin", - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum BuiltinType { - /// This is a 32-bit unicode scalar value, not a code point. - /// - /// Same as the Rust language's `char` type. - Char, - /// An 8-bit unsigned integer. - U8 { - /// Indicates whether this type is intended to represent the `char` - /// type in the C language. The C `char` type is often unsigned, but - /// it's language-specific. At an interface-types level this is an - /// unsigned byte but binding generators may wish to bind this as the - /// language-specific representation for a C character instead. - /// - /// This is also currently used exclusively in conjunction with `@witx - /// pointer` to hint that it's pointing to unicode string data as well. - lang_c_char: bool, - }, - /// A 16-bit unsigned integer. - U16, - /// A 32-bit unsigned integer. - U32 { - /// Indicates that this 32-bit value should actually be considered a - /// pointer-like value in language bindings. At the interface types - /// layer this is always a 32-bit unsigned value, but binding - /// generators may wish to instead bind this as the equivalent of C's - /// `size_t` for convenience with other APIs. - /// - /// This allows witx authors to communicate the intent that the - /// argument or return-value is pointer-like. - lang_ptr_size: bool, - }, - /// A 64-bit unsigned integer. - U64, - /// An 8-bit signed integer - S8, - /// A 16-bit signed integer - S16, - /// A 32-bit signed integer - S32, - /// A 64-bit signed integer - S64, - /// A 32-bit floating point value. - F32, - /// A 64-bit floating point value. - F64, -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum IntRepr { - U8, - U16, - U32, - U64, -} - -impl IntRepr { - pub fn to_builtin(&self) -> BuiltinType { - match self { - IntRepr::U8 => BuiltinType::U8 { lang_c_char: false }, - IntRepr::U16 => BuiltinType::U16, - IntRepr::U32 => BuiltinType::U32 { - lang_ptr_size: false, - }, - IntRepr::U64 => BuiltinType::U64, - } - } -} - -/// A struct-like value with named fields. -/// -/// Records map to `struct`s in most languages where this is a type with a -/// number of named fields that all have their own particular type. Field order -/// dictates layout in memory. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct RecordDatatype { - /// A hint as to what this record might be. - /// - /// Note that in the future this will only be a hint, not a control of the - /// actual representation itself. At this time though the record layout of - /// bitflags is different from other types. - pub kind: RecordKind, - - /// A list of named fields for this record. - pub members: Vec, -} - -/// Different kinds of records used for hinting various language-specific types. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum RecordKind { - /// A tuple where the name of all fields are consecutive integers starting - /// at "0". - Tuple, - /// A record where all fields are `bool`s. Currently represented as an - /// integer with bits set or not set. - Bitflags(IntRepr), - /// All other structures. - Other, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct RecordMember { - pub name: Id, - pub tref: TypeRef, - pub docs: String, -} - -impl RecordDatatype { - pub fn is_tuple(&self) -> bool { - match self.kind { - RecordKind::Tuple => true, - _ => false, - } - } - - pub fn bitflags_repr(&self) -> Option { - match self.kind { - RecordKind::Bitflags(i) => Some(i), - _ => None, - } - } -} - -/// A type which represents how values can be one of a set of possible cases. -/// -/// This type maps to an `enum` in languages like Rust, but doesn't have an -/// equivalent in languages like JS or C. The closest analog in C is a tagged -/// union, but a `Variant` is always consistent whereas a tagged union in C -/// could be mis-tagged or such. -/// -/// Variants are used to represent one of a possible set of types. For example -/// an enum-like variant, a result that is either success or failure, or even a -/// simple `bool`. Variants are primarily used heavily with various kinds of -/// shorthands in the `*.witx` format to represent idioms in languages. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Variant { - /// The bit representation of the width of this variant's tag when the - /// variant is stored in memory. - pub tag_repr: IntRepr, - /// The possible cases that values of this variant type can take. - pub cases: Vec, -} - -impl Variant { - /// If this variant looks like an `expected` shorthand, return the ok/err - /// types associated with this result. - /// - /// Only matches variants fo the form: - /// - /// ```text - /// (variant - /// (case "ok" ok?) - /// (case "err" err?)) - /// ``` - pub fn as_expected(&self) -> Option<(Option<&TypeRef>, Option<&TypeRef>)> { - if self.cases.len() != 2 { - return None; - } - if self.cases[0].name != "ok" { - return None; - } - if self.cases[1].name != "err" { - return None; - } - Some((self.cases[0].tref.as_ref(), self.cases[1].tref.as_ref())) - } - - /// Returns whether this variant type is "bool-like" meaning that it matches - /// this type: - /// - /// ```text - /// (variant - /// (case "false") - /// (case "true")) - /// ``` - pub fn is_bool(&self) -> bool { - self.cases.len() == 2 - && self.cases[0].name == "false" - && self.cases[1].name == "true" - && self.cases[0].tref.is_none() - && self.cases[1].tref.is_none() - } - - /// Returns whether this variant type is "enum-like" meaning that all of its - /// cases have no payload associated with them. - pub fn is_enum(&self) -> bool { - self.cases.iter().all(|c| c.tref.is_none()) - } -} - -/// One of a number of possible types that a `Variant` can take. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Case { - /// The name of this case and how to identify it. - pub name: Id, - /// An optional payload type for this case and data that can be associated - /// with it. - pub tref: Option, - /// Documentation for this case. - pub docs: String, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct HandleDatatype {} - -#[derive(Debug, Clone)] -pub struct Module { - pub name: Id, - definitions: Vec, - entries: HashMap, - pub docs: String, -} - -impl Module { - pub(crate) fn new( - name: Id, - definitions: Vec, - entries: HashMap, - docs: String, - ) -> Self { - Module { - name, - definitions, - entries, - docs, - } - } - pub fn import(&self, name: &Id) -> Option> { - self.entries.get(name).and_then(|e| match e { - ModuleEntry::Import(d) => Some(d.upgrade().expect("always possible to upgrade entry")), - _ => None, - }) - } - pub fn imports<'a>(&'a self) -> impl Iterator> + 'a { - self.definitions.iter().filter_map(|d| match d { - ModuleDefinition::Import(d) => Some(d.clone()), - _ => None, - }) - } - pub fn func(&self, name: &Id) -> Option> { - self.entries.get(name).and_then(|e| match e { - ModuleEntry::Func(d) => Some(d.upgrade().expect("always possible to upgrade entry")), - _ => None, - }) - } - pub fn funcs<'a>(&'a self) -> impl Iterator> + 'a { - self.definitions.iter().filter_map(|d| match d { - ModuleDefinition::Func(d) => Some(d.clone()), - _ => None, - }) - } -} - -impl PartialEq for Module { - fn eq(&self, rhs: &Module) -> bool { - // For equality, we don't care about the ordering of definitions, - // so we only need to check that the entries map is equal - self.name == rhs.name && self.entries == rhs.entries && self.docs == rhs.docs - } -} -impl Eq for Module {} - -impl std::hash::Hash for Module { - fn hash(&self, state: &mut H) { - std::hash::Hash::hash(&self.name, state); - std::hash::Hash::hash(&self.definitions, state); - std::hash::Hash::hash(&self.docs, state); - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ModuleDefinition { - Import(Rc), - Func(Rc), -} - -#[derive(Debug, Clone)] -pub enum ModuleEntry { - Import(Weak), - Func(Weak), -} - -impl PartialEq for ModuleEntry { - fn eq(&self, rhs: &ModuleEntry) -> bool { - match (self, rhs) { - (ModuleEntry::Import(i), ModuleEntry::Import(i_rhs)) => { - i.upgrade() - .expect("always possible to upgrade moduleentry when part of module") - == i_rhs - .upgrade() - .expect("always possible to upgrade moduleentry when part of module") - } - (ModuleEntry::Func(i), ModuleEntry::Func(i_rhs)) => { - i.upgrade() - .expect("always possible to upgrade moduleentry when part of module") - == i_rhs - .upgrade() - .expect("always possible to upgrade moduleentry when part of module") - } - _ => false, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ModuleImport { - pub name: Id, - pub variant: ModuleImportVariant, - pub docs: String, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ModuleImportVariant { - Memory, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct InterfaceFunc { - pub abi: Abi, - pub name: Id, - pub params: Vec, - pub results: Vec, - pub noreturn: bool, - pub docs: String, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct InterfaceFuncParam { - pub name: Id, - pub tref: TypeRef, - pub docs: String, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Constant { - pub ty: Id, - pub name: Id, - pub value: u64, - pub docs: String, -} diff --git a/legacy/tools/witx/src/docs/ast.rs b/legacy/tools/witx/src/docs/ast.rs deleted file mode 100644 index a295a6756..000000000 --- a/legacy/tools/witx/src/docs/ast.rs +++ /dev/null @@ -1,503 +0,0 @@ -use super::{ - md::{MdFunc, MdHeading, MdNamedType, MdNodeRef, MdSection, ToMarkdown}, - Documentation, -}; -use crate::{ - ast::*, - layout::Layout, - polyfill::{FuncPolyfill, ModulePolyfill, ParamPolyfill, Polyfill, TypePolyfill}, - RepEquality, -}; -use std::collections::HashMap; - -fn heading_from_node(node: &MdNodeRef, levels_down: usize) -> MdHeading { - MdHeading::new_header(node.borrow().ancestors().len() + levels_down) -} - -impl ToMarkdown for Document { - fn generate(&self, node: MdNodeRef) { - let heading = heading_from_node(&node, 1); - let types = node.new_child(MdSection::new(heading, "Types")); - - let mut constants_by_name = HashMap::new(); - for c in self.constants() { - constants_by_name.entry(&c.ty).or_insert(Vec::new()).push(c); - } - - for d in self.typenames() { - let name = d.name.as_str(); - let child = types.new_child(MdNamedType::new( - heading.new_level_down(), - name, - name, - format!( - "{}\nSize: {}\n\nAlignment: {}\n", - &d.docs, - &d.mem_size(), - &d.mem_align() - ) - .as_str(), - )); - if let Some(constants) = constants_by_name.remove(&d.name) { - let heading = heading_from_node(&child, 1); - child.new_child(MdSection::new(heading, "Constants")); - for constant in constants { - child.new_child(MdNamedType::new( - MdHeading::new_bullet(), - format!("{}.{}", name, constant.name.as_str()).as_str(), - constant.name.as_str(), - &constant.docs, - )); - } - } - d.generate(child.clone()); - } - - let modules = node.new_child(MdSection::new(heading, "Modules")); - for d in self.modules() { - let mut content = MdSection::new(heading.new_level_down(), d.name.as_str()); - content.id = Some(d.name.as_str().to_owned()); - let child = modules.new_child(content); - d.generate(child.clone()); - } - - assert!(constants_by_name.is_empty()); - } -} - -impl ToMarkdown for TypeRef { - fn generate(&self, node: MdNodeRef) { - match self { - TypeRef::Value(v) => { - v.generate(node.clone()); - node.content_ref_mut::().ty = Some(format!("`{}`", self.type_name())); - } - TypeRef::Name(n) => { - node.content_ref_mut::().ty = - Some(format!("[`{0}`](#{0})", n.name.as_str().to_owned())); - } - } - } -} - -impl ToMarkdown for NamedType { - fn generate(&self, node: MdNodeRef) { - self.tref.generate(node.clone()); - } -} - -impl ToMarkdown for Type { - fn generate(&self, node: MdNodeRef) { - match self { - Self::Record(a) => a.generate(node.clone()), - Self::Variant(a) => a.generate(node.clone()), - Self::Handle(a) => a.generate(node.clone()), - Self::List(_) => {} - Self::Pointer(_) => {} - Self::ConstPointer(_) => {} - Self::Builtin(_) => {} - } - } -} - -impl ToMarkdown for RecordDatatype { - fn generate(&self, node: MdNodeRef) { - let heading = heading_from_node(&node, 1); - node.new_child(MdSection::new(heading, "Record members")); - - for member_layout in &self.member_layout() { - let member = member_layout.member; - let offset = member_layout.offset; - let name = member.name.as_str(); - let id = if let Some(id) = node.any_ref().id() { - format!("{}.{}", id, name) - } else { - name.to_owned() - }; - let (div, offset_desc) = if self.bitflags_repr().is_some() { - (4, "Bit") - } else { - (1, "Offset") - }; - let n = node.new_child(MdNamedType::new( - MdHeading::new_bullet(), - id.as_str(), - name, - format!("{}\n{}: {}\n", &member.docs, offset_desc, offset / div).as_str(), - )); - member.tref.generate(n.clone()); - } - } -} - -impl ToMarkdown for Variant { - fn generate(&self, node: MdNodeRef) { - if self.is_bool() { - return; - } - if self.cases.iter().any(|c| c.tref.is_some()) { - let heading = heading_from_node(&node, 1); - node.new_child(MdSection::new(heading, "Variant Layout")); - - let whole = self.mem_size_align(); - node.new_child(MdSection::new( - MdHeading::new_bullet(), - format!("size: {}", whole.size), - )); - node.new_child(MdSection::new( - MdHeading::new_bullet(), - format!("align: {}", whole.align), - )); - - let tag = self.tag_repr.mem_size_align(); - node.new_child(MdSection::new( - MdHeading::new_bullet(), - format!("tag_size: {}", tag.size), - )); - } - - let heading = heading_from_node(&node, 1); - node.new_child(MdSection::new(heading, "Variant cases")); - - for case in self.cases.iter() { - let name = case.name.as_str(); - let id = if let Some(id) = node.any_ref().id() { - format!("{}.{}", id, name) - } else { - name.to_owned() - }; - let n = node.new_child(MdNamedType::new( - MdHeading::new_bullet(), - id.as_str(), - name, - &case.docs, - )); - if let Some(ty) = &case.tref { - ty.generate(n.clone()); - } - } - } -} - -impl ToMarkdown for HandleDatatype { - fn generate(&self, node: MdNodeRef) { - // TODO this needs more work - let heading = heading_from_node(&node, 1); - node.new_child(MdSection::new(heading, "Supertypes")); - } -} - -impl ToMarkdown for Module { - fn generate(&self, node: MdNodeRef) { - let heading = heading_from_node(&node, 1); - let imports = node.new_child(MdSection::new(heading, "Imports")); - for import in self.imports() { - let child = imports.new_child(MdSection::new(heading.new_level_down(), "")); - import.generate(child.clone()); - } - - let funcs = node.new_child(MdSection::new(heading, "Functions")); - for func in self.funcs() { - let name = func.name.as_str(); - let child = funcs.new_child(MdFunc::new( - heading.new_level_down(), - name, - name, - &func.docs, - )); - func.generate(child.clone()); - } - } -} - -impl ToMarkdown for ModuleImport { - fn generate(&self, node: MdNodeRef) { - match self.variant { - ModuleImportVariant::Memory => { - node.content_ref_mut::().title = "Memory".to_owned(); - } - } - } -} - -impl ToMarkdown for InterfaceFunc { - fn generate(&self, node: MdNodeRef) { - let heading = heading_from_node(&node, 1); - node.new_child(MdSection::new(heading, "Params")); - for param in &self.params { - let name = param.name.as_str(); - let id = if let Some(id) = node.any_ref().id() { - format!("{}.{}", id, name) - } else { - name.to_owned() - }; - let child = node.new_child(MdNamedType::new( - MdHeading::new_bullet(), - id.as_str(), - name, - param.name.as_str(), - )); - param.generate(child.clone()); - // TODO should this be expanded recursively instead of using flattened type names? - node.content_ref_mut::() - .inputs - .push((param.name.as_str().to_owned(), param.tref.type_name())); - } - - node.new_child(MdSection::new(heading, "Results")); - for result in &self.results { - let name = result.name.as_str(); - let id = if let Some(id) = node.any_ref().id() { - format!("{}.{}", id, name) - } else { - name.to_owned() - }; - let child = node.new_child(MdNamedType::new( - MdHeading::new_bullet(), - id.as_str(), - name, - result.name.as_str(), - )); - result.generate(child.clone()); - // TODO should this be expanded recursively instead of using flattened type names? - node.content_ref_mut::() - .outputs - .push(result.tref.type_name()); - } - } -} - -impl ToMarkdown for InterfaceFuncParam { - fn generate(&self, node: MdNodeRef) { - self.tref.generate(node.clone()); - node.content_ref_mut::().docs = self.docs.clone(); - } -} - -impl BuiltinType { - pub fn type_name(&self) -> &'static str { - match self { - BuiltinType::Char => "char", - BuiltinType::U8 { .. } => "u8", - BuiltinType::U16 => "u16", - BuiltinType::U32 { - lang_ptr_size: false, - } => "u32", - BuiltinType::U32 { - lang_ptr_size: true, - } => "usize", - BuiltinType::U64 => "u64", - BuiltinType::S8 => "s8", - BuiltinType::S16 => "s16", - BuiltinType::S32 => "s32", - BuiltinType::S64 => "s64", - BuiltinType::F32 => "f32", - BuiltinType::F64 => "f64", - } - } -} - -impl TypeRef { - pub fn type_name(&self) -> String { - match self { - TypeRef::Name(n) => n.name.as_str().to_string(), - TypeRef::Value(v) => match &**v { - Type::List(a) => match &**a.type_() { - Type::Builtin(BuiltinType::Char) => "string".to_string(), - _ => format!("List<{}>", a.type_name()), - }, - Type::Pointer(p) => format!("Pointer<{}>", p.type_name()), - Type::ConstPointer(p) => format!("ConstPointer<{}>", p.type_name()), - Type::Builtin(b) => b.type_name().to_string(), - Type::Record(RecordDatatype { - kind: RecordKind::Tuple, - members, - }) => { - let mut ret = "(".to_string(); - for (i, member) in members.iter().enumerate() { - if i > 0 { - ret.push_str(", "); - } - ret.push_str(&member.tref.type_name()); - } - ret.push_str(")"); - ret - } - Type::Record { .. } => { - format!("Record") - } - Type::Handle { .. } => { - format!("Handle") - } - Type::Variant(v) => { - if let Some((ok, err)) = v.as_expected() { - let ok = match ok { - Some(ty) => ty.type_name(), - None => "()".to_string(), - }; - let err = match err { - Some(ty) => ty.type_name(), - None => "()".to_string(), - }; - format!("Result<{}, {}>", ok, err) - } else if v.is_bool() { - format!("bool") - } else { - format!("Variant") - } - } - }, - } - } -} - -// TODO -// Generate Markdown tree for the polyfill -impl Documentation for Polyfill { - fn to_md(&self) -> String { - let module_docs = self - .modules - .iter() - .map(|m| m.to_md()) - .collect::>() - .join("\n"); - let type_docs = self - .type_polyfills() - .iter() - .filter_map(|t| { - if t.repeq() == RepEquality::Eq { - None - } else { - Some(t.to_md()) - } - }) - .collect::>() - .join("\n"); - format!( - "# Modules\n{}\n# Type Conversions\n{}\n", - module_docs, type_docs - ) - } -} - -impl Documentation for ModulePolyfill { - fn to_md(&self) -> String { - format!( - "## `{}` in terms of `{}`\n{}", - self.new.name.as_str(), - self.old.name.as_str(), - self.funcs - .iter() - .map(|f| f.to_md()) - .collect::>() - .join("\n"), - ) - } -} - -impl Documentation for FuncPolyfill { - fn to_md(&self) -> String { - if self.full_compat() { - format!("* `{}`: full compatibility", self.new.name.as_str()) - } else { - let name = if self.new.name != self.old.name { - format!( - "* `{}` => `{}`", - self.old.name.as_str(), - self.new.name.as_str() - ) - } else { - format!("* `{}`", self.new.name.as_str()) - }; - let mut contents = Vec::new(); - for p in self.mapped_params.iter() { - contents.push(if !p.full_compat() { - format!("param {}", p.to_md()) - } else { - format!("param `{}`: compatible", p.new.name.as_str()) - }) - } - for u in self.unknown_params.iter() { - contents.push(format!( - "{} param `{}`: no corresponding result!", - u.which(), - u.param().name.as_str() - )) - } - for r in self.mapped_results.iter() { - contents.push(if !r.full_compat() { - format!("result {}", r.to_md()) - } else { - format!("result `{}`: compatible", r.new.name.as_str()) - }) - } - for u in self.unknown_results.iter() { - contents.push(format!( - "{} result `{}`: no corresponding result!", - u.which(), - u.param().name.as_str() - )) - } - let contents = if contents.is_empty() { - String::new() - } else { - format!(":\n - {}", contents.join("\n - ")) - }; - format!("{}{}", name, contents) - } - } -} - -impl Documentation for ParamPolyfill { - fn to_md(&self) -> String { - let name = if self.new.name != self.old.name { - format!( - "`{}` => `{}`", - self.old.name.as_str(), - self.new.name.as_str() - ) - } else { - format!("`{}`", self.new.name.as_str()) - }; - let repr = match self.repeq() { - RepEquality::Eq => "compatible types".to_string(), - RepEquality::Superset => format!( - "`{}` is superset-compatible with `{}`", - self.old.tref.type_name(), - self.new.tref.type_name() - ), - RepEquality::NotEq => format!( - "`{}` is incompatible with new `{}`", - self.old.tref.type_name(), - self.new.tref.type_name() - ), - }; - format!("{}: {}", name, repr) - } -} - -impl Documentation for TypePolyfill { - fn to_md(&self) -> String { - fn repeq_name(r: RepEquality) -> &'static str { - match r { - RepEquality::Eq => ": compatible", - RepEquality::Superset => ": superset", - RepEquality::NotEq => "", - } - } - match self { - TypePolyfill::OldToNew(o, n) => format!( - "* old `{}` => new `{}`{}", - o.type_name(), - n.type_name(), - repeq_name(self.repeq()) - ), - TypePolyfill::NewToOld(n, o) => format!( - "* new `{}` => old `{}`{}", - n.type_name(), - o.type_name(), - repeq_name(self.repeq()) - ), - } - } -} diff --git a/legacy/tools/witx/src/docs/md.rs b/legacy/tools/witx/src/docs/md.rs deleted file mode 100644 index 569b31837..000000000 --- a/legacy/tools/witx/src/docs/md.rs +++ /dev/null @@ -1,480 +0,0 @@ -use std::{ - any::Any, - cell::{self, RefCell}, - fmt, - rc::{Rc, Weak}, -}; - -/// Helper trait which simplifies generation of the Markdown document represented -/// as a tree of `MdNodeRef`s. -pub(super) trait ToMarkdown { - /// Drives the generation of the `MdNodeRef` tree by either mutating - /// the outer (parent) `MdNodeRef`, shared reference to the `MdNode` `node`, - /// or spawning new child `MdNodeRef` references to nodes. - fn generate(&self, node: MdNodeRef); -} - -/// Interface required for any "content" that is expected to be generated into a -/// Markdown valid format, hence the constraint of `fmt::Display`. -/// -/// In essence, any AST element that is meant to be rendered into Markdown, should -/// define a type implementing this trait. -pub(super) trait MdElement: fmt::Display + fmt::Debug + 'static { - /// Returns `Some(id)` of this `MdElement`. Here `id` is synonym for a Markdown actionable - /// link. - fn id(&self) -> Option<&str>; - - /// Returns `Some(docs)`, the "docs" of this `MdElement`. - fn docs(&self) -> Option<&str>; - - /// Sets `docs`, the "docs" of this `MdElement`. - fn set_docs(&mut self, docs: &str); - - fn as_any(&self) -> &dyn Any; - fn as_any_mut(&mut self) -> &mut dyn Any; -} - -/// A Markdown node containing: -/// * the Markdown renderable `content`, -/// * a weak reference to the `parent` `MdNode` (if any), and -/// * children `MdNodeRef`s -/// -/// `content` is expected to implement the `MdElement` trait. -#[derive(Debug)] -pub(super) struct MdNode { - content: Box, - parent: Option>>, - children: Vec, -} - -/// Helper function for walking the tree up from some starting `MdNode`, all the way up -/// to the root of the tree. -fn walk_ancestors(parent: Option<&Weak>>, cb: &mut impl FnMut(MdNodeRef)) { - if let Some(parent) = parent.and_then(|x| x.upgrade()) { - cb(parent.clone().into()); - walk_ancestors(parent.borrow().parent.as_ref(), cb) - } -} - -impl MdNode { - fn new(item: T) -> Self { - Self { - content: Box::new(item), - parent: None, - children: vec![], - } - } - - /// Returns all ancestors of this `MdNode` all the way to the tree's root. - pub fn ancestors(&self) -> Vec { - let mut ancestors = Vec::new(); - walk_ancestors(self.parent.as_ref(), &mut |parent| ancestors.push(parent)); - ancestors - } - - /// Returns all children of this `MdNode` in a BFS order. - pub fn children(&self) -> Vec { - let mut children = self.children.clone(); - for child in &self.children { - children.append(&mut child.borrow().children()); - } - children - } -} - -impl fmt::Display for MdNode { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.content.fmt(f)?; - - for child in &self.children { - child.fmt(f)?; - } - - Ok(()) - } -} - -/// Helper struct for storing a shared mutable reference to `MdNode`. -#[derive(Debug)] -pub(super) struct MdNodeRef(Rc>); - -impl MdNodeRef { - pub fn new(item: T) -> Self { - Self(Rc::new(RefCell::new(MdNode::new(item)))) - } - - /// Spawns new `MdNode` child node, automatically wrapping it in a - /// `MdNodeRef` and creating a weak link from child to itself. - pub fn new_child(&self, item: T) -> Self { - let mut child_node = MdNode::new(item); - child_node.parent = Some(Rc::downgrade(&self.0)); - let child_ref = Self(Rc::new(RefCell::new(child_node))); - self.borrow_mut().children.push(child_ref.clone()); - child_ref - } - - pub fn borrow(&self) -> cell::Ref { - self.0.borrow() - } - - pub fn borrow_mut(&self) -> cell::RefMut { - self.0.borrow_mut() - } - - /// Returns an immutable reference to `MdNode`'s `content` as-is, that - /// is as some type implementing the `MdElement` trait. - pub fn any_ref(&self) -> cell::Ref> { - cell::Ref::map(self.borrow(), |b| &b.content) - } - - /// Returns a mutable reference to `MdNode`'s `content` as-is, that - /// is as some type implementing the `MdElement` trait. - pub fn any_ref_mut(&self) -> cell::RefMut> { - cell::RefMut::map(self.borrow_mut(), |b| &mut b.content) - } - - /// Returns a mutable reference to `MdNode`'s `content` cast to some type - /// `T` which implements `MdElement` trait. - /// - /// Panics if `content` cannot be downcast to `T`. - pub fn content_ref_mut(&self) -> cell::RefMut { - cell::RefMut::map(self.borrow_mut(), |b| { - let r = b.content.as_any_mut(); - r.downcast_mut::().expect("reference is not T type") - }) - } -} - -impl Clone for MdNodeRef { - fn clone(&self) -> Self { - Self(self.0.clone()) - } -} - -impl From>> for MdNodeRef { - fn from(node: Rc>) -> Self { - Self(node) - } -} - -impl fmt::Display for MdNodeRef { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.borrow().fmt(f) - } -} - -/// Record representing the Markdown tree's root. -/// -/// Doesn't render to anything. -#[derive(Debug, Default)] -pub(super) struct MdRoot; - -impl MdElement for MdRoot { - fn id(&self) -> Option<&str> { - None - } - - fn docs(&self) -> Option<&str> { - None - } - - fn set_docs(&mut self, _: &str) {} - - fn as_any(&self) -> &dyn Any { - self - } - - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } -} - -impl fmt::Display for MdRoot { - fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { - Ok(()) - } -} - -/// Helper enum representing either a Markdown header "#" nested at some -/// `level` down the tree, or a bullet "-" in a list which is idempotent -/// to changing the nesting level. -#[derive(Debug, Clone, Copy)] -pub(super) enum MdHeading { - Header { level: usize }, - Bullet, -} - -impl MdHeading { - /// Creates new instance of `MdHeading::Header` variant nested at some - /// `level` down the Markdown tree. - pub fn new_header(level: usize) -> Self { - MdHeading::Header { level } - } - - /// Creates new instance of `MdHeading::Bullet` variant. - pub fn new_bullet() -> Self { - MdHeading::Bullet - } - - /// Copies `MdHeading` and if `MdHeading::Header`, pushes it down one - /// level in the Markdown tree by incrementing `level`. - pub fn new_level_down(&self) -> Self { - let mut copy = *self; - if let Self::Header { ref mut level } = &mut copy { - *level += 1; - } - copy - } -} - -impl fmt::Display for MdHeading { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let as_string = match self { - Self::Header { level } => "#".repeat(*level), - Self::Bullet => "-".to_owned(), - }; - f.write_str(&as_string) - } -} - -/// Record representing a Markdown section without any `docs`, consisting -/// of only a `header` (e.g., "###"), maybe some referencable `id` (i.e., -/// a Markdown link), and some `title`. -/// -/// Example rendering: -/// -/// ### Typenames -/// -#[derive(Debug)] -pub(super) struct MdSection { - pub heading: MdHeading, - pub id: Option, - pub title: String, -} - -impl MdSection { - pub fn new>(heading: MdHeading, title: S) -> Self { - Self { - heading, - id: None, - title: title.as_ref().to_owned(), - } - } -} - -impl MdElement for MdSection { - fn id(&self) -> Option<&str> { - self.id.as_ref().map(|s| s.as_str()) - } - - fn docs(&self) -> Option<&str> { - None - } - - fn set_docs(&mut self, _: &str) {} - - fn as_any(&self) -> &dyn Any { - self - } - - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } -} - -fn gen_link>(id: S) -> String { - format!("", id = id.as_ref()) -} - -impl fmt::Display for MdSection { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_fmt(format_args!("{} ", self.heading))?; - - if let Some(id) = &self.id { - f.write_fmt(format_args!("{} ", gen_link(id)))?; - } - - writeln!(f, "{}", self.title) - } -} - -/// Record representing a Markdown section representing any `NamedType` element -/// of the AST. -/// Consists of: -/// * `header`, e.g., "###", or "-" for Enum variants, etc., -/// * referencable `id`, -/// * some `name`, e.g., `errno`, -/// * `docs` paragraph, and -/// * maybe `MdType`. -/// -/// Example rendering (recursive): -/// -/// ### `errno`: Enum(`u16`) -/// Error codes returned by... -/// -/// #### Variants -/// - `success` No error occurred... -/// - `2big` Argument list too long... -/// -#[derive(Debug)] -pub(super) struct MdNamedType { - pub heading: MdHeading, - pub id: String, - pub name: String, - pub docs: String, - pub ty: Option, -} - -impl MdNamedType { - pub fn new>(heading: MdHeading, id: S, name: S, docs: S) -> Self { - Self { - heading, - id: id.as_ref().to_owned(), - name: name.as_ref().to_owned(), - docs: docs.as_ref().to_owned(), - ty: None, - } - } -} - -impl MdElement for MdNamedType { - fn id(&self) -> Option<&str> { - Some(&self.id) - } - - fn docs(&self) -> Option<&str> { - Some(&self.docs) - } - - fn set_docs(&mut self, docs: &str) { - self.docs = docs.to_owned(); - } - - fn as_any(&self) -> &dyn Any { - self - } - - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } -} - -impl fmt::Display for MdNamedType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_fmt(format_args!( - "{heading} {link} `{name}`", - heading = self.heading, - link = gen_link(&self.id), - name = self.name, - ))?; - - if let Some(tt) = &self.ty { - f.write_fmt(format_args!(": {}", tt))?; - } - - writeln!(f, "\n{}", self.docs) - } -} - -/// Record representing a Markdown section representing any `InterfaceFunc` element -/// of the AST. -/// Consists of: -/// * `header`, e.g., "###", -/// * referencable `id`, -/// * some `name`, e.g., `path_open`, -/// * function `inputs`, i.e., arguments, -/// * function `outputs`, i.e., results, and -/// * `docs` paragraph. -/// -/// Example rendering: -/// -/// ### Fn args_get(argv: `Pointer>`, ...) -> `errno` -/// Read command-line... -/// -/// #### Params -/// - `argv`: `Pointer>` Some docs... -/// - ... -/// -/// #### Results -/// - `error`: `errno` Error code... -/// -#[derive(Debug)] -pub(super) struct MdFunc { - pub heading: MdHeading, - pub id: String, - pub name: String, - pub inputs: Vec<(String, String)>, - pub outputs: Vec, - pub docs: String, -} - -impl MdFunc { - pub fn new>(heading: MdHeading, id: S, name: S, docs: S) -> Self { - Self { - heading, - id: id.as_ref().to_owned(), - name: name.as_ref().to_owned(), - inputs: vec![], - outputs: vec![], - docs: docs.as_ref().to_owned(), - } - } -} - -impl MdElement for MdFunc { - fn id(&self) -> Option<&str> { - Some(&self.id) - } - - fn docs(&self) -> Option<&str> { - Some(&self.docs) - } - - fn set_docs(&mut self, docs: &str) { - self.docs = docs.to_owned(); - } - - fn as_any(&self) -> &dyn Any { - self - } - - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } -} - -impl fmt::Display for MdFunc { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // Expand inputs - let inputs = self - .inputs - .iter() - .map(|(name, r#type)| format!("{}: {}", name, r#type)) - .collect::>() - .join(", "); - // Expand outputs - let outputs: Vec<_> = self - .outputs - .iter() - .map(|r#type| format!("{}", r#type)) - .collect(); - let outputs = match outputs.len() { - 0 => "".to_owned(), - 1 => format!(" -> {}", outputs[0]), - _ => format!(" -> ({})", outputs.join(", ")), - }; - // Format - writeln!(f, "\n---\n")?; - - f.write_fmt(format_args!( - "{heading} {link} `{name}({inputs}){outputs}`", - heading = self.heading, - link = gen_link(&self.id), - name = self.name, - inputs = inputs, - outputs = outputs, - ))?; - - writeln!(f, "\n{}", self.docs) - } -} diff --git a/legacy/tools/witx/src/docs/mod.rs b/legacy/tools/witx/src/docs/mod.rs deleted file mode 100644 index 8f082cba5..000000000 --- a/legacy/tools/witx/src/docs/mod.rs +++ /dev/null @@ -1,87 +0,0 @@ -mod ast; -mod md; - -use crate::ast::Document; -use md::{MdNodeRef, MdRoot, ToMarkdown}; -use std::{ - collections::{hash_map, HashSet}, - iter::FromIterator, -}; - -/// Enables generating Markdown formatted content. -pub trait Documentation { - fn to_md(&self) -> String; -} - -/// Helper function which given input `text` and a `HashSet` of existing links converts -/// any slice of the form '`{link}`' into either -/// 1. "[`{link}`](#{md_link})" where `md_link` is `link` with "::" replaced with "." -/// (in Markdown, scoping should be done with ".") if `md_link` exists in the `HashSet` -/// 2. "`{link}`" otherwise. That is, if `md_link` could not be found in the `HashSet`, we -/// just leave what we've consumed. -fn parse_links>(text: S, existing_links: &HashSet) -> String { - let text = text.as_ref(); - let mut parsed_text = String::with_capacity(text.len()); - let mut link = String::with_capacity(text.len()); - let mut is_link = false; - - for ch in text.chars() { - match (ch, is_link) { - // Found the beginning of a link! - ('`', false) => { - is_link = true; - } - // Reached the end, expand into a link! - ('`', true) => { - // Sanitise scoping by replacing "::" with '.' - let md_link = link.replace("::", "."); - // Before committing to pasting the link in, - // first verify that it actually exists. - let expanded = if let Some(_) = existing_links.get(&md_link) { - format!("[`{}`](#{})", link, md_link) - } else { - log::warn!( - "Link [`{}`](#{}) could not be found in the document!", - link, - md_link - ); - format!("`{}`", link) - }; - parsed_text.push_str(&expanded); - link.drain(..); - is_link = false; - } - (ch, false) => parsed_text.push(ch), - (ch, true) => link.push(ch), - } - } - - parsed_text -} - -impl Documentation for Document { - fn to_md(&self) -> String { - let root = MdNodeRef::new(MdRoot::default()); - self.generate(root.clone()); - // Get all children of the `root` element. - let children = root.borrow().children(); - // Gather all existing links in the document into a set. - let existing_links: HashSet = HashSet::from_iter( - children - .iter() - .filter_map(|x| x.any_ref().id().map(String::from)), - ); - // Traverse each docs section of each child, and parse links - // logging a warning in case the generated is invalid. - for child in children { - let docs_with_links = child - .any_ref() - .docs() - .map(|docs| parse_links(docs, &existing_links)); - if let Some(docs) = docs_with_links { - child.any_ref_mut().set_docs(&docs); - } - } - format!("{}", root) - } -} diff --git a/legacy/tools/witx/src/io.rs b/legacy/tools/witx/src/io.rs deleted file mode 100644 index a38a22d82..000000000 --- a/legacy/tools/witx/src/io.rs +++ /dev/null @@ -1,103 +0,0 @@ -use crate::WitxError; -use std::collections::HashMap; -use std::fs::{read_to_string, File}; -use std::io::{BufRead, BufReader, Error, ErrorKind}; -use std::path::{Path, PathBuf}; - -pub trait WitxIo { - /// Read the entire file into a String. Used to resolve `use` declarations. - fn fgets(&self, path: &Path) -> Result; - /// Read a line of a file into a String. Used for error reporting. - fn fget_line(&self, path: &Path, line_num: usize) -> Result; - /// Return the canonical (non-symlinked) path of a file. Used to resolve `use` declarations. - fn canonicalize(&self, path: &Path) -> Result; -} - -impl WitxIo for &'_ T { - fn fgets(&self, path: &Path) -> Result { - T::fgets(self, path) - } - fn fget_line(&self, path: &Path, line_num: usize) -> Result { - T::fget_line(self, path, line_num) - } - fn canonicalize(&self, path: &Path) -> Result { - T::canonicalize(self, path) - } -} - -pub struct Filesystem; - -impl WitxIo for Filesystem { - fn fgets(&self, path: &Path) -> Result { - read_to_string(path).map_err(|e| WitxError::Io(path.to_path_buf(), e)) - } - fn fget_line(&self, path: &Path, line_num: usize) -> Result { - let f = File::open(path).map_err(|e| WitxError::Io(path.into(), e))?; - let buf = BufReader::new(f); - let l = buf - .lines() - .skip(line_num - 1) - .next() - .ok_or_else(|| { - WitxError::Io(path.into(), Error::new(ErrorKind::Other, "Line not found")) - })? - .map_err(|e| WitxError::Io(path.into(), e))?; - - Ok(l) - } - fn canonicalize(&self, path: &Path) -> Result { - path.canonicalize() - .map_err(|e| WitxError::Io(path.to_path_buf(), e)) - } -} - -pub struct MockFs { - map: HashMap, -} - -impl MockFs { - pub fn new(strings: &[(&str, &str)]) -> Self { - MockFs { - map: strings - .iter() - .map(|(k, v)| (PathBuf::from(k), v.to_string())) - .collect(), - } - } -} - -impl WitxIo for MockFs { - fn fgets(&self, path: &Path) -> Result { - if let Some(entry) = self.map.get(path) { - Ok(entry.to_string()) - } else { - Err(WitxError::Io( - path.to_path_buf(), - Error::new(ErrorKind::Other, "mock fs: file not found"), - )) - } - } - fn fget_line(&self, path: &Path, line: usize) -> Result { - if let Some(entry) = self.map.get(path) { - entry - .lines() - .skip(line - 1) - .next() - .map(|s| s.to_string()) - .ok_or_else(|| { - WitxError::Io( - path.to_path_buf(), - Error::new(ErrorKind::Other, "mock fs: file not found"), - ) - }) - } else { - Err(WitxError::Io( - path.to_path_buf(), - Error::new(ErrorKind::Other, "mock fs: file not found"), - )) - } - } - fn canonicalize(&self, path: &Path) -> Result { - Ok(PathBuf::from(path)) - } -} diff --git a/legacy/tools/witx/src/layout.rs b/legacy/tools/witx/src/layout.rs deleted file mode 100644 index 6812f01ae..000000000 --- a/legacy/tools/witx/src/layout.rs +++ /dev/null @@ -1,219 +0,0 @@ -use crate::ast::*; -use std::collections::HashMap; - -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct SizeAlign { - pub size: usize, - pub align: usize, -} - -impl SizeAlign { - fn zero() -> SizeAlign { - SizeAlign { size: 0, align: 0 } - } - fn append_field(&mut self, other: &SizeAlign) { - self.align = self.align.max(other.align); - self.size = align_to(self.size, other.align); - self.size += other.size; - } -} - -pub trait Layout { - fn mem_size_align(&self) -> SizeAlign; - fn mem_size(&self) -> usize { - self.mem_size_align().size - } - fn mem_align(&self) -> usize { - self.mem_size_align().align - } -} - -impl TypeRef { - fn layout(&self, cache: &mut HashMap) -> SizeAlign { - if let Some(hit) = cache.get(self) { - return *hit; - } - let layout = match &self { - TypeRef::Name(nt) => nt.layout(cache), - TypeRef::Value(v) => v.layout(cache), - }; - cache.insert(self.clone(), layout); - layout - } -} - -impl Layout for TypeRef { - fn mem_size_align(&self) -> SizeAlign { - let mut cache = HashMap::new(); - self.layout(&mut cache) - } -} - -impl NamedType { - fn layout(&self, cache: &mut HashMap) -> SizeAlign { - self.tref.layout(cache) - } -} -impl Layout for NamedType { - fn mem_size_align(&self) -> SizeAlign { - let mut cache = HashMap::new(); - self.layout(&mut cache) - } -} - -impl Type { - fn layout(&self, cache: &mut HashMap) -> SizeAlign { - match &self { - Type::Record(s) => match s.bitflags_repr() { - Some(repr) => repr.mem_size_align(), - None => s.layout(cache), - }, - Type::Variant(s) => s.mem_size_align(), - Type::Handle(h) => h.mem_size_align(), - Type::List { .. } => SizeAlign { size: 8, align: 4 }, // Pointer and Length - Type::Pointer { .. } | Type::ConstPointer { .. } => BuiltinType::S32.mem_size_align(), - Type::Builtin(b) => b.mem_size_align(), - } - } -} - -impl Layout for Type { - fn mem_size_align(&self) -> SizeAlign { - let mut cache = HashMap::new(); - self.layout(&mut cache) - } -} - -impl Layout for IntRepr { - fn mem_size_align(&self) -> SizeAlign { - self.to_builtin().mem_size_align() - } -} - -pub struct RecordMemberLayout<'a> { - pub member: &'a RecordMember, - pub offset: usize, -} - -impl RecordDatatype { - pub fn member_layout(&self) -> Vec { - self.member_layout_(&mut HashMap::new()).1 - } - - fn member_layout_( - &self, - cache: &mut HashMap, - ) -> (SizeAlign, Vec) { - let mut members = Vec::new(); - let mut sa = SizeAlign::zero(); - for m in self.members.iter() { - let member = m.tref.layout(cache); - sa.append_field(&member); - members.push(RecordMemberLayout { - member: m, - offset: sa.size - member.size, - }); - } - sa.size = align_to(sa.size, sa.align); - (sa, members) - } - - fn layout(&self, cache: &mut HashMap) -> SizeAlign { - self.member_layout_(cache).0 - } -} - -impl Layout for RecordDatatype { - fn mem_size_align(&self) -> SizeAlign { - match self.bitflags_repr() { - Some(repr) => repr.mem_size_align(), - None => { - let mut cache = HashMap::new(); - self.layout(&mut cache) - } - } - } -} - -impl Layout for Variant { - fn mem_size_align(&self) -> SizeAlign { - let mut max = SizeAlign { size: 0, align: 0 }; - for case in self.cases.iter() { - let mut size = self.tag_repr.mem_size_align(); - if let Some(payload) = &case.tref { - size.append_field(&payload.mem_size_align()); - } - size.size = align_to(size.size, size.align); - max.size = max.size.max(size.size); - max.align = max.align.max(size.align); - } - max - } -} - -impl Variant { - pub fn payload_offset(&self) -> usize { - let mut offset = self.tag_repr.mem_size_align().size; - for case in self.cases.iter() { - if let Some(payload) = &case.tref { - offset = offset.max(align_to(offset, payload.mem_size_align().align)); - } - } - offset - } -} - -/// If the next free byte in the struct is `offs`, and the next -/// element has alignment `alignment`, determine the offset at -/// which to place that element. -fn align_to(offs: usize, alignment: usize) -> usize { - offs + alignment - 1 - ((offs + alignment - 1) % alignment) -} - -#[cfg(test)] -mod test { - use super::align_to; - #[test] - fn align() { - assert_eq!(0, align_to(0, 1)); - assert_eq!(0, align_to(0, 2)); - assert_eq!(0, align_to(0, 4)); - assert_eq!(0, align_to(0, 8)); - - assert_eq!(1, align_to(1, 1)); - assert_eq!(2, align_to(1, 2)); - assert_eq!(4, align_to(1, 4)); - assert_eq!(8, align_to(1, 8)); - - assert_eq!(2, align_to(2, 1)); - assert_eq!(2, align_to(2, 2)); - assert_eq!(4, align_to(2, 4)); - assert_eq!(8, align_to(2, 8)); - - assert_eq!(5, align_to(5, 1)); - assert_eq!(6, align_to(5, 2)); - assert_eq!(8, align_to(5, 4)); - assert_eq!(8, align_to(5, 8)); - } -} - -impl Layout for HandleDatatype { - fn mem_size_align(&self) -> SizeAlign { - BuiltinType::S32.mem_size_align() - } -} - -impl Layout for BuiltinType { - fn mem_size_align(&self) -> SizeAlign { - match self { - BuiltinType::U8 { .. } | BuiltinType::S8 => SizeAlign { size: 1, align: 1 }, - BuiltinType::U16 | BuiltinType::S16 => SizeAlign { size: 2, align: 2 }, - BuiltinType::Char | BuiltinType::U32 { .. } | BuiltinType::S32 | BuiltinType::F32 => { - SizeAlign { size: 4, align: 4 } - } - BuiltinType::U64 | BuiltinType::S64 | BuiltinType::F64 => { - SizeAlign { size: 8, align: 8 } - } - } - } -} diff --git a/legacy/tools/witx/src/lib.rs b/legacy/tools/witx/src/lib.rs deleted file mode 100644 index f1cc7e229..000000000 --- a/legacy/tools/witx/src/lib.rs +++ /dev/null @@ -1,99 +0,0 @@ -/// Map witx types to core (wasm standard) types -mod abi; -/// Types describing a validated witx document -mod ast; -/// Render documentation -mod docs; -/// Interface for filesystem or mock IO -mod io; -/// Calculate memory layout of types -mod layout; -/// Witx syntax parsing from SExprs -pub mod parser; -/// Paths to witx documents for various proposal phases -pub mod phases; -/// Calculate required polyfill between interfaces -pub mod polyfill; -/// Render ast to text -mod render; -/// Representational equality of types -mod representation; -/// Resolve toplevel `use` declarations across files -mod toplevel; -/// Validate declarations into ast -mod validate; - -pub use abi::*; -pub use ast::*; -pub use docs::Documentation; -pub use io::{Filesystem, MockFs, WitxIo}; -pub use layout::{Layout, RecordMemberLayout, SizeAlign}; -pub use render::SExpr; -pub use representation::{RepEquality, Representable}; -pub use validate::{DocValidation, ValidationError}; - -use std::path::{Path, PathBuf}; -use thiserror::Error; - -/// Load a witx document from the filesystem -pub fn load>(paths: &[P]) -> Result { - toplevel::parse_witx(paths) -} - -/// Parse a witx document from a str. `(use ...)` directives are not permitted. -pub fn parse(source: &str) -> Result { - let mockfs = MockFs::new(&[("-", source)]); - toplevel::parse_witx_with(&[Path::new("-")], &mockfs) -} - -/// Location in the source text -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Location { - pub path: PathBuf, - pub line: usize, - pub column: usize, -} - -#[derive(Debug, Error)] -pub enum WitxError { - #[error("IO error with file {0:?}")] - Io(PathBuf, #[source] ::std::io::Error), - #[error("Parse error")] - Parse(#[from] wast::Error), - #[error("Validation error")] - Validation(#[from] ValidationError), -} - -impl WitxError { - pub fn report_with(&self, witxio: &dyn WitxIo) -> String { - use WitxError::*; - match self { - Io(path, ioerr) => format!("with file {:?}: {}", path, ioerr), - Parse(parse) => parse.to_string(), - Validation(validation) => validation.report_with(witxio), - } - } - pub fn report(&self) -> String { - self.report_with(&Filesystem) - } -} - -impl Location { - pub fn highlight_source_with(&self, witxio: &dyn WitxIo) -> String { - let mut msg = format!("in {:?}:\n", self.path); - if let Ok(src_line) = witxio.fget_line(&self.path, self.line) { - msg += &format!( - "{line_num: >5} | {src_line}\n{blank: >5} {caret: >column$}", - line_num = self.line, - src_line = src_line, - blank = " ", - caret = "^", - column = self.column, - ); - } - msg - } - pub fn highlight_source(&self) -> String { - self.highlight_source_with(&Filesystem) - } -} diff --git a/legacy/tools/witx/src/parser.rs b/legacy/tools/witx/src/parser.rs deleted file mode 100644 index 33cf745ff..000000000 --- a/legacy/tools/witx/src/parser.rs +++ /dev/null @@ -1,778 +0,0 @@ -use crate::BuiltinType; -use wast::parser::{Parse, Parser, Peek, Result}; - -///! Parser turns s-expressions into unvalidated syntax constructs. -///! conventions: -///! `Type::starts_parsing(s-expr) -> bool` is for look-ahead: we use -///! this predicate to combine parsers for different `Type`s where both -///! alternatives are accepted. -///! `Type::parse(sexpr: &SExpr) -> Result` takes a single -///! s-expression and parses it into a `Self`. -///! for parsers that take a subset of a vector s-expression, the signature -///! `Type::parse(sexprs: &[SExpr], location: Location) -> Result` -///! has an additional `Location` argument, which should point to the parent SExpr::Vec. -///! This is used for error reporting in case the slice doesn't have the number of elements -///! expected. - -mod kw { - pub use wast::kw::{export, func, import, memory, module, param, result}; - - wast::custom_keyword!(case); - wast::custom_keyword!(char8); - wast::custom_keyword!(char); - wast::custom_keyword!(const_pointer); - wast::custom_keyword!(f32); - wast::custom_keyword!(f64); - wast::custom_keyword!(field); - wast::custom_keyword!(empty); - wast::custom_keyword!(error); - wast::custom_keyword!(expected); - wast::custom_keyword!(flags); - wast::custom_keyword!(handle); - wast::custom_keyword!(list); - wast::custom_keyword!(noreturn); - wast::custom_keyword!(pointer); - wast::custom_keyword!(record); - wast::custom_keyword!(r#const = "const"); - wast::custom_keyword!(r#enum = "enum"); - wast::custom_keyword!(r#union = "union"); - wast::custom_keyword!(r#use = "use"); - wast::custom_keyword!(repr); - wast::custom_keyword!(s16); - wast::custom_keyword!(s32); - wast::custom_keyword!(s64); - wast::custom_keyword!(s8); - wast::custom_keyword!(string); - wast::custom_keyword!(tag); - wast::custom_keyword!(tuple); - wast::custom_keyword!(typename); - wast::custom_keyword!(u16); - wast::custom_keyword!(u32); - wast::custom_keyword!(u64); - wast::custom_keyword!(u8); - wast::custom_keyword!(usize); - wast::custom_keyword!(variant); - wast::custom_keyword!(bool_ = "bool"); -} - -mod annotation { - wast::annotation!(interface); - wast::annotation!(witx); -} - -impl Parse<'_> for BuiltinType { - fn parse(parser: Parser<'_>) -> Result { - let mut l = parser.lookahead1(); - if l.peek::() { - parser.parse::()?; - Ok(BuiltinType::Char) - } else if l.peek::() { - parser.parse::()?; - Ok(BuiltinType::U8 { lang_c_char: false }) - } else if l.peek::() { - parser.parse::()?; - Ok(BuiltinType::U16) - } else if l.peek::() { - parser.parse::()?; - Ok(BuiltinType::U32 { - lang_ptr_size: false, - }) - } else if l.peek::() { - parser.parse::()?; - Ok(BuiltinType::U64) - } else if l.peek::() { - parser.parse::()?; - Ok(BuiltinType::S8) - } else if l.peek::() { - parser.parse::()?; - Ok(BuiltinType::S16) - } else if l.peek::() { - parser.parse::()?; - Ok(BuiltinType::S32) - } else if l.peek::() { - parser.parse::()?; - Ok(BuiltinType::S64) - } else if l.peek::() { - parser.parse::()?; - Ok(BuiltinType::F32) - } else if l.peek::() { - parser.parse::()?; - Ok(BuiltinType::F64) - } else { - Err(l.error()) - } - } -} - -impl wast::parser::Peek for BuiltinType { - fn peek(cursor: wast::parser::Cursor<'_>) -> bool { - ::peek(cursor) - || ::peek(cursor) - || ::peek(cursor) - || ::peek(cursor) - || ::peek(cursor) - || ::peek(cursor) - || ::peek(cursor) - || ::peek(cursor) - || ::peek(cursor) - || ::peek(cursor) - || ::peek(cursor) - } - - fn display() -> &'static str { - "builtin type" - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Default)] -pub struct CommentSyntax<'a> { - pub comments: Vec<&'a str>, -} - -impl<'a> Parse<'a> for CommentSyntax<'a> { - fn parse(parser: Parser<'a>) -> Result> { - let comments = parser.step(|mut cursor| { - let mut comments = Vec::new(); - loop { - let (comment, c) = match cursor.comment() { - Some(pair) => pair, - None => break, - }; - cursor = c; - comments.push(if comment.starts_with(";;") { - &comment[2..] - } else { - &comment[2..comment.len() - 2] - }); - } - Ok((comments, cursor)) - })?; - Ok(CommentSyntax { comments }) - } -} - -impl<'a> CommentSyntax<'a> { - pub fn docs(&self) -> String { - // Perform a small amount of preprocessing by removing all trailing - // whitespace, and then also filter for only "doc comments" which are `;;;` - // or `(;; ... ;)`. - let docs = self - .comments - .iter() - .map(|d| d.trim_end()) - .filter_map(|d| { - if d.starts_with(";") { - Some(&d[1..]) - } else { - None - } - }) - .collect::>(); - - // Figure out how much leading whitespace we're going to be trimming from - // all docs, trimming the minimum amount in each doc comment. - let to_trim = docs - .iter() - .filter(|d| !d.is_empty()) - .map(|d| d.len() - d.trim().len()) - .min() - .unwrap_or(0); - - // Separate all documents by a newline and collect everything into a single - // string. - let mut ret = String::new(); - for doc in docs { - if !doc.is_empty() { - ret.push_str(doc[to_trim..].trim_end()); - } - ret.push_str("\n"); - } - return ret; - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Default)] -pub struct Documented<'a, T> { - pub comments: CommentSyntax<'a>, - pub item: T, -} - -impl<'a, T: Parse<'a>> Parse<'a> for Documented<'a, T> { - fn parse(parser: Parser<'a>) -> Result { - let _r1 = parser.register_annotation("witx"); - let _r1 = parser.register_annotation("interface"); - let comments = parser.parse()?; - let item = parser.parse()?; - Ok(Documented { comments, item }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct TopLevelDocument<'a> { - pub items: Vec>>, -} - -impl<'a> Parse<'a> for TopLevelDocument<'a> { - fn parse(parser: Parser<'a>) -> Result { - let mut items = Vec::new(); - while !parser.is_empty() { - items.push(parser.parse()?); - } - Ok(TopLevelDocument { items }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum TopLevelSyntax<'a> { - Decl(DeclSyntax<'a>), - Use(&'a str), -} - -impl<'a> Parse<'a> for TopLevelSyntax<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parens(|p| { - if p.peek::() { - p.parse::()?; - Ok(TopLevelSyntax::Use(p.parse()?)) - } else { - Ok(TopLevelSyntax::Decl(p.parse()?)) - } - }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum DeclSyntax<'a> { - Typename(TypenameSyntax<'a>), - Module(ModuleSyntax<'a>), - Const(Documented<'a, ConstSyntax<'a>>), -} - -impl<'a> Parse<'a> for DeclSyntax<'a> { - fn parse(parser: Parser<'a>) -> Result { - let mut l = parser.lookahead1(); - if l.peek::() { - Ok(DeclSyntax::Module(parser.parse()?)) - } else if l.peek::() { - Ok(DeclSyntax::Typename(parser.parse()?)) - } else if l.peek::() { - Ok(DeclSyntax::Const(parser.parse()?)) - } else { - Err(l.error()) - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct TypenameSyntax<'a> { - pub ident: wast::Id<'a>, - pub def: TypedefSyntax<'a>, -} - -impl<'a> Parse<'a> for TypenameSyntax<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let ident = parser.parse()?; - let def = parser.parse()?; - Ok(TypenameSyntax { ident, def }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum TypedefSyntax<'a> { - Enum(EnumSyntax<'a>), - Tuple(TupleSyntax<'a>), - Expected(ExpectedSyntax<'a>), - Flags(FlagsSyntax<'a>), - Record(RecordSyntax<'a>), - Union(UnionSyntax<'a>), - Variant(VariantSyntax<'a>), - Handle(HandleSyntax), - List(Box>), - Pointer(Box>), - ConstPointer(Box>), - Builtin(BuiltinType), - Ident(wast::Id<'a>), - String, - Bool, -} - -impl<'a> Parse<'a> for TypedefSyntax<'a> { - fn parse(parser: Parser<'a>) -> Result { - let mut l = parser.lookahead1(); - if l.peek::() { - Ok(TypedefSyntax::Ident(parser.parse()?)) - } else if l.peek::() { - Ok(TypedefSyntax::Builtin(parser.parse()?)) - } else if l.peek::() { - parser.parse::()?; - Ok(TypedefSyntax::String) - } else if l.peek::() { - parser.parse::()?; - Ok(TypedefSyntax::Bool) - } else if l.peek::() { - parser.parens(|parser| { - let mut l = parser.lookahead1(); - if l.peek::() { - Ok(TypedefSyntax::Enum(parser.parse()?)) - } else if l.peek::() { - Ok(TypedefSyntax::Tuple(parser.parse()?)) - } else if l.peek::() { - Ok(TypedefSyntax::Expected(parser.parse()?)) - } else if l.peek::() { - Ok(TypedefSyntax::Flags(parser.parse()?)) - } else if l.peek::() { - Ok(TypedefSyntax::Record(parser.parse()?)) - } else if l.peek::() { - Ok(TypedefSyntax::Union(parser.parse()?)) - } else if l.peek::() { - Ok(TypedefSyntax::Variant(parser.parse()?)) - } else if l.peek::() { - Ok(TypedefSyntax::Handle(parser.parse()?)) - } else if l.peek::() { - parser.parse::()?; - Ok(TypedefSyntax::List(Box::new(parser.parse()?))) - } else if l.peek::() { - parser.parse::()?; - let mut l = parser.lookahead1(); - if l.peek::() { - parser.parse::()?; - Ok(TypedefSyntax::ConstPointer(Box::new(parser.parse()?))) - } else if l.peek::() { - parser.parse::()?; - Ok(TypedefSyntax::Pointer(Box::new(parser.parse()?))) - } else if l.peek::() { - parser.parse::()?; - Ok(TypedefSyntax::Builtin(BuiltinType::U32 { - lang_ptr_size: true, - })) - } else if l.peek::() { - parser.parse::()?; - Ok(TypedefSyntax::Builtin(BuiltinType::U8 { - lang_c_char: true, - })) - } else { - Err(l.error()) - } - } else { - Err(l.error()) - } - }) - } else { - Err(l.error()) - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct EnumSyntax<'a> { - pub repr: Option, - pub members: Vec>>, -} - -impl<'a> Parse<'a> for EnumSyntax<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let repr = if parser.peek2::() { - Some(parser.parens(|p| { - p.parse::()?; - p.parse::()?; - p.parse() - })?) - } else { - None - }; - let mut members = Vec::new(); - members.push(parser.parse()?); - while !parser.is_empty() { - members.push(parser.parse()?); - } - Ok(EnumSyntax { repr, members }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct TupleSyntax<'a> { - pub types: Vec>, -} - -impl<'a> Parse<'a> for TupleSyntax<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let mut types = Vec::new(); - while !parser.is_empty() { - types.push(parser.parse()?); - } - Ok(TupleSyntax { types }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ExpectedSyntax<'a> { - pub ok: Option>>, - pub err: Option>>, -} - -impl<'a> Parse<'a> for ExpectedSyntax<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let ok = if !parser.is_empty() && !parser.peek2::() { - Some(Box::new(parser.parse()?)) - } else { - None - }; - let err = parser.parens(|p| { - p.parse::()?; - Ok(if p.is_empty() { - None - } else { - Some(Box::new(p.parse()?)) - }) - })?; - Ok(ExpectedSyntax { ok, err }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ConstSyntax<'a> { - pub ty: wast::Id<'a>, - pub name: wast::Id<'a>, - pub value: u64, -} - -impl<'a> Parse<'a> for ConstSyntax<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - parser.parse::()?; - let ty = parser.parse()?; - let name = parser.parse()?; - let value = parser.parse()?; - Ok(ConstSyntax { ty, name, value }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FlagsSyntax<'a> { - pub repr: Option, - pub flags: Vec>>, -} - -impl<'a> Parse<'a> for FlagsSyntax<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let repr = if parser.peek2::() { - Some(parser.parens(|p| { - p.parse::()?; - p.parse::()?; - p.parse() - })?) - } else { - None - }; - let mut flags = Vec::new(); - while !parser.is_empty() { - flags.push(parser.parse()?); - } - Ok(FlagsSyntax { repr, flags }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RecordSyntax<'a> { - pub fields: Vec>>, -} - -impl<'a> Parse<'a> for RecordSyntax<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let mut fields = Vec::new(); - fields.push(parser.parse()?); - while !parser.is_empty() { - fields.push(parser.parse()?); - } - Ok(RecordSyntax { fields }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FieldSyntax<'a> { - pub name: wast::Id<'a>, - pub type_: TypedefSyntax<'a>, -} - -impl<'a> Parse<'a> for FieldSyntax<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parens(|p| { - p.parse::()?; - let name = p.parse()?; - let type_ = p.parse()?; - Ok(FieldSyntax { name, type_ }) - }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct UnionSyntax<'a> { - pub tag: Option>>, - pub fields: Vec>>, -} - -impl<'a> Parse<'a> for UnionSyntax<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let tag = if parser.peek2::() { - Some(parser.parens(|p| { - p.parse::()?; - p.parse::()?; - p.parse().map(Box::new) - })?) - } else { - None - }; - let mut fields = Vec::new(); - while !parser.is_empty() { - fields.push(parser.parse()?); - } - Ok(UnionSyntax { tag, fields }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct VariantSyntax<'a> { - pub tag: Option>>, - pub cases: Vec>>, -} - -impl<'a> Parse<'a> for VariantSyntax<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let tag = if parser.peek2::() { - Some(parser.parens(|p| { - p.parse::()?; - p.parse::()?; - p.parse().map(Box::new) - })?) - } else { - None - }; - let mut cases = Vec::new(); - while !parser.is_empty() { - let comments = parser.parse()?; - let item = parser.parens(|p| p.parse())?; - cases.push(Documented { comments, item }); - } - Ok(VariantSyntax { tag, cases }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct CaseSyntax<'a> { - pub name: wast::Id<'a>, - pub ty: Option>, -} - -impl<'a> Parse<'a> for CaseSyntax<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - Ok(CaseSyntax { - name: parser.parse()?, - ty: if parser.is_empty() { - None - } else { - Some(parser.parse()?) - }, - }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct HandleSyntax {} - -impl<'a> Parse<'a> for HandleSyntax { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - Ok(HandleSyntax {}) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ModuleSyntax<'a> { - pub name: wast::Id<'a>, - pub decls: Vec>>, -} - -impl<'a> Parse<'a> for ModuleSyntax<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let name = parser.parse()?; - let mut decls = Vec::new(); - while !parser.is_empty() { - decls.push(parser.parse()?); - } - Ok(ModuleSyntax { name, decls }) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ModuleDeclSyntax<'a> { - Import(ModuleImportSyntax<'a>), - Func(InterfaceFuncSyntax<'a>), -} - -impl<'a> Parse<'a> for ModuleDeclSyntax<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parens(|p| { - let mut l = p.lookahead1(); - if l.peek::() { - Ok(ModuleDeclSyntax::Import(p.parse()?)) - } else if l.peek::() { - Ok(ModuleDeclSyntax::Func(p.parse()?)) - } else { - Err(l.error()) - } - }) - } -} - -#[derive(Debug, Clone)] -pub struct ModuleImportSyntax<'a> { - pub name: &'a str, - pub name_loc: wast::Span, - pub type_: ImportTypeSyntax, -} - -impl<'a> Parse<'a> for ModuleImportSyntax<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let name_loc = parser.cur_span(); - Ok(ModuleImportSyntax { - name: parser.parse()?, - name_loc, - type_: parser.parens(|p| p.parse())?, - }) - } -} - -impl PartialEq for ModuleImportSyntax<'_> { - fn eq(&self, other: &ModuleImportSyntax<'_>) -> bool { - // skip the `name_loc` field - self.name == other.name && self.type_ == other.type_ - } -} - -impl Eq for ModuleImportSyntax<'_> {} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ImportTypeSyntax { - Memory, -} - -impl Parse<'_> for ImportTypeSyntax { - fn parse(parser: Parser<'_>) -> Result { - parser.parse::()?; - Ok(ImportTypeSyntax::Memory) - } -} - -#[derive(Debug, Clone)] -pub struct InterfaceFuncSyntax<'a> { - pub export: &'a str, - pub export_loc: wast::Span, - pub params: Vec>>, - pub results: Vec>>, - pub noreturn: bool, -} - -impl<'a> Parse<'a> for InterfaceFuncSyntax<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - parser.parse::()?; - - let (export_loc, export) = parser.parens(|p| { - p.parse::()?; - Ok((p.cur_span(), p.parse()?)) - })?; - - let mut params = Vec::new(); - let mut results = Vec::new(); - let mut noreturn = false; - - while !parser.is_empty() { - let func_field = parser.parse::>()?; - match func_field.item { - InterfaceFuncField::Param(item) => { - params.push(Documented { - comments: func_field.comments, - item, - }); - } - InterfaceFuncField::Result(item) => { - results.push(Documented { - comments: func_field.comments, - item, - }); - } - InterfaceFuncField::Noreturn => { - noreturn = true; - } - } - } - - Ok(InterfaceFuncSyntax { - export, - export_loc, - params, - results, - noreturn, - }) - } -} - -enum InterfaceFuncField<'a> { - Param(FieldSyntax<'a>), - Result(FieldSyntax<'a>), - Noreturn, -} -impl<'a> Parse<'a> for InterfaceFuncField<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parens(|p| { - let mut l = p.lookahead1(); - if l.peek::() { - parser.parse::()?; - Ok(InterfaceFuncField::Param(FieldSyntax { - name: parser.parse()?, - type_: parser.parse()?, - })) - } else if l.peek::() { - parser.parse::()?; - Ok(InterfaceFuncField::Result(FieldSyntax { - name: parser.parse()?, - type_: parser.parse()?, - })) - } else if l.peek::() { - parser.parse::()?; - let mut l = parser.lookahead1(); - if l.peek::() { - parser.parse::()?; - Ok(InterfaceFuncField::Noreturn) - } else { - Err(l.error()) - } - } else { - Err(l.error()) - } - }) - } -} - -impl PartialEq for InterfaceFuncSyntax<'_> { - fn eq(&self, other: &InterfaceFuncSyntax<'_>) -> bool { - // skip the `export_loc` field - self.export == other.export - && self.params == other.params - && self.results == other.results - && self.noreturn == other.noreturn - } -} - -impl Eq for InterfaceFuncSyntax<'_> {} diff --git a/legacy/tools/witx/src/phases.rs b/legacy/tools/witx/src/phases.rs deleted file mode 100644 index 0bf697e21..000000000 --- a/legacy/tools/witx/src/phases.rs +++ /dev/null @@ -1,75 +0,0 @@ -use anyhow::{bail, Result}; -use std::env; -use std::path::{Path, PathBuf}; - -pub fn docs_path(phase_paths: &[PathBuf]) -> PathBuf { - phase_paths - .get(0) - .expect("at least one path") - .parent() - .expect("drop file") - .join("../docs.md") -} - -pub fn snapshot() -> Result> { - let root = repo_root()?; - let snapshot = root.join("phases/snapshot/witx"); - let paths = vec![snapshot.join("wasi_snapshot_preview1.witx")]; - ensure_exists(&paths)?; - Ok(paths) -} - -pub fn ephemeral() -> Result> { - let root = repo_root()?; - let ephemeral = root.join("phases/ephemeral/witx"); - let paths = vec![ - ephemeral.join("wasi_ephemeral_args.witx"), - ephemeral.join("wasi_ephemeral_clock.witx"), - ephemeral.join("wasi_ephemeral_environ.witx"), - ephemeral.join("wasi_ephemeral_fd.witx"), - ephemeral.join("wasi_ephemeral_path.witx"), - ephemeral.join("wasi_ephemeral_poll.witx"), - ephemeral.join("wasi_ephemeral_proc.witx"), - ephemeral.join("wasi_ephemeral_random.witx"), - ephemeral.join("wasi_ephemeral_sched.witx"), - ephemeral.join("wasi_ephemeral_sock.witx"), - ]; - ensure_exists(&paths)?; - Ok(paths) -} - -pub mod old { - use super::*; - pub fn snapshot_0() -> Result> { - let root = repo_root()?; - let snapshot_0 = root.join("phases/old/snapshot_0/witx"); - let paths = vec![snapshot_0.join("wasi_unstable.witx")]; - ensure_exists(&paths)?; - Ok(paths) - } -} - -fn repo_root() -> Result { - let repo_root = if let Ok(e) = env::var("WASI_REPO") { - PathBuf::from(e) - } else { - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..") - }; - if repo_root.exists() { - Ok(repo_root) - } else { - bail!("could not find WASI repo root - try setting WASI_REPO env variable") - } -} - -fn ensure_exists(paths: &[PathBuf]) -> Result<()> { - for p in paths.iter() { - if !p.exists() { - bail!( - "{} does not exist - is WASI_REPO set to repository root?", - Path::display(p) - ) - } - } - Ok(()) -} diff --git a/legacy/tools/witx/src/polyfill.rs b/legacy/tools/witx/src/polyfill.rs deleted file mode 100644 index c779cfa4e..000000000 --- a/legacy/tools/witx/src/polyfill.rs +++ /dev/null @@ -1,255 +0,0 @@ -use crate::{ - Document, Id, InterfaceFunc, InterfaceFuncParam, Module, RepEquality, Representable, Type, - TypeRef, -}; -use std::collections::{HashMap, HashSet}; -use std::rc::Rc; -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum PolyfillError { - #[error("Module not present: {name:?}")] - ModuleNotPresent { name: Id }, - #[error("Function not present: {name:?}")] - FuncNotPresent { module: Id, name: Id }, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Polyfill { - pub modules: Vec, -} - -impl Polyfill { - pub fn new( - new: &Document, - old: &Document, - module_mapping: &HashMap, // Will need a more sophisticated mapping - what about function names, argument names? - ) -> Result { - let mut modules = Vec::new(); - for (newname, oldname) in module_mapping { - let newname = Id::new(newname); - let oldname = Id::new(oldname); - let newmod = new - .module(&newname) - .ok_or_else(|| PolyfillError::ModuleNotPresent { name: newname })?; - let oldmod = old - .module(&oldname) - .ok_or_else(|| PolyfillError::ModuleNotPresent { name: oldname })?; - modules.push(ModulePolyfill::new(newmod, oldmod)?); - } - Ok(Polyfill { modules }) - } - - pub fn type_polyfills(&self) -> HashSet { - self.modules - .iter() - .map(|m| m.type_polyfills()) - .flatten() - .collect() - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ModulePolyfill { - pub new: Rc, - pub old: Rc, - pub funcs: Vec, -} - -impl ModulePolyfill { - pub fn new(new: Rc, old: Rc) -> Result { - let mut funcs = Vec::new(); - for oldfunc in old.funcs() { - let newfunc = new - .func(&oldfunc.name) - .ok_or_else(|| PolyfillError::FuncNotPresent { - module: new.name.clone(), - name: oldfunc.name.clone(), - })?; - funcs.push(FuncPolyfill::new(newfunc, oldfunc)); - } - Ok(ModulePolyfill { new, old, funcs }) - } - pub fn type_polyfills(&self) -> HashSet { - self.funcs - .iter() - .map(|f| f.type_polyfills()) - .flatten() - .collect() - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct FuncPolyfill { - pub new: Rc, - pub old: Rc, - pub mapped_params: Vec, - pub unknown_params: Vec, - pub mapped_results: Vec, - pub unknown_results: Vec, -} - -impl FuncPolyfill { - pub fn new(new: Rc, old: Rc) -> FuncPolyfill { - let mut mapped_params = Vec::new(); - let mut unknown_params = Vec::new(); - - // Old function is called. Need to map each of its parameters to the new function: - for old_param in old.params.iter() { - if let Some(new_param) = new.params.iter().find(|p| p.name == old_param.name) { - mapped_params.push(ParamPolyfill::param(new_param.clone(), old_param.clone())) - } else { - unknown_params.push(ParamUnknown::Old(old_param.clone())); - } - } - // Are any new params not covered by the old params? - // This search is O(n^2), but n ought to be small. - for new_param in new.params.iter() { - if mapped_params - .iter() - .find(|m| m.new.name == new_param.name) - .is_none() - { - unknown_params.push(ParamUnknown::New(new_param.clone())); - } - } - - let mut mapped_results = Vec::new(); - let mut unknown_results = Vec::new(); - - // New function has returned. Need to map each of its results to the old function: - for new_result in new.results.iter() { - if let Some(old_result) = old.results.iter().find(|p| p.name == new_result.name) { - mapped_results.push(ParamPolyfill::result( - new_result.clone(), - old_result.clone(), - )) - } else { - unknown_results.push(ParamUnknown::New(new_result.clone())); - } - } - - // Are any old results not covered by the new results? - for old_result in old.results.iter() { - if mapped_results - .iter() - .find(|m| m.old.name == old_result.name) - .is_none() - { - unknown_results.push(ParamUnknown::Old(old_result.clone())); - } - } - - FuncPolyfill { - new, - old, - mapped_params, - unknown_params, - mapped_results, - unknown_results, - } - } - - pub fn full_compat(&self) -> bool { - self.new.name == self.old.name - && self.mapped_params.iter().all(|p| p.full_compat()) - && self.unknown_params.is_empty() - && self.mapped_results.iter().all(|p| p.full_compat()) - && self.unknown_results.is_empty() - } - - pub fn type_polyfills(&self) -> HashSet { - self.mapped_params - .iter() - .map(|p| p.type_polyfill.clone()) - .chain(self.mapped_results.iter().map(|p| p.type_polyfill.clone())) - .collect() - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ParamPolyfill { - pub new: InterfaceFuncParam, - pub old: InterfaceFuncParam, - pub type_polyfill: TypePolyfill, -} - -impl ParamPolyfill { - fn common_denominator(a: TypeRef, b: TypeRef) -> (TypeRef, TypeRef) { - match (&a, &b) { - (TypeRef::Value(va), TypeRef::Value(vb)) => match (&**va, &**vb) { - (Type::List(a), Type::List(b)) => (a.clone(), b.clone()), - (Type::Pointer(a), Type::Pointer(b)) => (a.clone(), b.clone()), - (Type::ConstPointer(a), Type::ConstPointer(b)) => (a.clone(), b.clone()), - _ => (a, b), - }, - _ => (a, b), - } - } - - pub fn param(new: InterfaceFuncParam, old: InterfaceFuncParam) -> Self { - let (told, tnew) = Self::common_denominator(old.tref.clone(), new.tref.clone()); - // Call new param type with old param: - let type_polyfill = TypePolyfill::OldToNew(told, tnew); - ParamPolyfill { - new, - old, - type_polyfill, - } - } - - pub fn result(new: InterfaceFuncParam, old: InterfaceFuncParam) -> Self { - let (told, tnew) = Self::common_denominator(old.tref.clone(), new.tref.clone()); - // Return old result type from new result: - let type_polyfill = TypePolyfill::NewToOld(tnew, told); - ParamPolyfill { - new, - old, - type_polyfill, - } - } - - pub fn full_compat(&self) -> bool { - self.new.name == self.old.name && self.repeq() == RepEquality::Eq - } - - pub fn repeq(&self) -> RepEquality { - self.type_polyfill.repeq() - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum ParamUnknown { - Old(InterfaceFuncParam), - New(InterfaceFuncParam), -} - -impl ParamUnknown { - pub fn which(&self) -> &'static str { - match self { - ParamUnknown::Old { .. } => "old", - ParamUnknown::New { .. } => "new", - } - } - pub fn param(&self) -> &InterfaceFuncParam { - match self { - ParamUnknown::Old(p) => &p, - ParamUnknown::New(p) => &p, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum TypePolyfill { - NewToOld(TypeRef, TypeRef), - OldToNew(TypeRef, TypeRef), -} - -impl TypePolyfill { - pub fn repeq(&self) -> RepEquality { - match self { - TypePolyfill::NewToOld(new, old) => old.type_().representable(&new.type_()), - TypePolyfill::OldToNew(old, new) => new.type_().representable(&old.type_()), - } - } -} diff --git a/legacy/tools/witx/src/render.rs b/legacy/tools/witx/src/render.rs deleted file mode 100644 index a740e282c..000000000 --- a/legacy/tools/witx/src/render.rs +++ /dev/null @@ -1,320 +0,0 @@ -use crate::ast::*; -use std::fmt; - -impl fmt::Display for Document { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for d in self.typenames() { - write!(f, "{}\n", d.to_sexpr())?; - } - for m in self.modules() { - write!(f, "{}\n", m.to_sexpr())?; - } - Ok(()) - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum SExpr { - Vec(Vec), - Word(String), - Ident(String), - Quote(String), - /// Short for Annotation - Annot(String), - /// Doc comment - Docs(String, Box), -} - -impl fmt::Display for SExpr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - SExpr::Vec(vs) => { - write!(f, "(")?; - let mut vss = Vec::new(); - for v in vs { - vss.push(format!("{}", v)); - } - f.write_str(&vss.join(" "))?; - write!(f, ")") - } - SExpr::Word(w) => write!(f, "{}", w), - SExpr::Ident(i) => write!(f, "${}", i), - SExpr::Quote(q) => write!(f, "\"{}\"", q), - SExpr::Annot(a) => write!(f, "@{}", a), - SExpr::Docs(d, s) => write!(f, "(;; {} ;) {}", d, s), - } - } -} - -impl SExpr { - pub fn word(s: &str) -> SExpr { - SExpr::Word(s.to_string()) - } - pub fn ident(s: &str) -> SExpr { - SExpr::Ident(s.to_string()) - } - pub fn quote(s: &str) -> SExpr { - SExpr::Quote(s.to_string()) - } - pub fn annot(s: &str) -> SExpr { - SExpr::Annot(s.to_string()) - } - pub fn docs(d: &str, s: SExpr) -> SExpr { - if d.is_empty() { - s - } else { - SExpr::Docs(d.to_string(), Box::new(s)) - } - } -} - -impl Id { - pub fn to_sexpr(&self) -> SExpr { - SExpr::ident(self.as_str()) - } -} - -impl BuiltinType { - pub fn to_sexpr(&self) -> SExpr { - match self { - BuiltinType::Char => SExpr::word("char"), - BuiltinType::U8 { lang_c_char: true } => { - SExpr::Vec(vec![SExpr::annot("witx"), SExpr::word("char8")]) - } - BuiltinType::U8 { lang_c_char: false } => SExpr::word("u8"), - BuiltinType::U16 => SExpr::word("u16"), - BuiltinType::U32 { - lang_ptr_size: false, - } => SExpr::word("u32"), - BuiltinType::U32 { - lang_ptr_size: true, - } => SExpr::Vec(vec![SExpr::annot("witx"), SExpr::word("usize")]), - BuiltinType::U64 => SExpr::word("u64"), - BuiltinType::S8 => SExpr::word("s8"), - BuiltinType::S16 => SExpr::word("s16"), - BuiltinType::S32 => SExpr::word("s32"), - BuiltinType::S64 => SExpr::word("s64"), - BuiltinType::F32 => SExpr::word("f32"), - BuiltinType::F64 => SExpr::word("f64"), - } - } -} - -impl NamedType { - pub fn to_sexpr(&self) -> SExpr { - let body = self.tref.to_sexpr(); - SExpr::docs( - &self.docs, - SExpr::Vec(vec![SExpr::word("typename"), self.name.to_sexpr(), body]), - ) - } -} - -impl TypeRef { - pub fn to_sexpr(&self) -> SExpr { - match self { - TypeRef::Name(n) => n.name.to_sexpr(), - TypeRef::Value(v) => v.to_sexpr(), - } - } -} - -impl Type { - pub fn to_sexpr(&self) -> SExpr { - match self { - Type::Record(a) => a.to_sexpr(), - Type::Variant(a) => a.to_sexpr(), - Type::Handle(a) => a.to_sexpr(), - Type::List(a) => SExpr::Vec(vec![SExpr::word("list"), a.to_sexpr()]), - Type::Pointer(p) => SExpr::Vec(vec![ - SExpr::annot("witx"), - SExpr::word("pointer"), - p.to_sexpr(), - ]), - Type::ConstPointer(p) => SExpr::Vec(vec![ - SExpr::annot("witx"), - SExpr::word("const_pointer"), - p.to_sexpr(), - ]), - Type::Builtin(b) => b.to_sexpr(), - } - } -} - -impl RecordDatatype { - pub fn to_sexpr(&self) -> SExpr { - match self.kind { - RecordKind::Tuple => { - let mut tuple = vec![SExpr::word("tuple")]; - for m in self.members.iter() { - tuple.push(SExpr::docs(&m.docs, m.tref.to_sexpr())); - } - SExpr::Vec(tuple) - } - RecordKind::Bitflags(repr) => { - let mut flags = vec![SExpr::word("flags")]; - flags.push(SExpr::Vec(vec![ - SExpr::word("@witx"), - SExpr::word("repr"), - repr.to_sexpr(), - ])); - flags.extend( - self.members - .iter() - .map(|m| SExpr::docs(&m.docs, m.name.to_sexpr())), - ); - SExpr::Vec(flags) - } - RecordKind::Other => { - let header = vec![SExpr::word("record")]; - let members = self - .members - .iter() - .map(|m| { - SExpr::docs( - &m.docs, - SExpr::Vec(vec![ - SExpr::word("field"), - m.name.to_sexpr(), - m.tref.to_sexpr(), - ]), - ) - }) - .collect::>(); - SExpr::Vec([header, members].concat()) - } - } - } -} - -impl Variant { - pub fn to_sexpr(&self) -> SExpr { - let mut list = Vec::new(); - if self.is_bool() { - return SExpr::word("bool"); - } else if self.is_enum() { - list.push(SExpr::word("enum")); - list.push(SExpr::Vec(vec![ - SExpr::word("@witx"), - SExpr::word("tag"), - self.tag_repr.to_sexpr(), - ])); - for case in self.cases.iter() { - list.push(SExpr::docs(&case.docs, case.name.to_sexpr())); - } - } else { - list.push(SExpr::word("variant")); - list.push(SExpr::Vec(vec![ - SExpr::word("@witx"), - SExpr::word("tag"), - self.tag_repr.to_sexpr(), - ])); - for case in self.cases.iter() { - let mut case_expr = vec![SExpr::word("case"), case.name.to_sexpr()]; - if let Some(ty) = &case.tref { - case_expr.push(ty.to_sexpr()); - } - list.push(SExpr::docs(&case.docs, SExpr::Vec(case_expr))); - } - } - SExpr::Vec(list) - } -} - -impl HandleDatatype { - pub fn to_sexpr(&self) -> SExpr { - SExpr::Vec(vec![SExpr::word("handle")]) - } -} - -impl IntRepr { - pub fn to_sexpr(&self) -> SExpr { - match self { - IntRepr::U8 => SExpr::word("u8"), - IntRepr::U16 => SExpr::word("u16"), - IntRepr::U32 => SExpr::word("u32"), - IntRepr::U64 => SExpr::word("u64"), - } - } -} - -impl Module { - pub fn to_sexpr(&self) -> SExpr { - let header = vec![SExpr::word("module"), self.name.to_sexpr()]; - let definitions = self - .imports() - .map(|i| i.to_sexpr()) - .chain(self.funcs().map(|f| f.to_sexpr())) - .collect::>(); - SExpr::docs(&self.docs, SExpr::Vec([header, definitions].concat())) - } -} - -impl ModuleImport { - pub fn to_sexpr(&self) -> SExpr { - let variant = match self.variant { - ModuleImportVariant::Memory => SExpr::Vec(vec![SExpr::word("memory")]), - }; - SExpr::docs( - &self.docs, - SExpr::Vec(vec![ - SExpr::word("import"), - SExpr::quote(self.name.as_str()), - variant, - ]), - ) - } -} - -impl InterfaceFunc { - pub fn to_sexpr(&self) -> SExpr { - let header = vec![ - SExpr::annot("interface"), - SExpr::word("func"), - SExpr::Vec(vec![ - SExpr::word("export"), - SExpr::quote(self.name.as_str()), - ]), - ]; - let params = self - .params - .iter() - .map(|f| { - SExpr::docs( - &f.docs, - SExpr::Vec(vec![ - SExpr::word("param"), - f.name.to_sexpr(), - f.tref.to_sexpr(), - ]), - ) - }) - .collect(); - let results = self - .results - .iter() - .map(|f| { - SExpr::docs( - &f.docs, - SExpr::Vec(vec![ - SExpr::word("result"), - f.name.to_sexpr(), - f.tref.to_sexpr(), - ]), - ) - }) - .collect(); - let attrs = if self.noreturn { - vec![SExpr::Vec(vec![ - SExpr::annot("witx"), - SExpr::word("noreturn"), - ])] - } else { - vec![] - }; - SExpr::docs( - &self.docs, - SExpr::Vec([header, params, results, attrs].concat()), - ) - } -} diff --git a/legacy/tools/witx/src/representation.rs b/legacy/tools/witx/src/representation.rs deleted file mode 100644 index 589b64e39..000000000 --- a/legacy/tools/witx/src/representation.rs +++ /dev/null @@ -1,161 +0,0 @@ -use crate::{BuiltinType, IntRepr, NamedType, RecordDatatype, Type, TypeRef, Variant}; -use std::collections::HashMap; - -// A lattice. Eq + Eq = Eq, SuperSet + any = NotEq, NotEq + any = NotEq. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum RepEquality { - Eq, - Superset, - NotEq, -} - -impl RepEquality { - pub fn join(&self, rhs: &Self) -> Self { - match (self, rhs) { - (RepEquality::Eq, RepEquality::Eq) => RepEquality::Eq, - _ => RepEquality::NotEq, - } - } -} - -pub trait Representable { - fn representable(&self, by: &Self) -> RepEquality; -} - -impl Representable for BuiltinType { - fn representable(&self, by: &Self) -> RepEquality { - // An unsigned integer can be used to represent an unsigned integer of smaller width. - // Otherwise, types must be equal. - if self == by { - return RepEquality::Eq; - } - match self { - BuiltinType::U8 { .. } => match by { - BuiltinType::U64 | BuiltinType::U32 { .. } | BuiltinType::U16 => { - RepEquality::Superset - } - _ => RepEquality::NotEq, - }, - BuiltinType::U16 => match by { - BuiltinType::U64 | BuiltinType::U32 { .. } => RepEquality::Superset, - _ => RepEquality::NotEq, - }, - BuiltinType::U32 { .. } => match by { - BuiltinType::U64 => RepEquality::Superset, - _ => RepEquality::NotEq, - }, - _ => RepEquality::NotEq, - } - } -} - -impl Representable for IntRepr { - fn representable(&self, by: &Self) -> RepEquality { - if self == by { - return RepEquality::Eq; - } - // An unsigned integer can be used to represent an unsigned integer of smaller width. - match self { - IntRepr::U16 => match by { - IntRepr::U32 | IntRepr::U64 => RepEquality::Superset, - _ => RepEquality::NotEq, - }, - IntRepr::U32 => match by { - IntRepr::U64 => RepEquality::Superset, - _ => RepEquality::NotEq, - }, - _ => RepEquality::NotEq, - } - } -} - -impl Representable for Variant { - fn representable(&self, by: &Self) -> RepEquality { - let mut superset = false; - // Integer representation must be compatible - match self.tag_repr.representable(&by.tag_repr) { - RepEquality::NotEq => return RepEquality::NotEq, - RepEquality::Eq => {} - RepEquality::Superset => superset = true, - } - let other_by_name = by - .cases - .iter() - .enumerate() - .map(|(i, c)| (&c.name, (c, i))) - .collect::>(); - // For each variant in self, must have variant of same name in by: - for (i, v) in self.cases.iter().enumerate() { - let other_ty = match other_by_name.get(&v.name) { - Some((_, j)) if i != *j => return RepEquality::NotEq, - Some((other, _)) => &other.tref, - None => return RepEquality::NotEq, - }; - match (&v.tref, other_ty) { - (Some(me), Some(other)) => match me.representable(other) { - RepEquality::NotEq => return RepEquality::NotEq, - RepEquality::Eq => {} - RepEquality::Superset => superset = true, - }, - // We added fields, that's not ok - (Some(_), None) => return RepEquality::NotEq, - // Fields were deleted, that's ok - (None, Some(_)) => superset = true, - (None, None) => {} - } - } - if superset || self.cases.len() < by.cases.len() { - RepEquality::Superset - } else { - RepEquality::Eq - } - } -} - -impl Representable for RecordDatatype { - fn representable(&self, by: &Self) -> RepEquality { - // Records must have exact structural equality - same members, must - // be Eq, in the same order. - // We would require require a more expressive RepEquality enum to describe which members - // might be supersets. - if self.members.len() != by.members.len() { - return RepEquality::NotEq; - } - for (m, bym) in self.members.iter().zip(by.members.iter()) { - if m.name != bym.name { - return RepEquality::NotEq; - } - if m.tref.type_().representable(&*bym.tref.type_()) != RepEquality::Eq { - return RepEquality::NotEq; - } - } - RepEquality::Eq - } -} - -impl Representable for TypeRef { - fn representable(&self, by: &Self) -> RepEquality { - self.type_().representable(&*by.type_()) - } -} - -impl Representable for NamedType { - fn representable(&self, by: &Self) -> RepEquality { - self.tref.representable(&by.tref) - } -} - -impl Representable for Type { - fn representable(&self, by: &Self) -> RepEquality { - match (&self, &by) { - (Type::Variant(s), Type::Variant(b)) => s.representable(b), - (Type::Record(s), Type::Record(b)) => s.representable(b), - (Type::Handle(_), Type::Handle(_)) => RepEquality::Eq, // Handles are nominal, not structural - (Type::List(s), Type::List(b)) => s.representable(b), - (Type::Pointer(s), Type::Pointer(b)) => s.representable(b), - (Type::ConstPointer(s), Type::ConstPointer(b)) => s.representable(b), - (Type::Builtin(s), Type::Builtin(b)) => s.representable(b), - _ => RepEquality::NotEq, - } - } -} diff --git a/legacy/tools/witx/src/toplevel.rs b/legacy/tools/witx/src/toplevel.rs deleted file mode 100644 index 94dbd1323..000000000 --- a/legacy/tools/witx/src/toplevel.rs +++ /dev/null @@ -1,198 +0,0 @@ -use crate::ast::{Definition, Document}; -use crate::io::{Filesystem, WitxIo}; -use crate::parser::{TopLevelDocument, TopLevelSyntax}; -use crate::validate::DocValidation; -use crate::WitxError; -use std::collections::HashSet; -use std::path::{Path, PathBuf}; - -pub fn parse_witx(i: &[impl AsRef]) -> Result { - let paths = i.iter().map(|p| p.as_ref()).collect::>(); - _parse_witx_with(&paths, &Filesystem) -} - -pub fn parse_witx_with(i: &[impl AsRef], witxio: impl WitxIo) -> Result { - let paths = i.iter().map(|p| p.as_ref()).collect::>(); - _parse_witx_with(&paths, &witxio) -} - -fn _parse_witx_with(paths: &[&Path], io: &dyn WitxIo) -> Result { - let mut validator = DocValidation::new(); - let mut definitions = Vec::new(); - let mut parsed = HashSet::new(); - for path in paths { - let root = path.parent().unwrap_or(Path::new(".")); - - parse_file( - path.file_name().unwrap().as_ref(), - io, - root, - &mut validator, - &mut definitions, - &mut parsed, - )?; - } - Ok(validator.into_document(definitions)) -} - -fn parse_file( - path: &Path, - io: &dyn WitxIo, - root: &Path, - validator: &mut DocValidation, - definitions: &mut Vec, - parsed: &mut HashSet, -) -> Result<(), WitxError> { - let path = io.canonicalize(&root.join(path))?; - if !parsed.insert(path.clone()) { - return Ok(()); - } - let input = io.fgets(&path)?; - - let adjust_err = |mut error: wast::Error| { - error.set_path(&path); - error.set_text(&input); - WitxError::Parse(error) - }; - let buf = wast::parser::ParseBuffer::new(&input).map_err(adjust_err)?; - let doc = wast::parser::parse::(&buf).map_err(adjust_err)?; - - for t in doc.items { - match t.item { - TopLevelSyntax::Decl(d) => { - validator - .scope(&input, &path) - .validate_decl(&d, &t.comments, definitions) - .map_err(WitxError::Validation)?; - } - TopLevelSyntax::Use(u) => { - let root = path.parent().unwrap_or(root); - parse_file(u.as_ref(), io, root, validator, definitions, parsed)?; - } - } - } - - Ok(()) -} - -#[cfg(test)] -mod test { - use super::*; - use crate::ast::*; - use crate::io::MockFs; - - #[test] - fn empty() { - parse_witx_with(&[Path::new("/a")], &MockFs::new(&[("/a", ";; empty")])).expect("parse"); - } - - #[test] - fn one_use() { - parse_witx_with( - &[Path::new("/a")], - &MockFs::new(&[("/a", "(use \"b\")"), ("/b", ";; empty")]), - ) - .unwrap(); - } - - #[test] - fn multi_use() { - let doc = parse_witx_with( - &[Path::new("/a")], - &MockFs::new(&[ - ("/a", "(use \"b\")"), - ("/b", "(use \"c\")\n(typename $b_float f64)"), - ("/c", "(typename $c_int u32)"), - ]), - ) - .expect("parse"); - - let b_float = doc.typename(&Id::new("b_float")).unwrap(); - assert_eq!(**b_float.type_(), Type::Builtin(BuiltinType::F64)); - - let c_int = doc.typename(&Id::new("c_int")).unwrap(); - assert_eq!( - **c_int.type_(), - Type::Builtin(BuiltinType::U32 { - lang_ptr_size: false - }) - ); - } - - #[test] - fn diamond_dependency() { - let doc = parse_witx_with( - &[Path::new("/a")], - &MockFs::new(&[ - ("/a", "(use \"b\")\n(use \"c\")"), - ("/b", "(use \"d\")"), - ("/c", "(use \"d\")"), - ("/d", "(typename $d_char u8)"), - ]), - ) - .expect("parse"); - - let d_char = doc.typename(&Id::new("d_char")).unwrap(); - assert_eq!( - **d_char.type_(), - Type::Builtin(BuiltinType::U8 { lang_c_char: false }) - ); - } - - #[test] - fn multi_use_with_layered_dirs() { - let doc = parse_witx_with( - &[Path::new("/root.witx")], - &MockFs::new(&[ - ("/root.witx", "(use \"subdir/child.witx\")"), - ( - "/subdir/child.witx", - "(use \"sibling.witx\")\n(typename $b_float f64)", - ), - ("/subdir/sibling.witx", "(typename $c_int u32)"), - // This definition looks just like subdir/sibling.witx but - // defines c_int differently - this test shows it does Not get - // included by subdir/child.witx's use. - ("/sibling.witx", "(typename $c_int u64)"), - ]), - ) - .expect("parse"); - - let b_float = doc.typename(&Id::new("b_float")).unwrap(); - assert_eq!(**b_float.type_(), Type::Builtin(BuiltinType::F64)); - - let c_int = doc.typename(&Id::new("c_int")).unwrap(); - assert_eq!( - **c_int.type_(), - Type::Builtin(BuiltinType::U32 { - lang_ptr_size: false - }) - ); - } - - #[test] - fn use_not_found() { - match parse_witx_with(&[Path::new("/a")], &MockFs::new(&[("/a", "(use \"b\")")])) - .err() - .unwrap() - { - WitxError::Io(path, _error) => assert_eq!(path, PathBuf::from("/b")), - e => panic!("wrong error: {:?}", e), - } - } - - #[test] - fn use_invalid() { - match parse_witx_with(&[Path::new("/a")], &MockFs::new(&[("/a", "(use bbbbbbb)")])) - .err() - .unwrap() - { - WitxError::Parse(e) => { - let err = e.to_string(); - assert!(err.contains("expected a string"), "bad error: {}", err); - assert!(err.contains("/a:1:6")); - } - e => panic!("wrong error: {:?}", e), - } - } -} diff --git a/legacy/tools/witx/src/validate.rs b/legacy/tools/witx/src/validate.rs deleted file mode 100644 index cf4d0ad7f..000000000 --- a/legacy/tools/witx/src/validate.rs +++ /dev/null @@ -1,722 +0,0 @@ -use crate::{ - io::{Filesystem, WitxIo}, - parser::{ - CommentSyntax, DeclSyntax, Documented, EnumSyntax, ExpectedSyntax, FlagsSyntax, - HandleSyntax, ImportTypeSyntax, ModuleDeclSyntax, RecordSyntax, TupleSyntax, TypedefSyntax, - UnionSyntax, VariantSyntax, - }, - Abi, BuiltinType, Case, Constant, Definition, Document, Entry, HandleDatatype, Id, IntRepr, - InterfaceFunc, InterfaceFuncParam, Location, Module, ModuleDefinition, ModuleEntry, - ModuleImport, ModuleImportVariant, NamedType, RecordDatatype, RecordKind, RecordMember, Type, - TypeRef, Variant, -}; -use std::collections::{HashMap, HashSet}; -use std::path::Path; -use std::rc::Rc; -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum ValidationError { - #[error("Unknown name `{name}`")] - UnknownName { name: String, location: Location }, - #[error("Redefinition of name `{name}`")] - NameAlreadyExists { - name: String, - at_location: Location, - previous_location: Location, - }, - #[error("Wrong kind of name `{name}`: expected {expected}, got {got}")] - WrongKindName { - name: String, - location: Location, - expected: &'static str, - got: &'static str, - }, - #[error("Recursive definition of name `{name}`")] - Recursive { name: String, location: Location }, - #[error("Invalid representation `{repr:?}`")] - InvalidRepr { - repr: BuiltinType, - location: Location, - }, - #[error("ABI error: {reason}")] - Abi { reason: String, location: Location }, - #[error("Anonymous structured types (struct, union, enum, flags, handle) are not permitted")] - AnonymousRecord { location: Location }, - #[error("Union expected {expected} variants, found {found}")] - UnionSizeMismatch { - expected: usize, - found: usize, - location: Location, - }, - #[error("Invalid union tag: {reason}")] - InvalidUnionTag { reason: String, location: Location }, - #[error("Invalid union field `{name}`: {reason}")] - InvalidUnionField { - name: String, - reason: String, - location: Location, - }, -} - -impl ValidationError { - pub fn report_with(&self, witxio: &dyn WitxIo) -> String { - use ValidationError::*; - match self { - UnknownName { location, .. } - | WrongKindName { location, .. } - | Recursive { location, .. } - | InvalidRepr { location, .. } - | Abi { location, .. } - | AnonymousRecord { location, .. } - | UnionSizeMismatch { location, .. } - | InvalidUnionField { location, .. } - | InvalidUnionTag { location, .. } => { - format!("{}\n{}", location.highlight_source_with(witxio), &self) - } - NameAlreadyExists { - at_location, - previous_location, - .. - } => format!( - "{}\n{}\nOriginally defined at:\n{}", - at_location.highlight_source_with(witxio), - &self, - previous_location.highlight_source_with(witxio), - ), - } - } - pub fn report(&self) -> String { - self.report_with(&Filesystem) - } -} - -struct IdentValidation { - names: HashMap, -} - -impl IdentValidation { - fn new() -> Self { - Self { - names: HashMap::new(), - } - } - - fn introduce(&mut self, syntax: &str, location: Location) -> Result { - if let Some(introduced) = self.names.get(syntax) { - Err(ValidationError::NameAlreadyExists { - name: syntax.to_string(), - at_location: location, - previous_location: introduced.clone(), - }) - } else { - self.names.insert(syntax.to_string(), location); - Ok(Id::new(syntax)) - } - } - - fn get(&self, syntax: &str, location: Location) -> Result { - if self.names.get(syntax).is_some() { - Ok(Id::new(syntax)) - } else { - Err(ValidationError::UnknownName { - name: syntax.to_string(), - location, - }) - } - } -} - -pub struct DocValidation { - scope: IdentValidation, - entries: HashMap, - constant_scopes: HashMap, - bool_ty: TypeRef, -} - -pub struct DocValidationScope<'a> { - doc: &'a mut DocValidation, - text: &'a str, - path: &'a Path, -} - -impl DocValidation { - pub fn new() -> Self { - Self { - scope: IdentValidation::new(), - entries: HashMap::new(), - constant_scopes: HashMap::new(), - bool_ty: TypeRef::Value(Rc::new(Type::Variant(Variant { - tag_repr: IntRepr::U32, - cases: vec![ - Case { - name: Id::new("false"), - tref: None, - docs: String::new(), - }, - Case { - name: Id::new("true"), - tref: None, - docs: String::new(), - }, - ], - }))), - } - } - - pub fn scope<'a>(&'a mut self, text: &'a str, path: &'a Path) -> DocValidationScope<'a> { - DocValidationScope { - doc: self, - text, - path, - } - } - - pub fn into_document(self, defs: Vec) -> Document { - Document::new(defs, self.entries) - } -} - -impl DocValidationScope<'_> { - fn location(&self, span: wast::Span) -> Location { - // Wast Span gives 0-indexed lines and columns. Location is 1-indexed. - let (line, column) = span.linecol_in(self.text); - Location { - line: line + 1, - column: column + 1, - path: self.path.to_path_buf(), - } - } - - fn introduce(&mut self, name: &wast::Id<'_>) -> Result { - let loc = self.location(name.span()); - self.doc.scope.introduce(name.name(), loc) - } - - fn get(&self, name: &wast::Id<'_>) -> Result { - let loc = self.location(name.span()); - self.doc.scope.get(name.name(), loc) - } - - pub fn validate_decl( - &mut self, - decl: &DeclSyntax, - comments: &CommentSyntax, - definitions: &mut Vec, - ) -> Result<(), ValidationError> { - match decl { - DeclSyntax::Typename(decl) => { - let name = self.introduce(&decl.ident)?; - let docs = comments.docs(); - let tref = self.validate_datatype(&decl.def, true, decl.ident.span())?; - - let rc_datatype = Rc::new(NamedType { - name: name.clone(), - tref, - docs, - }); - self.doc - .entries - .insert(name.clone(), Entry::Typename(Rc::downgrade(&rc_datatype))); - definitions.push(Definition::Typename(rc_datatype)); - } - - DeclSyntax::Module(syntax) => { - let name = self.introduce(&syntax.name)?; - let mut module_validator = ModuleValidation::new(self); - let decls = syntax - .decls - .iter() - .map(|d| module_validator.validate_decl(&d)) - .collect::, _>>()?; - - let rc_module = Rc::new(Module::new( - name.clone(), - decls, - module_validator.entries, - comments.docs(), - )); - self.doc - .entries - .insert(name, Entry::Module(Rc::downgrade(&rc_module))); - definitions.push(Definition::Module(rc_module)); - } - - DeclSyntax::Const(syntax) => { - let ty = Id::new(syntax.item.ty.name()); - let loc = self.location(syntax.item.name.span()); - let scope = self - .doc - .constant_scopes - .entry(ty.clone()) - .or_insert_with(IdentValidation::new); - let name = scope.introduce(syntax.item.name.name(), loc)?; - // TODO: validate `ty` is a integer datatype that `syntax.value` - // fits within. - definitions.push(Definition::Constant(Constant { - ty, - name, - value: syntax.item.value, - docs: syntax.comments.docs(), - })); - } - } - Ok(()) - } - - fn validate_datatype( - &self, - syntax: &TypedefSyntax, - named: bool, - span: wast::Span, - ) -> Result { - match syntax { - TypedefSyntax::Ident(syntax) => { - let i = self.get(syntax)?; - match self.doc.entries.get(&i) { - Some(Entry::Typename(weak_ref)) => Ok(TypeRef::Name( - weak_ref.upgrade().expect("weak backref to defined type"), - )), - Some(e) => Err(ValidationError::WrongKindName { - name: i.as_str().to_string(), - location: self.location(syntax.span()), - expected: "datatype", - got: e.kind(), - }), - None => Err(ValidationError::Recursive { - name: i.as_str().to_string(), - location: self.location(syntax.span()), - }), - } - } - TypedefSyntax::Enum { .. } - | TypedefSyntax::Flags { .. } - | TypedefSyntax::Record { .. } - | TypedefSyntax::Union { .. } - | TypedefSyntax::Handle { .. } - if !named => - { - Err(ValidationError::AnonymousRecord { - location: self.location(span), - }) - } - other => Ok(TypeRef::Value(Rc::new(match other { - TypedefSyntax::Enum(syntax) => Type::Variant(self.validate_enum(&syntax, span)?), - TypedefSyntax::Tuple(syntax) => Type::Record(self.validate_tuple(&syntax, span)?), - TypedefSyntax::Expected(syntax) => { - Type::Variant(self.validate_expected(&syntax, span)?) - } - TypedefSyntax::Flags(syntax) => Type::Record(self.validate_flags(&syntax, span)?), - TypedefSyntax::Record(syntax) => Type::Record(self.validate_record(&syntax, span)?), - TypedefSyntax::Union(syntax) => Type::Variant(self.validate_union(&syntax, span)?), - TypedefSyntax::Variant(syntax) => { - Type::Variant(self.validate_variant(&syntax, span)?) - } - TypedefSyntax::Handle(syntax) => Type::Handle(self.validate_handle(syntax, span)?), - TypedefSyntax::List(syntax) => { - Type::List(self.validate_datatype(syntax, false, span)?) - } - TypedefSyntax::Pointer(syntax) => { - Type::Pointer(self.validate_datatype(syntax, false, span)?) - } - TypedefSyntax::ConstPointer(syntax) => { - Type::ConstPointer(self.validate_datatype(syntax, false, span)?) - } - TypedefSyntax::Builtin(builtin) => Type::Builtin(*builtin), - TypedefSyntax::String => { - Type::List(TypeRef::Value(Rc::new(Type::Builtin(BuiltinType::Char)))) - } - TypedefSyntax::Bool => return Ok(self.doc.bool_ty.clone()), - TypedefSyntax::Ident { .. } => unreachable!(), - }))), - } - } - - fn validate_enum( - &self, - syntax: &EnumSyntax, - span: wast::Span, - ) -> Result { - let mut enum_scope = IdentValidation::new(); - let tag_repr = match &syntax.repr { - Some(repr) => self.validate_int_repr(repr, span)?, - None => IntRepr::U32, - }; - let cases = syntax - .members - .iter() - .map(|i| { - let name = enum_scope.introduce(i.item.name(), self.location(i.item.span()))?; - let docs = i.comments.docs(); - Ok(Case { - name, - tref: None, - docs, - }) - }) - .collect::, _>>()?; - - Ok(Variant { tag_repr, cases }) - } - - fn validate_tuple( - &self, - syntax: &TupleSyntax, - span: wast::Span, - ) -> Result { - let members = syntax - .types - .iter() - .enumerate() - .map(|(i, ty)| { - Ok(RecordMember { - name: Id::new(i.to_string()), - tref: self.validate_datatype(ty, false, span)?, - docs: String::new(), - }) - }) - .collect::, _>>()?; - - Ok(RecordDatatype { - kind: RecordKind::Tuple, - members, - }) - } - - fn validate_expected( - &self, - syntax: &ExpectedSyntax, - span: wast::Span, - ) -> Result { - let ok_ty = match &syntax.ok { - Some(ok) => Some(self.validate_datatype(ok, false, span)?), - None => None, - }; - let err_ty = match &syntax.err { - Some(err) => Some(self.validate_datatype(err, false, span)?), - None => None, - }; - Ok(Variant { - tag_repr: IntRepr::U32, - cases: vec![ - Case { - name: Id::new("ok"), - tref: ok_ty, - docs: String::new(), - }, - Case { - name: Id::new("err"), - tref: err_ty, - docs: String::new(), - }, - ], - }) - } - - fn validate_flags( - &self, - syntax: &FlagsSyntax, - span: wast::Span, - ) -> Result { - let repr = match syntax.repr { - Some(ty) => self.validate_int_repr(&ty, span)?, - None => IntRepr::U32, - }; - let mut flags_scope = IdentValidation::new(); - let mut members = Vec::new(); - for flag in syntax.flags.iter() { - let name = flags_scope.introduce(flag.item.name(), self.location(flag.item.span()))?; - let docs = flag.comments.docs(); - members.push(RecordMember { - name, - docs, - tref: self.doc.bool_ty.clone(), - }); - } - Ok(RecordDatatype { - kind: RecordKind::Bitflags(repr), - members, - }) - } - - fn validate_record( - &self, - syntax: &RecordSyntax, - _span: wast::Span, - ) -> Result { - let mut member_scope = IdentValidation::new(); - let members = syntax - .fields - .iter() - .map(|f| { - let name = member_scope - .introduce(f.item.name.name(), self.location(f.item.name.span()))?; - let tref = self.validate_datatype(&f.item.type_, false, f.item.name.span())?; - let docs = f.comments.docs(); - Ok(RecordMember { name, tref, docs }) - }) - .collect::, _>>()?; - - Ok(RecordDatatype { - kind: RecordKind::Other, - members, - }) - } - - fn validate_union( - &self, - syntax: &UnionSyntax, - span: wast::Span, - ) -> Result { - let (tag_repr, names) = self.union_tag_repr(&syntax.tag, span)?; - - if let Some(names) = &names { - if names.len() != syntax.fields.len() { - return Err(ValidationError::UnionSizeMismatch { - expected: names.len(), - found: syntax.fields.len(), - location: self.location(span), - }); - } - } - - let cases = syntax - .fields - .iter() - .enumerate() - .map(|(i, case)| { - Ok(Case { - name: match &names { - Some(names) => names[i].clone(), - None => Id::new(i.to_string()), - }, - tref: Some(self.validate_datatype(&case.item, false, span)?), - docs: case.comments.docs(), - }) - }) - .collect::, _>>()?; - Ok(Variant { tag_repr, cases }) - } - - fn validate_variant( - &self, - syntax: &VariantSyntax, - span: wast::Span, - ) -> Result { - let (tag_repr, names) = self.union_tag_repr(&syntax.tag, span)?; - - if let Some(names) = &names { - if names.len() != syntax.cases.len() { - return Err(ValidationError::UnionSizeMismatch { - expected: names.len(), - found: syntax.cases.len(), - location: self.location(span), - }); - } - } - - let mut name_set = names - .as_ref() - .map(|names| names.iter().collect::>()); - - let mut cases = syntax - .cases - .iter() - .map(|case| { - let name = Id::new(case.item.name.name()); - if let Some(names) = &mut name_set { - if !names.remove(&name) { - return Err(ValidationError::InvalidUnionField { - name: name.as_str().to_string(), - location: self.location(case.item.name.span()), - reason: format!("does not correspond to variant in tag `tag`"), - }); - } - } - Ok(Case { - name: Id::new(case.item.name.name()), - tref: match &case.item.ty { - Some(ty) => { - Some(self.validate_datatype(ty, false, case.item.name.span())?) - } - None => None, - }, - docs: case.comments.docs(), - }) - }) - .collect::, _>>()?; - - // If we have an explicit tag with an enum then that's instructing us to - // reorder cases based on the order of the enum itself, so do that here. - if let Some(names) = names { - let name_pos = names - .iter() - .enumerate() - .map(|(i, name)| (name, i)) - .collect::>(); - cases.sort_by_key(|c| name_pos[&&c.name]); - } - - Ok(Variant { tag_repr, cases }) - } - - fn union_tag_repr( - &self, - tag: &Option>>, - span: wast::Span, - ) -> Result<(IntRepr, Option>), ValidationError> { - let ty = match tag { - Some(tag) => self.validate_datatype(tag, false, span)?, - None => return Ok((IntRepr::U32, None)), - }; - match &**ty.type_() { - Type::Variant(e) => { - let mut names = Vec::new(); - for c in e.cases.iter() { - if c.tref.is_some() { - return Err(ValidationError::InvalidUnionTag { - location: self.location(span), - reason: format!("all variant cases should have empty payloads"), - }); - } - names.push(c.name.clone()); - } - return Ok((e.tag_repr, Some(names))); - } - Type::Builtin(BuiltinType::U8 { .. }) => return Ok((IntRepr::U8, None)), - Type::Builtin(BuiltinType::U16) => return Ok((IntRepr::U16, None)), - Type::Builtin(BuiltinType::U32 { .. }) => return Ok((IntRepr::U32, None)), - Type::Builtin(BuiltinType::U64) => return Ok((IntRepr::U64, None)), - _ => {} - } - - Err(ValidationError::WrongKindName { - name: "tag".to_string(), - location: self.location(span), - expected: "enum or builtin", - got: ty.type_().kind(), - }) - } - - fn validate_handle( - &self, - _syntax: &HandleSyntax, - _span: wast::Span, - ) -> Result { - Ok(HandleDatatype {}) - } - - fn validate_int_repr( - &self, - type_: &BuiltinType, - span: wast::Span, - ) -> Result { - match type_ { - BuiltinType::U8 { .. } => Ok(IntRepr::U8), - BuiltinType::U16 => Ok(IntRepr::U16), - BuiltinType::U32 { .. } => Ok(IntRepr::U32), - BuiltinType::U64 => Ok(IntRepr::U64), - _ => Err(ValidationError::InvalidRepr { - repr: type_.clone(), - location: self.location(span), - }), - } - } -} - -struct ModuleValidation<'a> { - doc: &'a DocValidationScope<'a>, - scope: IdentValidation, - pub entries: HashMap, -} - -impl<'a> ModuleValidation<'a> { - fn new(doc: &'a DocValidationScope<'a>) -> Self { - Self { - doc, - scope: IdentValidation::new(), - entries: HashMap::new(), - } - } - - fn validate_decl( - &mut self, - decl: &Documented, - ) -> Result { - match &decl.item { - ModuleDeclSyntax::Import(syntax) => { - let loc = self.doc.location(syntax.name_loc); - let name = self.scope.introduce(syntax.name, loc)?; - let variant = match syntax.type_ { - ImportTypeSyntax::Memory => ModuleImportVariant::Memory, - }; - let rc_import = Rc::new(ModuleImport { - name: name.clone(), - variant, - docs: decl.comments.docs(), - }); - self.entries - .insert(name, ModuleEntry::Import(Rc::downgrade(&rc_import))); - Ok(ModuleDefinition::Import(rc_import)) - } - ModuleDeclSyntax::Func(syntax) => { - let loc = self.doc.location(syntax.export_loc); - let name = self.scope.introduce(syntax.export, loc)?; - let mut argnames = IdentValidation::new(); - let params = syntax - .params - .iter() - .map(|f| { - Ok(InterfaceFuncParam { - name: argnames.introduce( - f.item.name.name(), - self.doc.location(f.item.name.span()), - )?, - tref: self.doc.validate_datatype( - &f.item.type_, - false, - f.item.name.span(), - )?, - docs: f.comments.docs(), - }) - }) - .collect::, _>>()?; - let results = syntax - .results - .iter() - .map(|f| { - let tref = - self.doc - .validate_datatype(&f.item.type_, false, f.item.name.span())?; - Ok(InterfaceFuncParam { - name: argnames.introduce( - f.item.name.name(), - self.doc.location(f.item.name.span()), - )?, - tref, - docs: f.comments.docs(), - }) - }) - .collect::, _>>()?; - let noreturn = syntax.noreturn; - let abi = Abi::Preview1; - abi.validate(¶ms, &results) - .map_err(|reason| ValidationError::Abi { - reason, - location: self.doc.location(syntax.export_loc), - })?; - let rc_func = Rc::new(InterfaceFunc { - abi, - name: name.clone(), - params, - results, - noreturn, - docs: decl.comments.docs(), - }); - self.entries - .insert(name, ModuleEntry::Func(Rc::downgrade(&rc_func))); - Ok(ModuleDefinition::Func(rc_func)) - } - } - } -} diff --git a/legacy/tools/witx/tests/witxt.rs b/legacy/tools/witx/tests/witxt.rs deleted file mode 100644 index 7c002fe1b..000000000 --- a/legacy/tools/witx/tests/witxt.rs +++ /dev/null @@ -1,656 +0,0 @@ -//! You can run this test suite with: -//! -//! cargo test --test witxt -//! -//! An argument can be passed as well to filter, based on filename, which test -//! to run -//! -//! cargo test --test witxt foo.witxt - -use anyhow::{anyhow, bail, Context, Result}; -use rayon::prelude::*; -use std::collections::HashMap; -use std::path::{Path, PathBuf}; -use std::str; -use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; -use wast::parser::{self, Parse, ParseBuffer, Parser}; -use witx::{Documentation, Instruction, Representable, WasmType}; - -fn main() { - let tests = find_tests(); - let filter = std::env::args().nth(1); - - let tests = tests - .par_iter() - .filter_map(|test| { - if let Some(filter) = &filter { - if let Some(s) = test.to_str() { - if !s.contains(filter) { - return None; - } - } - } - let contents = std::fs::read(test).unwrap(); - Some((test, contents)) - }) - .collect::>(); - - println!("running {} test files\n", tests.len()); - - let ntests = AtomicUsize::new(0); - let errors = tests - .par_iter() - .filter_map(|(test, contents)| { - WitxtRunner { - ntests: &ntests, - documents: HashMap::new(), - } - .run(test, contents) - .err() - }) - .collect::>(); - - if !errors.is_empty() { - for msg in errors.iter() { - eprintln!("{:?}", msg); - } - - panic!("{} tests failed", errors.len()) - } - - println!( - "test result: ok. {} directives passed\n", - ntests.load(SeqCst) - ); -} - -/// Recursively finds all tests in a whitelisted set of directories which we -/// then load up and test in parallel. -fn find_tests() -> Vec { - let mut tests = Vec::new(); - find_tests("tests/witxt".as_ref(), &mut tests); - tests.sort(); - return tests; - - fn find_tests(path: &Path, tests: &mut Vec) { - for f in path.read_dir().unwrap() { - let f = f.unwrap(); - if f.file_type().unwrap().is_dir() { - find_tests(&f.path(), tests); - continue; - } - - match f.path().extension().and_then(|s| s.to_str()) { - Some("witxt") => {} - _ => continue, - } - tests.push(f.path()); - } - } -} - -struct WitxtRunner<'a> { - ntests: &'a AtomicUsize, - documents: HashMap, -} - -impl WitxtRunner<'_> { - fn run(&mut self, test: &Path, contents: &[u8]) -> Result<()> { - let contents = str::from_utf8(contents)?; - macro_rules! adjust { - ($e:expr) => {{ - let mut e = wast::Error::from($e); - e.set_path(test); - e.set_text(contents); - e - }}; - } - let buf = ParseBuffer::new(contents).map_err(|e| adjust!(e))?; - let witxt = parser::parse::(&buf).map_err(|e| adjust!(e))?; - - let errors = witxt - .directives - .into_iter() - .filter_map(|directive| { - let (line, col) = directive.span().linecol_in(contents); - self.test_directive(contents, test, directive) - .with_context(|| { - format!( - "failed directive on {}:{}:{}", - test.display(), - line + 1, - col + 1 - ) - }) - .err() - }) - .collect::>(); - if errors.is_empty() { - return Ok(()); - } - let mut s = format!("{} test failures in {}:", errors.len(), test.display()); - for mut error in errors { - if let Some(err) = error.downcast_mut::() { - err.set_path(test); - err.set_text(contents); - } - s.push_str("\n\n\t--------------------------------\n\n\t"); - s.push_str(&format!("{:?}", error).replace("\n", "\n\t")); - } - bail!("{}", s) - } - - fn test_directive( - &mut self, - contents: &str, - test: &Path, - directive: WitxtDirective, - ) -> Result<()> { - self.bump_ntests(); - match directive { - WitxtDirective::Witx(witx) => { - let doc = witx.document(contents, test)?; - self.assert_roundtrip(&doc) - .context("failed to round-trip the document")?; - self.assert_md(&doc)?; - if let Some(name) = witx.id { - self.documents.insert(name.name().to_string(), doc); - } - } - WitxtDirective::AssertInvalid { witx, message, .. } => { - let err = match witx.document(contents, test) { - Ok(_) => bail!("witx was valid when it shouldn't be"), - Err(e) => format!("{:?}", anyhow::Error::from(e)), - }; - if !err.contains(message) { - bail!("expected error {:?}\nfound error {}", message, err); - } - } - WitxtDirective::AssertRepresentable { repr, t1, t2, .. } => { - let (t1m, t1t) = t1; - let (t2m, t2t) = t2; - let t1d = self - .documents - .get(t1m.name()) - .ok_or_else(|| anyhow!("no document named {:?}", t1m.name()))?; - let t2d = self - .documents - .get(t2m.name()) - .ok_or_else(|| anyhow!("no document named {:?}", t2m.name()))?; - let t1 = t1d - .typename(&witx::Id::new(t1t)) - .ok_or_else(|| anyhow!("no type named {:?}", t1t))?; - let t2 = t2d - .typename(&witx::Id::new(t2t)) - .ok_or_else(|| anyhow!("no type named {:?}", t2t))?; - match (repr, t1.type_().representable(&t2.type_())) { - (RepEquality::Eq, witx::RepEquality::Eq) - | (RepEquality::Superset, witx::RepEquality::Superset) - | (RepEquality::NotEq, witx::RepEquality::NotEq) => {} - (a, b) => { - bail!("expected {:?} representation, got {:?}", a, b); - } - } - } - WitxtDirective::AssertAbi { - witx, - wasm, - interface, - wasm_signature: (wasm_params, wasm_results), - .. - } => { - let doc = witx.document(contents, test)?; - let module = doc.modules().next().ok_or_else(|| anyhow!("no modules"))?; - let func = module.funcs().next().ok_or_else(|| anyhow!("no funcs"))?; - - let (params, results) = func.wasm_signature(); - if params != wasm_params { - bail!("expected params {:?}, found {:?}", wasm_params, params); - } - if results != wasm_results { - bail!("expected results {:?}, found {:?}", wasm_results, results); - } - - let mut check = AbiBindgen { - abi: wasm.instrs.iter(), - err: None, - contents, - }; - func.call_wasm(&module.name, &mut check); - check.check()?; - check.abi = interface.instrs.iter(); - func.call_interface(&module.name, &mut check); - check.check()?; - } - } - Ok(()) - } - - fn assert_roundtrip(&self, doc: &witx::Document) -> Result<()> { - self.bump_ntests(); - let back_to_sexprs = format!("{}", doc); - let doc2 = witx::parse(&back_to_sexprs)?; - if *doc == doc2 { - return Ok(()); - } - - // Try to get a more specific error message that isn't thousands of - // lines long of debug representations. - for type_ in doc.typenames() { - let type2 = match doc2.typename(&type_.name) { - Some(t) => t, - None => bail!("doc2 missing datatype"), - }; - if type_ != type2 { - bail!("types are not equal\n{:?}\n !=\n{:?}", type_, type2); - } - } - for mod_ in doc.modules() { - let mod2 = match doc2.module(&mod_.name) { - Some(m) => m, - None => bail!("doc2 missing module"), - }; - for import in mod_.imports() { - let import2 = match mod2.import(&import.name) { - Some(i) => i, - None => bail!("mod2 missing import"), - }; - assert_eq!(import, import2); - } - for func in mod_.funcs() { - let func2 = match mod2.func(&func.name) { - Some(f) => f, - None => bail!("mod2 missing func"), - }; - assert_eq!(func, func2); - } - } - bail!("{:?} != {:?}", doc, doc2) - } - - fn assert_md(&self, doc: &witx::Document) -> Result<()> { - self.bump_ntests(); - doc.to_md(); - Ok(()) - } - - fn bump_ntests(&self) { - self.ntests.fetch_add(1, SeqCst); - } -} - -struct AbiBindgen<'a> { - abi: std::slice::Iter<'a, (wast::Span, &'a str)>, - err: Option, - contents: &'a str, -} - -impl AbiBindgen<'_> { - fn check(&mut self) -> Result<()> { - match self.err.take() { - None => Ok(()), - Some(e) => Err(e), - } - } - - fn assert(&mut self, name: &str) { - if self.err.is_some() { - return; - } - match self.abi.next() { - Some((_, s)) if *s == name => {} - Some((span, s)) => { - let (line, col) = span.linecol_in(self.contents); - self.err = Some(anyhow!( - "line {}:{} - expected `{}` found `{}`", - line + 1, - col + 1, - name, - s, - )); - } - None => { - self.err = Some(anyhow!( - "extra instruction `{}` found when none was expected", - name - )); - } - } - } -} - -impl witx::Bindgen for AbiBindgen<'_> { - type Operand = (); - fn emit( - &mut self, - inst: &Instruction<'_>, - _operands: &mut Vec, - results: &mut Vec, - ) { - use witx::Instruction::*; - match inst { - GetArg { nth } => self.assert(&format!("get-arg{}", nth)), - AddrOf => self.assert("addr-of"), - I32FromChar => self.assert("i32.from_char"), - I64FromU64 => self.assert("i64.from_u64"), - I64FromS64 => self.assert("i64.from_s64"), - I32FromU32 => self.assert("i32.from_u32"), - I32FromS32 => self.assert("i32.from_s32"), - I32FromUsize => self.assert("i32.from_usize"), - I32FromU16 => self.assert("i32.from_u16"), - I32FromS16 => self.assert("i32.from_s16"), - I32FromU8 => self.assert("i32.from_u8"), - I32FromS8 => self.assert("i32.from_s8"), - I32FromChar8 => self.assert("i32.from_char8"), - I32FromPointer => self.assert("i32.from_pointer"), - I32FromConstPointer => self.assert("i32.from_const_pointer"), - I32FromHandle { .. } => self.assert("i32.from_handle"), - ListPointerLength => self.assert("list.pointer_length"), - ListFromPointerLength { .. } => self.assert("list.from_pointer_length"), - F32FromIf32 => self.assert("f32.from_if32"), - F64FromIf64 => self.assert("f64.from_if64"), - CallWasm { .. } => self.assert("call.wasm"), - CallInterface { .. } => self.assert("call.interface"), - S8FromI32 => self.assert("s8.from_i32"), - U8FromI32 => self.assert("u8.from_i32"), - S16FromI32 => self.assert("s16.from_i32"), - U16FromI32 => self.assert("u16.from_i32"), - S32FromI32 => self.assert("s32.from_i32"), - U32FromI32 => self.assert("u32.from_i32"), - S64FromI64 => self.assert("s64.from_i64"), - U64FromI64 => self.assert("u64.from_i64"), - CharFromI32 => self.assert("char.from_i32"), - Char8FromI32 => self.assert("char8.from_i32"), - UsizeFromI32 => self.assert("usize.from_i32"), - If32FromF32 => self.assert("if32.from_f32"), - If64FromF64 => self.assert("if64.from_f64"), - HandleFromI32 { .. } => self.assert("handle.from_i32"), - PointerFromI32 { .. } => self.assert("pointer.from_i32"), - ConstPointerFromI32 { .. } => self.assert("const_pointer.from_i32"), - ReturnPointerGet { n } => self.assert(&format!("return_pointer.get{}", n)), - ResultLift => self.assert("result.lift"), - ResultLower { .. } => self.assert("result.lower"), - EnumLift { .. } => self.assert("enum.lift"), - EnumLower { .. } => self.assert("enum.lower"), - TupleLift { .. } => self.assert("tuple.lift"), - TupleLower { .. } => self.assert("tuple.lower"), - ReuseReturn => self.assert("reuse_return"), - Load { .. } => self.assert("load"), - Store { .. } => self.assert("store"), - Return { .. } => self.assert("return"), - VariantPayload => self.assert("variant-payload"), - I32FromBitflags { .. } => self.assert("i32.from_bitflags"), - BitflagsFromI32 { .. } => self.assert("bitflags.from_i32"), - I64FromBitflags { .. } => self.assert("i64.from_bitflags"), - BitflagsFromI64 { .. } => self.assert("bitflags.from_i64"), - } - for _ in 0..inst.results_len() { - results.push(()); - } - } - - fn allocate_space(&mut self, _: usize, _: &witx::NamedType) { - self.assert("allocate-space"); - } - - fn push_block(&mut self) { - self.assert("block.push"); - } - - fn finish_block(&mut self, _operand: Option) { - self.assert("block.finish"); - } -} - -mod kw { - wast::custom_keyword!(assert_invalid); - wast::custom_keyword!(assert_representable); - wast::custom_keyword!(assert_abi); - wast::custom_keyword!(witx); - wast::custom_keyword!(eq); - wast::custom_keyword!(noteq); - wast::custom_keyword!(load); - wast::custom_keyword!(superset); - wast::custom_keyword!(call_wasm); - wast::custom_keyword!(call_interface); - wast::custom_keyword!(param); - wast::custom_keyword!(result); - wast::custom_keyword!(wasm); - wast::custom_keyword!(i32); - wast::custom_keyword!(i64); - wast::custom_keyword!(f32); - wast::custom_keyword!(f64); -} - -struct Witxt<'a> { - directives: Vec>, -} - -impl<'a> Parse<'a> for Witxt<'a> { - fn parse(parser: Parser<'a>) -> parser::Result { - let mut directives = Vec::new(); - while !parser.is_empty() { - directives.push(parser.parens(|p| p.parse())?); - } - Ok(Witxt { directives }) - } -} - -enum WitxtDirective<'a> { - Witx(Witx<'a>), - AssertInvalid { - span: wast::Span, - witx: Witx<'a>, - message: &'a str, - }, - AssertRepresentable { - span: wast::Span, - repr: RepEquality, - t1: (wast::Id<'a>, &'a str), - t2: (wast::Id<'a>, &'a str), - }, - AssertAbi { - span: wast::Span, - witx: Witx<'a>, - wasm_signature: (Vec, Vec), - wasm: Abi<'a>, - interface: Abi<'a>, - }, -} - -impl WitxtDirective<'_> { - fn span(&self) -> wast::Span { - match self { - WitxtDirective::Witx(w) => w.span, - WitxtDirective::AssertInvalid { span, .. } - | WitxtDirective::AssertAbi { span, .. } - | WitxtDirective::AssertRepresentable { span, .. } => *span, - } - } -} - -impl<'a> Parse<'a> for WitxtDirective<'a> { - fn parse(parser: Parser<'a>) -> parser::Result { - let mut l = parser.lookahead1(); - if l.peek::() { - Ok(WitxtDirective::Witx(parser.parse()?)) - } else if l.peek::() { - let span = parser.parse::()?.0; - Ok(WitxtDirective::AssertInvalid { - span, - witx: parser.parens(|p| p.parse())?, - message: parser.parse()?, - }) - } else if l.peek::() { - let span = parser.parse::()?.0; - Ok(WitxtDirective::AssertRepresentable { - span, - repr: parser.parse()?, - t1: (parser.parse()?, parser.parse()?), - t2: (parser.parse()?, parser.parse()?), - }) - } else if l.peek::() { - let span = parser.parse::()?.0; - Ok(WitxtDirective::AssertAbi { - span, - witx: parser.parens(|p| p.parse())?, - wasm_signature: parser.parens(|p| { - p.parse::()?; - let mut params = Vec::new(); - let mut results = Vec::new(); - if p.peek2::() { - p.parens(|p| { - p.parse::()?; - while !p.is_empty() { - params.push(parse_wasmtype(p)?); - } - Ok(()) - })?; - } - if p.peek2::() { - p.parens(|p| { - p.parse::()?; - while !p.is_empty() { - results.push(parse_wasmtype(p)?); - } - Ok(()) - })?; - } - Ok((params, results)) - })?, - wasm: parser.parens(|p| { - p.parse::()?; - p.parse() - })?, - interface: parser.parens(|p| { - p.parse::()?; - p.parse() - })?, - }) - } else { - Err(l.error()) - } - } -} - -fn parse_wasmtype(p: Parser<'_>) -> parser::Result { - let mut l = p.lookahead1(); - if l.peek::() { - p.parse::()?; - Ok(WasmType::I32) - } else if l.peek::() { - p.parse::()?; - Ok(WasmType::I64) - } else if l.peek::() { - p.parse::()?; - Ok(WasmType::F32) - } else if l.peek::() { - p.parse::()?; - Ok(WasmType::F64) - } else { - Err(l.error()) - } -} - -struct Witx<'a> { - span: wast::Span, - id: Option>, - def: WitxDef<'a>, -} - -enum WitxDef<'a> { - Fs(Vec<&'a str>), - Inline(Vec>>), -} - -impl Witx<'_> { - fn document(&self, contents: &str, file: &Path) -> Result { - match &self.def { - WitxDef::Inline(decls) => { - let mut validator = witx::DocValidation::new(); - let mut definitions = Vec::new(); - for decl in decls { - validator - .scope(contents, file) - .validate_decl(&decl.item, &decl.comments, &mut definitions) - .map_err(witx::WitxError::Validation)?; - } - Ok(validator.into_document(definitions)) - } - WitxDef::Fs(paths) => { - let parent = file.parent().unwrap(); - let paths = paths.iter().map(|p| parent.join(p)).collect::>(); - Ok(witx::load(&paths)?) - } - } - } -} - -impl<'a> Parse<'a> for Witx<'a> { - fn parse(parser: Parser<'a>) -> parser::Result { - let span = parser.parse::()?.0; - let id = parser.parse()?; - - let def = if parser.peek2::() { - parser.parens(|p| { - p.parse::()?; - let mut paths = Vec::new(); - while !p.is_empty() { - paths.push(p.parse()?); - } - Ok(WitxDef::Fs(paths)) - })? - } else { - let mut decls = Vec::new(); - while !parser.is_empty() { - decls.push(parser.parens(|p| p.parse())?); - } - WitxDef::Inline(decls) - }; - Ok(Witx { id, span, def }) - } -} - -#[derive(Debug)] -enum RepEquality { - Eq, - NotEq, - Superset, -} - -impl<'a> Parse<'a> for RepEquality { - fn parse(parser: Parser<'a>) -> parser::Result { - let mut l = parser.lookahead1(); - if l.peek::() { - parser.parse::()?; - Ok(RepEquality::Eq) - } else if l.peek::() { - parser.parse::()?; - Ok(RepEquality::NotEq) - } else if l.peek::() { - parser.parse::()?; - Ok(RepEquality::Superset) - } else { - Err(l.error()) - } - } -} - -struct Abi<'a> { - instrs: Vec<(wast::Span, &'a str)>, -} - -impl<'a> Parse<'a> for Abi<'a> { - fn parse(parser: Parser<'a>) -> parser::Result { - let mut instrs = Vec::new(); - while !parser.is_empty() { - instrs.push(parser.step(|cursor| { - let (kw, next) = cursor - .keyword() - .ok_or_else(|| cursor.error("expected keyword"))?; - Ok(((cursor.cur_span(), kw), next)) - })?); - } - Ok(Abi { instrs }) - } -} diff --git a/legacy/tools/witx/tests/witxt/abi.witxt b/legacy/tools/witx/tests/witxt/abi.witxt deleted file mode 100644 index ccdad7bf4..000000000 --- a/legacy/tools/witx/tests/witxt/abi.witxt +++ /dev/null @@ -1,490 +0,0 @@ -(assert_abi - (witx (module $x (@interface func (export "f")))) - (wasm) - (call_wasm call.wasm return) - (call_interface call.interface return) -) - -;; scalar arguments -(assert_abi - (witx (module $x (@interface func (export "f") (param $p u8)))) - (wasm (param i32)) - (call_wasm get-arg0 i32.from_u8 call.wasm return) - (call_interface get-arg0 u8.from_i32 call.interface return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (param $p s8)))) - (wasm (param i32)) - (call_wasm get-arg0 i32.from_s8 call.wasm return) - (call_interface get-arg0 s8.from_i32 call.interface return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (param $p u16)))) - (wasm (param i32)) - (call_wasm get-arg0 i32.from_u16 call.wasm return) - (call_interface get-arg0 u16.from_i32 call.interface return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (param $p s16)))) - (wasm (param i32)) - (call_wasm get-arg0 i32.from_s16 call.wasm return) - (call_interface get-arg0 s16.from_i32 call.interface return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (param $p u32)))) - (wasm (param i32)) - (call_wasm get-arg0 i32.from_u32 call.wasm return) - (call_interface get-arg0 u32.from_i32 call.interface return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (param $p s32)))) - (wasm (param i32)) - (call_wasm get-arg0 i32.from_s32 call.wasm return) - (call_interface get-arg0 s32.from_i32 call.interface return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (param $p u64)))) - (wasm (param i64)) - (call_wasm get-arg0 i64.from_u64 call.wasm return) - (call_interface get-arg0 u64.from_i64 call.interface return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (param $p s64)))) - (wasm (param i64)) - (call_wasm get-arg0 i64.from_s64 call.wasm return) - (call_interface get-arg0 s64.from_i64 call.interface return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (param $p f32)))) - (wasm (param f32)) - (call_wasm get-arg0 f32.from_if32 call.wasm return) - (call_interface get-arg0 if32.from_f32 call.interface return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (param $p f64)))) - (wasm (param f64)) - (call_wasm get-arg0 f64.from_if64 call.wasm return) - (call_interface get-arg0 if64.from_f64 call.interface return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (param $p (@witx usize))))) - (wasm (param i32)) - (call_wasm get-arg0 i32.from_usize call.wasm return) - (call_interface get-arg0 usize.from_i32 call.interface return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (param $p (@witx char8))))) - (wasm (param i32)) - (call_wasm get-arg0 i32.from_char8 call.wasm return) - (call_interface get-arg0 char8.from_i32 call.interface return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (param $p char)))) - (wasm (param i32)) - (call_wasm get-arg0 i32.from_char call.wasm return) - (call_interface get-arg0 char.from_i32 call.interface return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (param $p (@witx pointer u8))))) - (wasm (param i32)) - (call_wasm get-arg0 i32.from_pointer call.wasm return) - (call_interface get-arg0 pointer.from_i32 call.interface return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (param $p (@witx const_pointer u8))))) - (wasm (param i32)) - (call_wasm get-arg0 i32.from_const_pointer call.wasm return) - (call_interface get-arg0 const_pointer.from_i32 call.interface return) -) - -;; flags parameter -(assert_abi - (witx - (typename $a (flags $x $y)) - (module $x (@interface func (export "f") (param $p $a))) - ) - (wasm (param i32)) - (call_wasm get-arg0 i32.from_bitflags call.wasm return) - (call_interface get-arg0 bitflags.from_i32 call.interface return) -) -(assert_abi - (witx - (typename $a (flags (@witx repr u64) $x $y)) - (module $x (@interface func (export "f") (param $p $a))) - ) - (wasm (param i64)) - (call_wasm get-arg0 i64.from_bitflags call.wasm return) - (call_interface get-arg0 bitflags.from_i64 call.interface return) -) - -;; struct parameter -(assert_abi - (witx - (typename $a (record (field $x u8))) - (module $x (@interface func (export "f") (param $p $a))) - ) - (wasm (param i32)) - (call_wasm get-arg0 addr-of call.wasm return) - (call_interface get-arg0 load call.interface return) -) - -;; handle parameter -(assert_abi - (witx - (typename $a (handle)) - (module $x (@interface func (export "f") (param $p $a))) - ) - (wasm (param i32)) - (call_wasm get-arg0 i32.from_handle call.wasm return) - (call_interface get-arg0 handle.from_i32 call.interface return) -) - -;; list parameter -(assert_abi - (witx - (module $x (@interface func (export "f") (param $p (list u8)))) - ) - (wasm (param i32 i32)) - (call_wasm get-arg0 list.pointer_length call.wasm return) - (call_interface get-arg0 get-arg1 list.from_pointer_length call.interface return) -) - -;; variant parameter -- some not allowed at this time -(assert_abi - (witx - (typename $a (enum $b)) - (module $x (@interface func (export "f") (param $p $a))) - ) - (wasm (param i32)) - (call_wasm get-arg0 enum.lower call.wasm return) - (call_interface get-arg0 enum.lift call.interface return) -) -(assert_abi - (witx - (typename $a (union f32)) - (module $x (@interface func (export "f") (param $p $a))) - ) - (wasm (param i32)) - (call_wasm get-arg0 addr-of call.wasm return) - (call_interface get-arg0 load call.interface return) -) - -;; scalar returns -(assert_abi - (witx (module $x (@interface func (export "f") (result $p u8)))) - (wasm (result i32)) - (call_wasm call.wasm u8.from_i32 return) - (call_interface call.interface i32.from_u8 return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (result $p s8)))) - (wasm (result i32)) - (call_wasm call.wasm s8.from_i32 return) - (call_interface call.interface i32.from_s8 return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (result $p u16)))) - (wasm (result i32)) - (call_wasm call.wasm u16.from_i32 return) - (call_interface call.interface i32.from_u16 return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (result $p s16)))) - (wasm (result i32)) - (call_wasm call.wasm s16.from_i32 return) - (call_interface call.interface i32.from_s16 return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (result $p u32)))) - (wasm (result i32)) - (call_wasm call.wasm u32.from_i32 return) - (call_interface call.interface i32.from_u32 return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (result $p s32)))) - (wasm (result i32)) - (call_wasm call.wasm s32.from_i32 return) - (call_interface call.interface i32.from_s32 return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (result $p u64)))) - (wasm (result i64)) - (call_wasm call.wasm u64.from_i64 return) - (call_interface call.interface i64.from_u64 return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (result $p s64)))) - (wasm (result i64)) - (call_wasm call.wasm s64.from_i64 return) - (call_interface call.interface i64.from_s64 return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (result $p f32)))) - (wasm (result f32)) - (call_wasm call.wasm if32.from_f32 return) - (call_interface call.interface f32.from_if32 return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (result $p f64)))) - (wasm (result f64)) - (call_wasm call.wasm if64.from_f64 return) - (call_interface call.interface f64.from_if64 return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (result $p (@witx usize))))) - (wasm (result i32)) - (call_wasm call.wasm usize.from_i32 return) - (call_interface call.interface i32.from_usize return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (result $p (@witx char8))))) - (wasm (result i32)) - (call_wasm call.wasm char8.from_i32 return) - (call_interface call.interface i32.from_char8 return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (result $p char)))) - (wasm (result i32)) - (call_wasm call.wasm char.from_i32 return) - (call_interface call.interface i32.from_char return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (result $p (@witx pointer u8))))) - (wasm (result i32)) - (call_wasm call.wasm pointer.from_i32 return) - (call_interface call.interface i32.from_pointer return) -) -(assert_abi - (witx (module $x (@interface func (export "f") (result $p (@witx const_pointer u8))))) - (wasm (result i32)) - (call_wasm call.wasm const_pointer.from_i32 return) - (call_interface call.interface i32.from_const_pointer return) -) - -;; flags return -(assert_abi - (witx - (typename $a (flags $x $y)) - (module $x (@interface func (export "f") (result $p $a))) - ) - (wasm (result i32)) - (call_wasm call.wasm bitflags.from_i32 return) - (call_interface call.interface i32.from_bitflags return) -) -(assert_abi - (witx - (typename $a (flags (@witx repr u64) $x $y)) - (module $x (@interface func (export "f") (result $p $a))) - ) - (wasm (result i64)) - (call_wasm call.wasm bitflags.from_i64 return) - (call_interface call.interface i64.from_bitflags return) -) - -;; handle return -(assert_abi - (witx - (typename $a (handle)) - (module $x (@interface func (export "f") (result $p $a))) - ) - (wasm (result i32)) - (call_wasm call.wasm handle.from_i32 return) - (call_interface call.interface i32.from_handle return) -) - -;; struct return -- not supported -(assert_invalid - (witx - (typename $a (record (field $x u8))) - (module $x (@interface func (export "f") (result $p $a))) - ) - "ABI error: invalid return type" -) - -;; list return -- not supported -(assert_invalid - (witx - (module $x (@interface func (export "f") (result $p (list u8)))) - ) - "ABI error: invalid return type" -) - -;; variant return -- only some allowed -(assert_invalid - (witx - (typename $a (enum $b)) - (module $x (@interface func (export "f") (result $p $a))) - ) - "ABI error: invalid return type" -) -(assert_invalid - (witx - (typename $a (union s32 f32)) - (module $x (@interface func (export "f") (result $p $a))) - ) - "ABI error: invalid return type" -) -(assert_invalid - (witx - (typename $a (expected (error f32))) - (module $x (@interface func (export "f") (result $p $a))) - ) - "ABI error: only named types are allowed in results" -) -(assert_invalid - (witx - (typename $errno (enum $success $bad)) - (typename $a (expected f32 (error $errno))) - (module $x (@interface func (export "f") (result $p $a))) - ) - "ABI error: only named types are allowed in results" -) - -;; Result<(), $errno> -(assert_abi - (witx - (typename $errno (enum $success $bad)) - (typename $a (expected (error $errno))) - (module $x (@interface func (export "f") (result $p $a))) - ) - (wasm (result i32)) - - (call_wasm - call.wasm - ;; ok block, nothing happens - block.push - block.finish - ;; err block, we lift the return value as the num - block.push - reuse_return - enum.lift - block.finish - ;; consumes 2 blocks and uses the return value of the call to discriminate - result.lift - return) - - (call_interface - call.interface - - ;; ok block, nothing happens - block.push - block.finish - - ;; err block, lift the enum - block.push - variant-payload - enum.lower - block.finish - - ;; consume the 2 blocks and lower based on the call - result.lower - return) -) - -;; Result<$ty, $errno> -(assert_abi - (witx - (typename $errno (enum $success $bad)) - (typename $size u32) - (typename $a (expected $size (error $errno))) - (module $x (@interface func (export "f") (result $p $a))) - ) - (wasm (param i32) (result i32)) - - (call_wasm - ;; make space for the return value and push its pointer - allocate-space - return_pointer.get0 - - call.wasm - - ;; ok block, load the return pointer and have it be the result for the `Ok` - block.push - return_pointer.get0 - load - block.finish - - block.push - reuse_return - enum.lift - block.finish - - result.lift - return) - - (call_interface - call.interface - - ;; store the successful result at the first return pointer (the first param) - block.push - variant-payload - get-arg0 - store - block.finish - - block.push - variant-payload - enum.lower - block.finish - - result.lower - return) -) - -;; Result<($a, $b), $errno> -(assert_abi - (witx - (typename $errno (enum $success $bad)) - (typename $size u32) - (typename $other (record (field $a $size))) - (module $x (@interface func (export "f") - (result $p (expected (tuple $size $other) (error $errno))))) - ) - (wasm (param i32 i32) (result i32)) - - (call_wasm - allocate-space - return_pointer.get0 - allocate-space - return_pointer.get1 - - call.wasm - - block.push - return_pointer.get0 - load - return_pointer.get1 - load - tuple.lift - block.finish - - block.push - reuse_return - enum.lift - block.finish - - result.lift - return) - - (call_interface - call.interface - - ;; note the reverse order since we're consuming the results of lowering the - ;; tuple - block.push - variant-payload - tuple.lower - get-arg1 - store - get-arg0 - store - block.finish - - block.push - variant-payload - enum.lower - block.finish - - result.lower - return) -) diff --git a/legacy/tools/witx/tests/witxt/anonymous.witxt b/legacy/tools/witx/tests/witxt/anonymous.witxt deleted file mode 100644 index 0ed3bc0d2..000000000 --- a/legacy/tools/witx/tests/witxt/anonymous.witxt +++ /dev/null @@ -1,56 +0,0 @@ -;; Ensure that anonymous structured types are not allowed in type positions at -;; this time, everything has to be named to assist in binding in languages. - -(assert_invalid - (witx - (typename $a (@witx pointer (record (field $b u8)))) - ) - "Anonymous structured types") - -(assert_invalid - (witx - (typename $a (@witx pointer (union))) - ) - "Anonymous structured types") - -(assert_invalid - (witx - (typename $a (@witx pointer (enum $b))) - ) - "Anonymous structured types") - -(assert_invalid - (witx - (typename $a (@witx pointer (flags $b))) - ) - "Anonymous structured types") - -(assert_invalid - (witx - (typename $a (@witx pointer (handle))) - ) - "Anonymous structured types") - -(assert_invalid - (witx - (typename $a (record (field $b (record (field $c u8))))) - ) - "Anonymous structured types") - -(assert_invalid - (witx - (typename $tag (enum $c)) - (typename $a (record (field $b (union)))) - ) - "Anonymous structured types") - - -;; pointers don't count for anonymous indirections -(witx - (typename $a (@witx pointer u8))) - -(witx - (typename $a (@witx pointer (@witx const_pointer u8)))) - -(witx - (typename $a (record (field $b (@witx pointer u8))))) diff --git a/legacy/tools/witx/tests/witxt/multimodule.witxt b/legacy/tools/witx/tests/witxt/multimodule.witxt deleted file mode 100644 index d8b6559ac..000000000 --- a/legacy/tools/witx/tests/witxt/multimodule.witxt +++ /dev/null @@ -1,22 +0,0 @@ -;; B uses A, and C uses A. -(witx $multi - (load "multimodule/type_b.witx" "multimodule/type_c.witx") -) - -(witx $reference - (typename $a u32) - (typename $b (record (field $member_a $a))) - (typename $c (record (field $first_a $a) (field $second_a $a))) -) - -(assert_representable eq $reference "a" $multi "a") -(assert_representable eq $reference "b" $multi "b") -(assert_representable eq $reference "c" $multi "c") - -(assert_invalid - (witx - (load - "multimodule/type_a.witx" - "multimodule/redefine_a.witx") - ) - "Redefinition of name `a`") diff --git a/legacy/tools/witx/tests/witxt/multimodule/redefine_a.witx b/legacy/tools/witx/tests/witxt/multimodule/redefine_a.witx deleted file mode 100644 index e5d99d82c..000000000 --- a/legacy/tools/witx/tests/witxt/multimodule/redefine_a.witx +++ /dev/null @@ -1 +0,0 @@ -(typename $a u8) diff --git a/legacy/tools/witx/tests/witxt/multimodule/type_a.witx b/legacy/tools/witx/tests/witxt/multimodule/type_a.witx deleted file mode 100644 index 5499ff3db..000000000 --- a/legacy/tools/witx/tests/witxt/multimodule/type_a.witx +++ /dev/null @@ -1 +0,0 @@ -(typename $a u32) diff --git a/legacy/tools/witx/tests/witxt/multimodule/type_b.witx b/legacy/tools/witx/tests/witxt/multimodule/type_b.witx deleted file mode 100644 index fe169d3ec..000000000 --- a/legacy/tools/witx/tests/witxt/multimodule/type_b.witx +++ /dev/null @@ -1,2 +0,0 @@ -(use "type_a.witx") -(typename $b (record (field $member_a $a))) diff --git a/legacy/tools/witx/tests/witxt/multimodule/type_c.witx b/legacy/tools/witx/tests/witxt/multimodule/type_c.witx deleted file mode 100644 index f42aac2d0..000000000 --- a/legacy/tools/witx/tests/witxt/multimodule/type_c.witx +++ /dev/null @@ -1,2 +0,0 @@ -(use "type_a.witx") -(typename $c (record (field $first_a $a) (field $second_a $a))) diff --git a/legacy/tools/witx/tests/witxt/representation.witxt b/legacy/tools/witx/tests/witxt/representation.witxt deleted file mode 100644 index 53f71f196..000000000 --- a/legacy/tools/witx/tests/witxt/representation.witxt +++ /dev/null @@ -1,60 +0,0 @@ -;; type names don't matter -(witx $a - (typename $a (flags (@witx repr u8) $b $c))) -(witx $b - (typename $b (flags (@witx repr u8) $b $c))) - -(assert_representable eq $a "a" $b "b") -(assert_representable eq $b "b" $a "a") - -(; TODO: perhaps add assertions eventually for document-level representability? -;; flags -(witx $a - (typename $a (flags (@witx bitflags u8) $b $c))) -(witx $b - (typename $b (flags (@witx bitflags u8) $b $c $d))) - -(assert_representable noteq $b "b" $a "a") -(assert_representable superset $a "a" $b "b") - -(witx $c - (typename $c (flags (@witx bitflags u8) $b $e))) -(assert_representable noteq $a "a" $c "c") -(assert_representable noteq $c "c" $a "a") - -(witx $d - (typename $d (flags (@witx bitflags u16) $b $c))) -(assert_representable noteq $a "a" $d "d") -(assert_representable superset $d "d" $a "a") -(assert_representable superset $d "d" $b "b") -;) - -;; enums -(witx $a - (typename $a (enum $b $c))) -(witx $b - (typename $b (enum $b $c $d))) -(assert_representable superset $a "a" $b "b") -(assert_representable noteq $b "b" $a "a") - -(witx $c - (typename $c (enum (@witx tag u16) $b $c))) -(assert_representable superset $c "c" $a "a") -(assert_representable superset $c "c" $b "b") - -;; unions -(witx $a - (typename $tag (enum $b $c)) - (typename $a (union (@witx tag $tag) u32 f32))) -(witx $b - (typename $tag (enum $b $c $d)) - (typename $b (union (@witx tag $tag) u32 f32 f64))) -(assert_representable superset $a "a" $b "b") -(assert_representable noteq $b "b" $a "a") - -(witx $c - (typename $tag (enum $b $c)) - (typename $c (variant (@witx tag $tag) (case $c f32) (case $b u32)))) -(assert_representable eq $a "a" $c "c") -(assert_representable eq $c "c" $a "a") -(assert_representable superset $c "c" $b "b") diff --git a/legacy/tools/witx/tests/witxt/shorthand.witxt b/legacy/tools/witx/tests/witxt/shorthand.witxt deleted file mode 100644 index 960615f3c..000000000 --- a/legacy/tools/witx/tests/witxt/shorthand.witxt +++ /dev/null @@ -1,59 +0,0 @@ -(witx $a - (typename $a bool)) -(witx $b - (typename $a (variant (case $false) (case $true)))) -(assert_representable eq $a "a" $b "a") - -(witx $a - (typename $a (expected (error)))) -(witx $b - (typename $a (variant (case $ok) (case $err)))) -(assert_representable eq $a "a" $b "a") - -(witx $a - (typename $a (expected (error u32)))) -(witx $b - (typename $a (variant (case $ok) (case $err u32)))) -(assert_representable eq $a "a" $b "a") - -(witx $a - (typename $a (expected u32 (error)))) -(witx $b - (typename $a (variant (case $ok u32) (case $err)))) -(assert_representable eq $a "a" $b "a") - -(witx $a - (typename $a (expected u32 (error u64)))) -(witx $b - (typename $a (variant (case $ok u32) (case $err u64)))) -(assert_representable eq $a "a" $b "a") - -(witx $a - (typename $a (flags $a $b))) -(witx $b - (typename $a (record (field $a bool) (field $b bool)))) -(assert_representable eq $a "a" $b "a") - -(witx $a - (typename $a (enum $a $b))) -(witx $b - (typename $a (variant (case $a) (case $b)))) -(assert_representable eq $a "a" $b "a") - -(witx $a - (typename $a string)) -(witx $b - (typename $a (list char))) -(assert_representable eq $a "a" $b "a") - -(witx $a - (typename $a (tuple u32 u64))) -(witx $b - (typename $a (record (field $0 u32) (field $1 u64)))) -(assert_representable eq $a "a" $b "a") - -(witx $a - (typename $a (union u32 u64))) -(witx $b - (typename $a (variant (case $0 u32) (case $1 u64)))) -(assert_representable eq $a "a" $b "a") diff --git a/legacy/tools/witx/tests/witxt/simple.witxt b/legacy/tools/witx/tests/witxt/simple.witxt deleted file mode 100644 index af2403043..000000000 --- a/legacy/tools/witx/tests/witxt/simple.witxt +++ /dev/null @@ -1,12 +0,0 @@ -(witx) - -(witx - (typename $x u32) -) - -(assert_invalid - (witx - (typename $x u32) - (typename $x u32) - ) - "Redefinition of name `x`") diff --git a/legacy/tools/witx/tests/witxt/union.witxt b/legacy/tools/witx/tests/witxt/union.witxt deleted file mode 100644 index 92be3dcd9..000000000 --- a/legacy/tools/witx/tests/witxt/union.witxt +++ /dev/null @@ -1,97 +0,0 @@ - -(witx - (typename $u (union u8)) -) -(witx - (typename $tag (enum (@witx tag u8) $c)) - (typename $u (union (@witx tag $tag) u8)) -) - -(witx - (typename $tag (enum $a $b)) - (typename $u (variant (@witx tag $tag) (case $a) (case $b u16))) -) - -(witx - (typename $tag (enum $a $b)) - (typename $u (variant (@witx tag $tag) (case $a) (case $b))) -) - - -(witx - (typename $u - (union - u8 - u16 - u32 - u64 - s8 - s16 - s32 - s64 - f32 - f64 - (@witx usize) - (@witx char8) - ) - ) -) - -(assert_invalid - (witx (typename $u (union (@witx tag $tag) u8 u16))) - "Unknown name `tag`" -) - -(assert_invalid - (witx - (typename $tag string) - (typename $u (union (@witx tag $tag) u8 u16)) - ) - "Wrong kind of name `tag`: expected enum or builtin, got list" -) - -(assert_invalid - (witx - (typename $tag (enum $c)) - (typename $u (variant (@witx tag $tag) (case $b u8))) - ) - "Invalid union field `b`: does not correspond to variant in tag `tag`" -) - -(assert_invalid - (witx - (typename $tag (enum $c)) - (typename $u (union (@witx tag $tag) f32 u8)) - ) - "Union expected 1 variants, found 2" -) - -(assert_invalid - (witx - (typename $tag (enum $c $d)) - (typename $u (union (@witx tag $tag) f32)) - ) - "Union expected 2 variants, found 1" -) - -(witx $d1 - (typename $tag (enum $a $b)) - (typename $u (union (@witx tag $tag) u8 u16)) -) - -(witx $d2 - (typename $tag (enum $a $b)) - (typename $u (variant (@witx tag $tag) (case $b u16) (case $a u8))) -) - -;; These two unions should be represented the same: -(assert_representable eq $d1 "u" $d2 "u") -(assert_representable eq $d2 "u" $d1 "u") - -;; Tag order doesnt matter for validation, but does for rep equality -(witx $d3 - (typename $tag (enum $b $a)) - (typename $u (union (@witx tag $tag) u16 u8)) -) - -(assert_representable noteq $d3 "u" $d1 "u") diff --git a/legacy/tools/witx/tests/witxt/wasi.witxt b/legacy/tools/witx/tests/witxt/wasi.witxt deleted file mode 100644 index f654a7ee3..000000000 --- a/legacy/tools/witx/tests/witxt/wasi.witxt +++ /dev/null @@ -1,26 +0,0 @@ -;; Ensure that all current witx definitions in this repository load, parse, -;; roundtrip, and are documentable. - -(witx - (load "../../../../phases/old/snapshot_0/witx/wasi_unstable.witx")) -(witx - (load "../../../../phases/snapshot/witx/wasi_snapshot_preview1.witx")) - -(witx - (load - "../../../../phases/ephemeral/witx/wasi_ephemeral_args.witx" - "../../../../phases/ephemeral/witx/wasi_ephemeral_clock.witx" - "../../../../phases/ephemeral/witx/wasi_ephemeral_environ.witx" - "../../../../phases/ephemeral/witx/wasi_ephemeral_fd.witx" - "../../../../phases/ephemeral/witx/wasi_ephemeral_path.witx" - "../../../../phases/ephemeral/witx/wasi_ephemeral_poll.witx" - "../../../../phases/ephemeral/witx/wasi_ephemeral_proc.witx" - "../../../../phases/ephemeral/witx/wasi_ephemeral_random.witx" - "../../../../phases/ephemeral/witx/wasi_ephemeral_sched.witx" - "../../../../phases/ephemeral/witx/wasi_ephemeral_sock.witx" - ) -) -;; should be singularly-loadable as well -(witx - (load - "../../../../phases/ephemeral/witx/wasi_ephemeral_fd.witx"))