// From: https://github.com/WebAssembly/wasi-io/tree/e6bcf18ac5e2d2deee5016fc4b6e260fc14d4bdc/wit 

default world example-world {
    import streams: self.streams
}

/// WASI I/O is an I/O abstraction API which is currently focused on providing
/// stream types.
///
/// In the future, the component model is expected to add built-in stream types;
/// when it does, they are expected to subsume this API.
default interface streams {
    use self.poll.{pollable}

    /// An error type returned from a stream operation. Currently this
    /// doesn't provide any additional information.
    record stream-error {}

    /// An input bytestream. In the future, this will be replaced by handle
    /// types.
    ///
    /// This conceptually represents a `stream<u8, _>`. It's temporary
    /// scaffolding until component-model's async features are ready.
    ///
    /// `input-stream`s are *non-blocking* to the extent practical on underlying
    /// platforms. I/O operations always return promptly; if fewer bytes are
    /// promptly available than requested, they return the number of bytes promptly
    /// available, which could even be zero. To wait for data to be available,
    /// use the `subscribe-to-input-stream` function to obtain a `pollable` which
    /// can be polled for using `wasi_poll`.
    ///
    /// And at present, it is a `u32` instead of being an actual handle, until
    /// the wit-bindgen implementation of handles and resources is ready.
    ///
    /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources).
    type input-stream = u32

    /// Read bytes from a stream.
    ///
    /// This function returns a list of bytes containing the data that was
    /// read, along with a bool which, when true, indicates that the end of the
    /// stream was reached. The returned list will contain up to `len` bytes; it
    /// may return fewer than requested, but not more.
    ///
    /// Once a stream has reached the end, subsequent calls to read or
    /// `skip` will always report end-of-stream rather than producing more
    /// data.
    ///
    /// If `len` is 0, it represents a request to read 0 bytes, which should
    /// always succeed, assuming the stream hasn't reached its end yet, and
    /// return an empty list.
    ///
    /// The len here is a `u64`, but some callees may not be able to allocate
    /// a buffer as large as that would imply.
    /// FIXME: describe what happens if allocation fails.
    read: func(
        this: input-stream,
        /// The maximum number of bytes to read
        len: u64
    ) -> result<tuple<list<u8>, bool>, stream-error>

    /// Read bytes from a stream, with blocking.
    ///
    /// This is similar to `read`, except that it blocks until at least one
    /// byte can be read.
    blocking-read: func(
        this: input-stream,
        /// The maximum number of bytes to read
        len: u64
    ) -> result<tuple<list<u8>, bool>, stream-error>

    /// Skip bytes from a stream.
    ///
    /// This is similar to the `read` function, but avoids copying the
    /// bytes into the instance.
    ///
    /// Once a stream has reached the end, subsequent calls to read or
    /// `skip` will always report end-of-stream rather than producing more
    /// data.
    ///
    /// This function returns the number of bytes skipped, along with a bool
    /// indicating whether the end of the stream was reached. The returned
    /// value will be at most `len`; it may be less.
    skip: func(
        this: input-stream,
        /// The maximum number of bytes to skip.
        len: u64,
    ) -> result<tuple<u64, bool>, stream-error>

    /// Skip bytes from a stream, with blocking.
    ///
    /// This is similar to `skip`, except that it blocks until at least one
    /// byte can be consumed.
    blocking-skip: func(
        this: input-stream,
        /// The maximum number of bytes to skip.
        len: u64,
    ) -> result<tuple<u64, bool>, stream-error>

    /// Create a `pollable` which will resolve once either the specified stream
    /// has bytes available to read or the other end of the stream has been
    /// closed.
    subscribe-to-input-stream: func(this: input-stream) -> pollable

    /// Dispose of the specified `input-stream`, after which it may no longer
    /// be used.
    drop-input-stream: func(this: input-stream)

    /// An output bytestream. In the future, this will be replaced by handle
    /// types.
    ///
    /// This conceptually represents a `stream<u8, _>`. It's temporary
    /// scaffolding until component-model's async features are ready.
    ///
    /// `output-stream`s are *non-blocking* to the extent practical on
    /// underlying platforms. Except where specified otherwise, I/O operations also
    /// always return promptly, after the number of bytes that can be written
    /// promptly, which could even be zero. To wait for the stream to be ready to
    /// accept data, the `subscribe-to-output-stream` function to obtain a
    /// `pollable` which can be polled for using `wasi_poll`.
    ///
    /// And at present, it is a `u32` instead of being an actual handle, until
    /// the wit-bindgen implementation of handles and resources is ready.
    ///
    /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources).
    type output-stream = u32

    /// Write bytes to a stream.
    ///
    /// This function returns a `u64` indicating the number of bytes from
    /// `buf` that were written; it may be less than the full list.
    write: func(
        this: output-stream,
        /// Data to write
        buf: list<u8>
    ) -> result<u64, stream-error>

    /// Write bytes to a stream, with blocking.
    ///
    /// This is similar to `write`, except that it blocks until at least one
    /// byte can be written.
    blocking-write: func(
        this: output-stream,
        /// Data to write
        buf: list<u8>
    ) -> result<u64, stream-error>

    /// Write multiple zero bytes to a stream.
    ///
    /// This function returns a `u64` indicating the number of zero bytes
    /// that were written; it may be less than `len`.
    write-zeroes: func(
        this: output-stream,
        /// The number of zero bytes to write
        len: u64
    ) -> result<u64, stream-error>

    /// Write multiple zero bytes to a stream, with blocking.
    ///
    /// This is similar to `write-zeroes`, except that it blocks until at least
    /// one byte can be written.
    blocking-write-zeroes: func(
        this: output-stream,
        /// The number of zero bytes to write
        len: u64
    ) -> result<u64, stream-error>

    /// Read from one stream and write to another.
    ///
    /// This function returns the number of bytes transferred; it may be less
    /// than `len`.
    ///
    /// Unlike other I/O functions, this function blocks until all the data
    /// read from the input stream has been written to the output stream.
    splice: func(
        this: output-stream,
        /// The stream to read from
        src: input-stream,
        /// The number of bytes to splice
        len: u64,
    ) -> result<tuple<u64, bool>, stream-error>

    /// Read from one stream and write to another, with blocking.
    ///
    /// This is similar to `splice`, except that it blocks until at least
    /// one byte can be read.
    blocking-splice: func(
        this: output-stream,
        /// The stream to read from
        src: input-stream,
        /// The number of bytes to splice
        len: u64,
    ) -> result<tuple<u64, bool>, stream-error>

    /// Forward the entire contents of an input stream to an output stream.
    ///
    /// This function repeatedly reads from the input stream and writes
    /// the data to the output stream, until the end of the input stream
    /// is reached, or an error is encountered.
    ///
    /// Unlike other I/O functions, this function blocks until the end
    /// of the input stream is seen and all the data has been written to
    /// the output stream.
    ///
    /// This function returns the number of bytes transferred.
    forward: func(
        this: output-stream,
        /// The stream to read from
        src: input-stream
    ) -> result<u64, stream-error>

    /// Create a `pollable` which will resolve once either the specified stream
    /// is ready to accept bytes or the other end of the stream has been closed.
    subscribe-to-output-stream: func(this: output-stream) -> pollable

    /// Dispose of the specified `output-stream`, after which it may no longer
    /// be used.
    drop-output-stream: func(this: output-stream)
}

/// A poll API intended to let users wait for I/O events on multiple handles
/// at once.
default interface poll {
    /// A "pollable" handle.
    ///
    /// This is conceptually represents a `stream<_, _>`, or in other words,
    /// a stream that one can wait on, repeatedly, but which does not itself
    /// produce any data. It's temporary scaffolding until component-model's
    /// async features are ready.
    ///
    /// And at present, it is a `u32` instead of being an actual handle, until
    /// the wit-bindgen implementation of handles and resources is ready.
    ///
    /// `pollable` lifetimes are not automatically managed. Users must ensure
    /// that they do not outlive the resource they reference.
    ///
    /// This [represents a resource](https://github.com/WebAssembly/WASI/blob/main/docs/WitInWasi.md#Resources).
    type pollable = u32

    /// Dispose of the specified `pollable`, after which it may no longer
    /// be used.
    drop-pollable: func(this: pollable)

    /// Poll for completion on a set of pollables.
    ///
    /// The "oneoff" in the name refers to the fact that this function must do a
    /// linear scan through the entire list of subscriptions, which may be
    /// inefficient if the number is large and the same subscriptions are used
    /// many times. In the future, this is expected to be obsoleted by the
    /// component model async proposal, which will include a scalable waiting
    /// facility.
    ///
    /// Note that the return type would ideally be `list<bool>`, but that would
    /// be more difficult to polyfill given the current state of `wit-bindgen`.
    /// See <https://github.com/bytecodealliance/preview2-prototyping/pull/11#issuecomment-1329873061>
    /// for details.  For now, we use zero to mean "not ready" and non-zero to
    /// mean "ready".
    poll-oneoff: func(in: list<pollable>) -> list<u8>
}
