From 647ae8fc7a2b82114aff8c88f5d30244c6d981f9 Mon Sep 17 00:00:00 2001 From: Lachlan O'Dea Date: Sun, 4 Feb 2024 19:47:47 +1100 Subject: [PATCH] Add docs and cleanup. --- README.md | 179 ++- build-windows.sh | 2 - build.sbt | 22 +- doc-root.txt | 9 + src/main/resources/scala-native/helpers.c | 10 + src/main/scala/scalauv/Buffer.scala | 127 +- src/main/scala/scalauv/Handle.scala | 119 +- src/main/scala/scalauv/IOVector.scala | 26 + src/main/scala/scalauv/LibUv.scala | 1452 +++++++++++++++++- src/main/scala/scalauv/Req.scala | 105 ++ src/main/scala/scalauv/UvUtils.scala | 97 +- src/main/scala/scalauv/errors.scala | 6 + src/main/scala/scalauv/helpers.scala | 4 + src/main/scala/{ => scalauv/main}/Main.scala | 38 +- src/test/scala/scalauv/TcpSpec.scala | 4 +- 15 files changed, 2105 insertions(+), 95 deletions(-) create mode 100644 doc-root.txt rename src/main/scala/{ => scalauv/main}/Main.scala (51%) diff --git a/README.md b/README.md index f46f3d1..9a490ae 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Scala Native bindings for libuv -> Handcrafted, artisanal Scala Native bindings for libuv. +> Artisanal, handcrafted Scala Native bindings for libuv. **scala-uv** is a Scala Native library that provides Scala bindings for [libuv](https://libuv.org), which is a multi-platform asynchronous IO library written in C. libuv was originally developed for Node.js, but it's also used by other software projects. @@ -9,7 +9,7 @@ Only Scala 3 is supported. ## Getting it ```scala -libraryDependencies += "io.github.quelgar" %%% "scala-uv" % "0.0.1" +libraryDependencies += "io.github.quelgar" %%% "scala-uv" % "0.0.2" ``` ## Current status @@ -31,9 +31,11 @@ But many details of the API are still in flux. Runs a callback once, then closes the handle: ```scala -import scala.scalanative.unsafe.* -import scala.scalanative.unsigned.* import scalauv.* + +import scala.scalanative.* +import unsafe.* +import unsigned.* import LibUv.* object Main { @@ -51,7 +53,7 @@ object Main { withZone { val loop = uv_default_loop() - val asyncHandle = UvUtils.zoneAllocateHandle(HandleType.UV_ASYNC) + val asyncHandle = AsyncHandle.zoneAllocate() uv_async_init(loop, asyncHandle, callback).checkErrorThrowIO() uv_async_send(asyncHandle).checkErrorThrowIO() @@ -60,7 +62,6 @@ object Main { uv_run(loop, RunMode.DEFAULT).checkErrorThrowIO() println(s"Main after, done = $done") } - } } @@ -73,9 +74,79 @@ See also the tests * [TcpSpec.scala](src/test/scala/scalauv/TcpSpec.scala) * [FileSpec.scala](src/test/scala/scalauv/FileSpec.scala) +## Differences from the C API + +scala-uv tries to expose the exact C API of libuv as directly as possible. However, due to the nature of Scala Native, some changes are necessary. + +### Functions + +Most of the libuv functions can be found in the `LibUv` object, with the same name as the C function. The exceptions are the following: + +* `uv_loop_configuration` — currently not supported +* `uv_fileno` — currently not supported +* `uv_poll_init_socket` — currently not supported +* Process handle functions — not yet supported +* `uv_socketpair` — not yet supported +* `uv_udp_open` — not yet supported +* `uv_fs_chown` — not yet supported +* `uv_fs_fchown` — not yet supported +* `uv_fs_lchown` — not yet supported +* `uv_fs_getosfhandle` — not yet supported +* `uv_open_osfhandle` — not yet supported + +### Handles + +The C handle type `uv_handle_t*` is represented by the `Handle` type in Scala. There are subtypes of `Handle` for each of the pseudo-subtypes of `uv_handle_t` in C, such as `AsyncHandle`, `TcpHandle`, etc. + +Each type of handle has a companion object with methods to allocate the memory for that type of handle, for example `AsyncHandle.zoneAllocate()`, `TcpHandle.stackAllocate()`, etc. + +The `HandleType` object has the handle type constants. + +### Requests + +Similarly, the C request type `uv_req_t*` is represented by the `Req` type in Scala. There are subtypes of `Req` for each of the pseudo-subtypes of `uv_req_t` in C, such as `WriteReq`, `ConnectReq`, etc. + +Each type of request has a companion object with methods to allocate the memory for that type of request, for example `WriteReq.zoneAllocate()`, `ConnectReq.stackAllocate()`, etc. + +The `ReqType` object has the request type constants. + +### Buffers + +The `Buffer` type is a Scala wrapper around the `uv_buf_t*` type in C. To allocate and initialize a new `Buffer` on the stack: + +```scala +val size = 100 +val base = stackAlloc[Byte](size) +val buffer = Buffer.stackAllocate(base, size) +``` + +### Error codes + +The `ErrorCodes` object has all the error codes from libuv as Scala constants, with the same names as in C. + +### Constants + +Various objects provide the constant values needed to use various aspectes of the libuv API: + +* `RunMode` +* `FileOpenFlags` +* `CreateMode` +* `AccessCheckMode` +* `PollEvent` +* `ProcessFlags` +* `StdioFlags` +* `TtyMode` +* `TtyVtermState` +* `UdpFlags` +* `Membership` +* `FsEvent` +* `FsType` +* `DirEntType` +* `ClockType` + ## Conveniences -The `LibUv` objects provides the exact libuv API, but when using it directly you are basically writing C code with Scala syntax. A few convenienves are provided to make this less painful. +The `LibUv` object provides most othe exact libuv API, but when using it directly you are basically writing C code with Scala syntax. A few convenienves are provided to make this a little less painful. ### Dealing with libuv failures @@ -83,20 +154,108 @@ libuv functions that can fail return a negative integer on failure, with the val Pass an error code to `UvUtils.errorMessage` to get the human-readable error message as a Scala string. +Use `.onFail` to run some cleanup if the function failed. + +```scala +uv_write(writeReq, stream, buf, 1.toUInt, onWrite).onFail { + stdlib.free(writeReq) +} +``` + Use `.checkErrorThrowIO()` on the result of a libuv function to throw an `IOException` if the function failed. Note this isn't useful inside a callback, since you definitely should *not* throw exceptions from a C callback. ```scala uv_listen(serverTcpHandle, 128, onNewConnection).checkErrorThrowIO() ``` -Use `.onFail` to run some cleanup if the function failed. +When using a callback-based library like libuv, it is common that when everything works, cleanup like freeing memory must be done in a different callback function. However if something fails, we need to immediately cleanup anything we've allocated already. We can use `.checkErrorThrowIO()` with `try`/`catch` to do this, but it's a little verbose as everything that might need to be cleaned up needs to be declared as a `var` outside the `try` block: ```scala -uv_write(writeReq, stream, buf, 1.toUInt, onWrite).onFail { - stdlib.free(writeReq) +def onNewConnection: ConnectionCallback = { + (handle: StreamHandle, status: ErrorCode) => + val loop = uv_handle_get_loop(handle) + var clientTcpHandle: TcpHandle = null + try { + status.checkErrorThrowIO() + clientTcpHandle = TcpHandle.malloc() + println("New connection") + uv_tcp_init(loop, clientTcpHandle).checkErrorThrowIO() + uv_handle_set_data(clientTcpHandle, handle.toPtr) + uv_accept(handle, clientTcpHandle).checkErrorThrowIO() + try { + uv_read_start(clientTcpHandle, allocBuffer, onRead) + .checkErrorThrowIO() + } catch { + case e: IOException => + uv_close(clientTcpHandle, onClose) + throw e + } + () + } catch { + case e: IOException => + if (clientTcpHandle != null) { + clientTcpHandle.free() + } + setFailed(exception.getMessage()) + } +} +``` + +As an alternative, scala-uv provides `UvUtils.attemptCatch` to make scenarios such as this easier. Within an `attemptCatch` block, you can register cleanup actions at any point using `UvUtils.onFail`. These cleanup actions will be performed (in reverse order to the order registered) if an exception is thrown. If the code block completes, no cleanup is performed. A function to handle the exception must also be provided. This simplifies the above example to: + + +```scala +def onNewConnection: ConnectionCallback = { + (handle: StreamHandle, status: ErrorCode) => + val loop = uv_handle_get_loop(handle) + UvUtils.attemptCatch { + status.checkErrorThrowIO() + val clientTcpHandle = TcpHandle.malloc() + UvUtils.onFail(clientTcpHandle.free()) + println("New connection") + uv_tcp_init(loop, clientTcpHandle).checkErrorThrowIO() + uv_handle_set_data(clientTcpHandle, handle.toPtr) + uv_accept(handle, clientTcpHandle).checkErrorThrowIO() + UvUtils.onFail(uv_close(clientTcpHandle, onClose)) + uv_read_start(clientTcpHandle, allocBuffer, onRead) + .checkErrorThrowIO() + () + } { exception => + setFailed(exception.getMessage()) + } + // if `uv_read_start` failed, then `uv_close` followed by `clientTcpHandle.free()` + // have been run in that order by this point } ``` +`UvUtils.attemptCatch` is designed for use in callback functions where you don't want to throw any exceptions. There is also `UvUtils.attempt`, which runs the cleanup actions but does not catch the exception. + +### File I/O + +The libuv file I/O functions support use of multiple buffers at once. scala-uv provides the `IOVector` type for working with multiple buffers with varying amoutns of data. + +scala-uv provides a shortcut for allocating, using and freeing `FileReq` objects, *if you are doing blocking I/O*: `FileReq.use`. + +```scala +// writes the C string pointed to by `cText` to a file +val bytesWritten = FileReq + .use { writeReq => + val iov = + IOVector.stackAllocateForBuffer(cText, string.strlen(cText).toUInt) + uv_fs_write( + loop, + writeReq, + fileHandle, + iov.nativeBuffers, + iov.nativeNumBuffers, + -1, + null + ) + } + .checkErrorThrowIO() +``` + + ### Malloc C strings While the `Zone` memory allocation API from Scala Native is very nice, it's not useful when the memory is freed in a different callback, as there won't be a shared lexical scope. So `mallocCString` converts a Scala string to a C string, allocating the memory the old-fashioned way. diff --git a/build-windows.sh b/build-windows.sh index 298a515..1624196 100644 --- a/build-windows.sh +++ b/build-windows.sh @@ -9,8 +9,6 @@ mkdir -p build (cd build && cmake ..) cmake --build build -find build - echo SBT_NATIVE_COMPILE="set nativeCompileOptions += \"--include-directory=$repo_dir/libuv-build/include\" ; " >> $GITHUB_ENV echo SBT_NATIVE_LINK="set nativeLinkingOptions += \"--library-directory=$repo_dir/libuv-build/build/Debug\" ; " >> $GITHUB_ENV diff --git a/build.sbt b/build.sbt index 592d72e..46dcd73 100644 --- a/build.sbt +++ b/build.sbt @@ -7,7 +7,7 @@ organization := "io.github.quelgar" name := "scala-uv" -version := "0.0.1" +version := "0.0.2" ThisBuild / versionScheme := Some("early-semver") @@ -40,7 +40,7 @@ sonatypeCredentialHost := "s01.oss.sonatype.org" sonatypeRepository := "https://s01.oss.sonatype.org/service/local" -credentials += Credentials(Path.userHome / ".sbt" / "sonatype_credentials") +// credentials += Credentials(Path.userHome / ".sbt" / "sonatype_credentials") licenses := Seq("APL2" -> url("http://www.apache.org/licenses/LICENSE-2.0.txt")) @@ -48,3 +48,21 @@ import xerial.sbt.Sonatype._ sonatypeProjectHosting := Some( GitHubHosting("quelgar", "scala-uv", "lodea@mac.com") ) + +autoAPIMappings := true + +apiURL := Some( + url( + s"https://javadoc.io/doc/io.github.quelgar/scala-uv_native0.4_3/${version.value}/index.html" + ) +) + +Compile / doc / scalacOptions ++= Seq( + "-social-links:github::https://github.com/quelgar,twitter::https://twitter.com/quelgar", + "-groups", + "-project-version", + version.value, + "-doc-root-content", + "doc-root.txt", + "-skip-by-id:scalauv.main" +) diff --git a/doc-root.txt b/doc-root.txt new file mode 100644 index 0000000..1444ea7 --- /dev/null +++ b/doc-root.txt @@ -0,0 +1,9 @@ +/** **scala-uv** provides Scala Native bindings for the [libuv](https://libuv.org/) library. + +The main API is located in the [[scalauv.LibUv]] object. Other important types are +[[scalauv.Handle]] and [[scalauv.Req]]. + +See [[scalauv.ErrorCodes]] for error codes. + +See [[scalauv.UvUtils]] for some useful utilities to make working with libuv easier. +*/ \ No newline at end of file diff --git a/src/main/resources/scala-native/helpers.c b/src/main/resources/scala-native/helpers.c index f7817dc..2bccf2c 100644 --- a/src/main/resources/scala-native/helpers.c +++ b/src/main/resources/scala-native/helpers.c @@ -19,11 +19,21 @@ void *scala_uv_buf_base(const uv_buf_t *buffer) return buffer->base; } +void scala_uv_buf_base_set(uv_buf_t *buffer, void *base) +{ + buffer->base = base; +} + size_t scala_uv_buf_len(const uv_buf_t *buffer) { return buffer->len; } +void scala_uv_buf_len_set(uv_buf_t *buffer, size_t len) +{ + buffer->len = len; +} + size_t scala_uv_buf_struct_size() { return sizeof(uv_buf_t); diff --git a/src/main/scala/scalauv/Buffer.scala b/src/main/scala/scalauv/Buffer.scala index 40df73a..232e758 100644 --- a/src/main/scala/scalauv/Buffer.scala +++ b/src/main/scala/scalauv/Buffer.scala @@ -6,35 +6,78 @@ import java.nio import java.nio.charset.StandardCharsets import scala.scalanative.libc.stdlib +/** The `uv_buf_t*` type. The fields of a `Buffer` are `base` and `length`. + * `base` points to the actual content, while `length` typicaly indicates how + * many bytes are valid. + * + * @see + * [[scalauv.Buffer$]] + */ opaque type Buffer = Ptr[Byte] +/** Constructors and utilties for the [[scalauv.Buffer Buffer]] opaque type that + * represents a pointer to the `uv_buf_t` native C type. + * + * @see + * [[scalauv.Buffer]] + */ object Buffer { given Tag[Buffer] = Tag.Ptr(Tag.Byte) extension (buffer: Buffer) { + /** Pointer to the actual content. + */ def base: Ptr[Byte] = helpers.scala_uv_buf_base(buffer) + + def base_=(ptr: Ptr[Byte]): Unit = + helpers.scala_uv_buf_base_set(buffer, ptr) + + /** The number of bytes (starting from `base`) that should be considered + * part of this buffer. When reading, you probably want to set this to the + * number of bytes read. + */ def length: Int = helpers.scala_uv_buf_len(buffer).toInt + def length_=(len: Int): Unit = + helpers.scala_uv_buf_len_set(buffer, len.toUInt) + + /** Gets the byte at the specified index. + * + * @param index + * the index of the byte to get, should be 0 <= `index` < `length`, but + * this is not checked. + */ def apply(index: Int): Byte = base(index) // TODO in Scala Native 0.5 - def asNio: nio.ByteBuffer = ??? - - def asUtf8String(max: Int): String = - new String(asArray(max), StandardCharsets.UTF_8) - - def asArray(max: Int): Array[Byte] = { - val a = Array.ofDim[Byte](max) - for i <- 0 until max do { + // def asNio: nio.ByteBuffer = ??? + + /** Convert this buffer to a `String` using the UTF-8 charset. When reading, + * you probably want to set `length` to the number of bytes read before + * calling this. + */ + def asUtf8String: String = + new String(asArray, StandardCharsets.UTF_8) + + /** Copies this buffer content into a new Scala array. Copies `length` bytes + * from `base` into a new array. When reading, you probably want to set + * `length` to the number of bytes read before calling this. + */ + def asArray: Array[Byte] = { + val len = length + val a = Array.ofDim[Byte](len) + for i <- 0 until len do { a(i) = base(i) } a } - def foreachByte(max: Int)(f: Byte => Unit): Unit = { - for i <- 0 until max do { + /** Performs an operation using each byte in this buffer. + */ + def foreach(f: Byte => Unit): Unit = { + for i <- 0 until length do { f(base(i)) } } @@ -42,61 +85,95 @@ object Buffer { def +(index: Int): Buffer = buffer + (index.toLong * Buffer.structureSize.toLong) + /** Gets the native pointer to this buffer structure. + */ inline def toPtr: Ptr[Byte] = buffer - inline def init(base: Ptr[Byte], size: CSize): Unit = - helpers.scala_uv_buf_init(base, size.toUInt, buffer) + /** Initializes this buffer structure with the specified `base` and + * `length`. + */ + inline def init(base: Ptr[Byte], length: CSize): Unit = + helpers.scala_uv_buf_init(base, length.toUInt, buffer) + /** Allocates a new native byte array of `size` bytes, and uses it to + * initialize this buffer structure. `base` is set to the newly allocated + * array, and `length` is set to `size`. + */ inline def mallocInit(size: CSize): Unit = helpers.scala_uv_buf_init(stdlib.malloc(size), size.toUInt, buffer) + /** Frees this boffer structure. **Note:** does not free the `base` pointer. + */ inline def free(): Unit = stdlib.free(buffer) } + /** The size of the `uv_buf_t` structure. Useful for manual allocation. + */ val structureSize: CSize = helpers.scala_uv_buf_struct_size() + /** Cast a native pointer to a buffer structure pointer. + */ inline def unsafeFromPtr(ptr: Ptr[Byte]): Buffer = ptr + /** Allocates a new buffer structure on the stack and initializes it with the + * specified `base` and `length`. + */ inline def stackAllocate( - ptr: Ptr[Byte], - size: CUnsignedInt + base: Ptr[Byte], + length: CUnsignedInt ): Buffer = { val uvBuf = stackalloc[Byte](structureSize) - helpers.scala_uv_buf_init(ptr, size, uvBuf) + uvBuf.init(base, length) uvBuf } + /** Allocates a new buffer structure on the stack and initializes it to point + * to the specified array and index. `base` points to the byte and index + * `index` in `array`. `length` is set to `array.length - index`. + */ inline def stackAllocate( array: Array[Byte], index: Int = 0 ): Buffer = { val uvBuf = stackalloc[Byte](structureSize) - helpers.scala_uv_buf_init( - array.at(index), - (array.length - index).toUInt, - uvBuf - ) + uvBuf.init(array.at(index), (array.length - index).toUInt) uvBuf } + /** Zone allocates a new buffer structure and initializes it with the + * specified `base` and `length`. + */ + def zoneAllocate(base: Ptr[Byte], length: CSize)(using Zone): Buffer = { + val uvBuf = alloc[Byte](structureSize) + uvBuf.init(base, length) + uvBuf + } + + /** Zone allocates a new buffer structure and initializes it to point to the + * specified array and index. `base` points to the byte and index `index` in + * `array`. `length` is set to `array.length - index`. + */ def zoneAllocate(array: Array[Byte], index: Int = 0)(using Zone ): Buffer = { val uvBuf = alloc[Byte](structureSize) - helpers.scala_uv_buf_init( - array.at(index), - (array.length - index).toUInt, - uvBuf - ) + uvBuf.init(array.at(index), (array.length - index).toUInt) uvBuf } + /** Allocates a new buffer structure and initializes it with the specified + * `base` and `length`. + */ def malloc(base: Ptr[Byte], size: CSize): Buffer = { val uvBuf = stdlib.malloc(structureSize.toULong) helpers.scala_uv_buf_init(base, size.toUInt, uvBuf) uvBuf } + /** Allocates a new buffer structure and initializes it to point to the + * specified array and index. `base` points to the byte and index `index` in + * `array`. `length` is set to `array.length - index`. + */ def malloc(array: Array[Byte], index: Int = 0): Buffer = { val uvBuf = stdlib.malloc(structureSize.toULong) helpers.scala_uv_buf_init( diff --git a/src/main/scala/scalauv/Handle.scala b/src/main/scala/scalauv/Handle.scala index 37a1090..f7f3f5f 100644 --- a/src/main/scala/scalauv/Handle.scala +++ b/src/main/scala/scalauv/Handle.scala @@ -3,32 +3,60 @@ package scalauv import scala.scalanative.unsafe.* import scala.scalanative.libc.stdlib +/** Representation of a `uv_handle_t*` native type. + * + * @see + * [[https://docs.libuv.org/en/v1.x/handle.html#c.uv_handle_t Libuv Docs]] + */ opaque type Handle = Ptr[Byte] +/** Constructors for the [[scalauv.Handle Handle]] opaque type that represents a + * pointer to the `uv_handle_t` native C type. While this object can be used to + * allocate handles by providing a handle type, it is more common to use the + * equivalent allocation methods for the exact handle type you want, for + * example `TcpHandle.malloc()`. + */ object Handle { given Tag[Handle] = Tag.Ptr(Tag.Byte) extension (h: Handle) { + + /** Extract the underlying native pointer for this handle. + */ inline def toPtr: Ptr[Byte] = h + /** Frees this hnadle structure. + */ inline def free(): Unit = stdlib.free(h) } + /** Casts a native pointer to a handle structure to the `Handle` type. + */ inline def unsafeFromPtr(ptr: Ptr[Byte]): Handle = ptr - inline def zoneAllocate(handleType: HandleType)(using Zone): Handle = - alloc[Byte](LibUv.uv_handle_size(handleType)).asInstanceOf[Handle] - + /** Stack allocate a handle structure of the specified type. + */ inline def stackAllocate(handleType: HandleType): Handle = Handle.unsafeFromPtr(stackalloc[Byte](LibUv.uv_handle_size(handleType))) + /** Zone allocate a handle structure of the specified type. + */ + inline def zoneAllocate(handleType: HandleType)(using Zone): Handle = + alloc[Byte](LibUv.uv_handle_size(handleType)).asInstanceOf[Handle] + + /** Malloc allocate a handle structure of the specified type. + */ inline def malloc(handleType: HandleType): Handle = stdlib.malloc(LibUv.uv_handle_size(handleType)).asInstanceOf[Handle] } +/** A native C enum representing the type of a handle. + */ opaque type HandleType = CInt +/** Constants for alll the handle types supported by libuv. + */ object HandleType { val UV_UNKNOWN_HANDLE: HandleType = 0 val UV_ASYNC: HandleType = 1 @@ -51,6 +79,11 @@ object HandleType { val UV_HANDLE_TYPE_MAX: HandleType = 18 } +/** The `uv_async_t*` type. + * + * @see + * [[https://docs.libuv.org/en/v1.x/async.html#c.uv_async_t Libuv Docs]] + */ opaque type AsyncHandle <: Handle = Ptr[Byte] object AsyncHandle { @@ -66,6 +99,11 @@ object AsyncHandle { Handle.malloc(HandleType.UV_ASYNC) } +/** The `uv_timer_t*` type. + * + * @see + * [[https://docs.libuv.org/en/v1.x/timer.html#c.uv_timer_t Libuv Docs]] + */ opaque type TimerHandle <: Handle = Ptr[Byte] object TimerHandle { @@ -81,7 +119,12 @@ object TimerHandle { Handle.malloc(HandleType.UV_TIMER) } -type PrepareHandle = Ptr[Byte] +/** The `uv_prepare_t*` type. + * + * @see + * [[https://docs.libuv.org/en/v1.x/prepare.html#c.uv_prepare_t Libuv Docs]] + */ +opaque type PrepareHandle <: Handle = Ptr[Byte] object PrepareHandle { given Tag[PrepareHandle] = Tag.Ptr(Tag.Byte) @@ -96,7 +139,12 @@ object PrepareHandle { Handle.malloc(HandleType.UV_PREPARE) } -type CheckHandle = Ptr[Byte] +/** The `uv_check_t*` type. + * + * @see + * [[https://docs.libuv.org/en/v1.x/check.html#c.uv_check_t Libuv Docs]] + */ +opaque type CheckHandle <: Handle = Ptr[Byte] object CheckHandle { given Tag[CheckHandle] = Tag.Ptr(Tag.Byte) @@ -111,7 +159,12 @@ object CheckHandle { Handle.malloc(HandleType.UV_CHECK) } -type IdleHandle = Ptr[Byte] +/** The `uv_idle_t*` type. + * + * @see + * [[https://docs.libuv.org/en/v1.x/idle.html#c.uv_idle_t Libuv Docs]] + */ +opaque type IdleHandle <: Handle = Ptr[Byte] object IdleHandle { given Tag[IdleHandle] = Tag.Ptr(Tag.Byte) @@ -126,7 +179,12 @@ object IdleHandle { Handle.malloc(HandleType.UV_IDLE) } -type PollHandle = Ptr[Byte] +/** The `uv_poll_t*` type. + * + * @see + * [[https://docs.libuv.org/en/v1.x/poll.html#c.uv_poll_t Libuv Docs]] + */ +opaque type PollHandle <: Handle = Ptr[Byte] object PollHandle { given Tag[PollHandle] = Tag.Ptr(Tag.Byte) @@ -141,7 +199,12 @@ object PollHandle { Handle.malloc(HandleType.UV_POLL) } -type SignalHandle = Ptr[Byte] +/** The `uv_signal_t*` type. + * + * @see + * [[https://docs.libuv.org/en/v1.x/signal.html#c.uv_signal_t Libuv Docs]] + */ +opaque type SignalHandle <: Handle = Ptr[Byte] object SignalHandle { given Tag[SignalHandle] = Tag.Ptr(Tag.Byte) @@ -156,6 +219,11 @@ object SignalHandle { Handle.malloc(HandleType.UV_SIGNAL) } +/** The `uv_stream_t*` type. + * + * @see + * [[https://docs.libuv.org/en/v1.x/stream.html#c.uv_stream_t Libuv Docs]] + */ opaque type StreamHandle <: Handle = Ptr[Byte] object StreamHandle { @@ -164,6 +232,11 @@ object StreamHandle { } +/** The `uv_tcp_t*` type. + * + * @see + * [[https://docs.libuv.org/en/v1.x/tcp.html#c.uv_tcp_t Libuv Docs]] + */ opaque type TcpHandle <: StreamHandle = Ptr[Byte] object TcpHandle { @@ -179,6 +252,11 @@ object TcpHandle { Handle.malloc(HandleType.UV_TCP) } +/** The `uv_pipe_t*` type. + * + * @see + * [[https://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_t Libuv Docs]] + */ opaque type PipeHandle <: StreamHandle = Ptr[Byte] object PipeHandle { @@ -194,6 +272,11 @@ object PipeHandle { Handle.malloc(HandleType.UV_NAMED_PIPE) } +/** The `uv_tty_t*` type. + * + * @see + * [[https://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_t Libuv Docs]] + */ opaque type TtyHandle <: StreamHandle = Ptr[Byte] object TtyHandle { @@ -209,6 +292,11 @@ object TtyHandle { Handle.malloc(HandleType.UV_TTY) } +/** The `uv_udp_t*` type. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_t Libuv Docs]] + */ opaque type UdpHandle = Ptr[Byte] object UdpHandle { @@ -224,6 +312,11 @@ object UdpHandle { Handle.malloc(HandleType.UV_UDP) } +/** The `uv_fs_event_t*` type. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs_event.html#c.uv_fs_event_t Libuv Docs]] + */ opaque type FsEventHandle = Ptr[Byte] object FsEventHandle { @@ -239,6 +332,11 @@ object FsEventHandle { Handle.malloc(HandleType.UV_FS_EVENT) } +/** The `uv_fs_poll_t*` type. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs_poll.html#c.uv_fs_poll_t Libuv Docs]] + */ opaque type FsPollHandle = Ptr[Byte] object FsPollHandle { @@ -254,4 +352,9 @@ object FsPollHandle { Handle.malloc(HandleType.UV_FS_POLL) } +/** The `uv_fs_t` type. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_t Libuv Docs]] + */ type FileHandle = CInt diff --git a/src/main/scala/scalauv/IOVector.scala b/src/main/scala/scalauv/IOVector.scala index 67f829d..6efba87 100644 --- a/src/main/scala/scalauv/IOVector.scala +++ b/src/main/scala/scalauv/IOVector.scala @@ -4,17 +4,34 @@ import scala.util.boundary import scala.scalanative.unsigned.* import scala.scalanative.unsafe.* +/** A collection of multiple buffers. + * + * @param nativeBuffers + * Pointer to a consecutive sequence of `uv_buf_t` structures. + * @param numberOfBuffers + * The number of buffers located at `nativeBuffers`. + */ final class IOVector(val nativeBuffers: Buffer, numberOfBuffers: Int) { + /** Gets the buffer structure at the specified index. + */ inline def apply(index: Int): Buffer = { nativeBuffers + index } + /** Calls the specified function for each buffer in this collection. + */ inline def foreachBuffer(f: Buffer => Unit): Unit = for index <- 0 until numberOfBuffers do { f(apply(index)) } + /** Calls the specified function for each buffer in this collection, up to a + * maximum number. + * + * @param max + * The maximum number of buffers to process. + */ def foreachBufferMax(max: Int)(f: Buffer => Unit): Unit = { var remaining = max boundary { @@ -35,6 +52,8 @@ final class IOVector(val nativeBuffers: Buffer, numberOfBuffers: Int) { object IOVector { + /** Stack allocats a single buffer structure. + */ inline def stackAllocateForBuffer( ptr: Ptr[Byte], size: CUnsignedInt @@ -43,6 +62,8 @@ object IOVector { IOVector(buffer, 1) } + /** Stack allocates multiple buffer structures. + */ inline def stackAllocateForBuffers( buffers: Seq[(Ptr[Byte], CUnsignedInt)] ): IOVector = { @@ -55,6 +76,11 @@ object IOVector { IOVector(uvBufs, buffers.size) } + /** Zone allocates both buffer structures and the underlying base byte arrays. + * + * @param bufferSizes + * The sizes of the buffers to allocate. + */ def zoneAllocate(bufferSizes: Int*)(using Zone): IOVector = { val uvBufs = alloc[Byte](bufferSizes.size.toUInt * Buffer.structureSize) diff --git a/src/main/scala/scalauv/LibUv.scala b/src/main/scala/scalauv/LibUv.scala index b41c377..f87e37f 100644 --- a/src/main/scala/scalauv/LibUv.scala +++ b/src/main/scala/scalauv/LibUv.scala @@ -4,6 +4,54 @@ import scala.scalanative.unsafe.* opaque type Loop = Ptr[Byte] +/** The main API of libuv. + * + * @groupprio event_loop 10 + * @groupprio base_handle 20 + * @groupprio base_request 30 + * @groupprio misc 40 + * @groupprio stream_handle 50 + * @groupprio tcp_handle 60 + * @groupprio fs 70 + * @groupprio async_handle 80 + * @groupprio timer_handle 90 + * @groupprio prepare_handle 100 + * @groupprio check_handle 110 + * @groupprio idle_handle 120 + * @groupprio poll_handle 130 + * @groupprio signal_handle 140 + * @groupprio process_handle 150 + * @groupprio thread_pool 160 + * @groupprio dns 170 + * @groupprio thread 180 + * @groupprio fs_event_handle 190 + * @groupprio fs_poll_handle 200 + * + * @groupname event_loop Event loop + * @groupname base_handle Base handle + * @groupname base_request Base request + * @groupname timer_handle Timer handle + * @groupname prepare_handle Prepare handle + * @groupname check_handle Check handle + * @groupname idle_handle Idle handle + * @groupname async_handle Async handle + * @groupname poll_handle Poll handle + * @groupname signal_handle Signal handle + * @groupname process_handle Process handle + * @groupname stream_handle Stream handle + * @groupname tcp_handle TCP handle + * @groupname pipe_handle Pipe handle + * @groupname tty_handle TTY handle + * @groupname udp_handle UDP handle + * @groupname fs_event_handle Filesystem event handle + * @groupname fs_poll_handle Filesystem poll handle + * @groupname timer_handle Timer handle + * @groupname fs File system operations + * @groupname thread_pool Thread pool + * @groupname dns DNS + * @groupname thread Threads and synchronization + * @groupname misc Miscellaneous + */ @link("uv") @extern object LibUv { @@ -11,103 +59,349 @@ object LibUv { // ========================================================= // Event loop + /** Callback for `uv_walk`. + * + * @see + * [[https://docs.libuv.org/en/v1.x/loop.html#c.uv_walk_cb LibUv docs]] + * @group event_loop + */ type WalkCallback = CFuncPtr2[Handle, Ptr[Byte], Unit] + /** Initialize an event loop. + * + * @see + * [[https://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_init LibUv docs]] + * @group event_loop + */ def uv_loop_init(loop: Loop): ErrorCode = extern // TODO: figure out best way to handle varargs // def uv_loop_configure(loop: Loop, option: CInt, value: CInt): ErrorCode = // extern + /** Close an event loop. + * + * @see + * [[https://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_close LibUv docs]] + * @group event_loop + */ def uv_loop_close(loop: Loop): ErrorCode = extern + /** Get the default event loop. + * + * @see + * [[https://docs.libuv.org/en/v1.x/loop.html#c.uv_default_loop LibUv docs]] + * @group event_loop + */ def uv_default_loop(): Loop = extern + /** Run the event loop. + * + * @see + * [[https://docs.libuv.org/en/v1.x/loop.html#c.uv_run LibUv docs]] + * @group event_loop + */ def uv_run(loop: Loop, runMode: RunMode): ErrorCode = extern + /** Check if the event loop is still alive. + * + * @see + * [[https://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_alive LibUv docs]] + * @group event_loop + */ def uv_loop_alive(loop: Loop): CInt = extern + /** Stop the event loop. + * + * @see + * [[https://docs.libuv.org/en/v1.x/loop.html#c.uv_stop LibUv docs]] + * @group event_loop + */ def uv_stop(loop: Loop): Unit = extern + /** Get the size of the event loop structure. + * + * @see + * [[https://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_size LibUv docs]] + * @group event_loop + */ def uv_loop_size(): CSize = extern + /** Get the file descriptor of the event loop. + * + * @see + * [[https://docs.libuv.org/en/v1.x/loop.html#c.uv_backend_fd LibUv docs]] + * @group event_loop + */ def uv_backend_fd(loop: Loop): CInt = extern + /** Get the timeout of the event loop. + * + * @see + * [[https://docs.libuv.org/en/v1.x/loop.html#c.uv_backend_timeout LibUv docs]] + * @group event_loop + */ def uv_backend_timeout(loop: Loop): CInt = extern + /** Get the current time. + * + * @see + * [[https://docs.libuv.org/en/v1.x/loop.html#c.uv_now LibUv docs]] + * @group event_loop + */ def uv_now(loop: Loop): CUnsignedLongLong = extern + /** Update event loop's current time. + * + * @see + * [[https://docs.libuv.org/en/v1.x/loop.html#c.uv_update_time LibUv docs]] + * @group event_loop + */ def uv_update_time(loop: Loop): Unit = extern + /** Walk the event loop's handles. + * + * @see + * [[https://docs.libuv.org/en/v1.x/loop.html#c.uv_walk LibUv docs]] + * @group event_loop + */ def uv_walk(loop: Loop, walkCallback: WalkCallback, arg: Ptr[Byte]): Unit = extern + /** Initialize the event loop after a fork. + * + * @see + * [[https://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_fork LibUv docs]] + * @group event_loop + */ def uv_loop_fork(loop: Loop): ErrorCode = extern + /** Get the user data attached to the event loop. + * + * @see + * [[https://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_get_data LibUv docs]] + * @group event_loop + */ def uv_loop_get_data(loop: Loop): Ptr[Byte] = extern + /** Set the user data attached to the event loop. + * + * @see + * [[https://docs.libuv.org/en/v1.x/loop.html#c.uv_loop_set_data LibUv docs]] + * @group event_loop + */ def uv_loop_set_data(loop: Loop, data: Ptr[Byte]): Unit = extern // ========================================================= // Base handle + /** Callback for buffer allocation. + * + * @see + * [[https://docs.libuv.org/en/v1.x/handle.html#c.uv_alloc_cb LibUv docs]] + * @group base_handle + */ type AllocCallback = CFuncPtr3[Handle, CSize, Buffer, Unit] + /** Callback for closing handles. + * + * @see + * [[https://docs.libuv.org/en/v1.x/handle.html#c.uv_close_cb LibUv docs]] + * @group base_handle + */ type CloseCallback = CFuncPtr1[Handle, Unit] + /** Check if a handle is active. + * + * @see + * [[https://docs.libuv.org/en/v1.x/handle.html#c.uv_is_active LibUv docs]] + * @group base_handle + */ def uv_is_active(handle: Handle): CInt = extern + /** Check if a handle is closing. + * + * @see + * [[https://docs.libuv.org/en/v1.x/handle.html#c.uv_is_closing LibUv docs]] + * @group base_handle + */ def uv_is_closing(handle: Handle): CInt = extern + /** Close a handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/handle.html#c.uv_close LibUv docs]] + * @group base_handle + */ def uv_close(handle: Handle, callback: CloseCallback): Unit = extern + /** Reference a handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/handle.html#c.uv_ref LibUv docs]] + * @group base_handle + */ def uv_ref(handle: Handle): Unit = extern + /** Unreference a handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/handle.html#c.uv_unref LibUv docs]] + * @group base_handle + */ def uv_unref(handle: Handle): Unit = extern + /** Check if a handle is referenced. + * + * @see + * [[https://docs.libuv.org/en/v1.x/handle.html#c.uv_has_ref LibUv docs]] + * @group base_handle + */ def uv_has_ref(handle: Handle): CInt = extern + /** Get the size of a handle structure. + * + * @see + * [[https://docs.libuv.org/en/v1.x/handle.html#c.uv_handle_size LibUv docs]] + * @group base_handle + */ def uv_handle_size(handle_type: HandleType): CSize = extern + /** Gets the size of the send buffer. + * + * @see + * [[https://docs.libuv.org/en/v1.x/handle.html#c.uv_send_buffer_size LibUv docs]] + * @group base_handle + */ def uv_send_buffer_size(handle: Handle, value: Ptr[CInt]): ErrorCode = extern + /** Sets the size of the receive buffer. + * + * @see + * [[https://docs.libuv.org/en/v1.x/handle.html#c.uv_recv_buffer_size LibUv docs]] + * @group base_handle + */ def uv_recv_buffer_size(handle: Handle, value: Ptr[CInt]): ErrorCode = extern // TODO: the file descriptor type varies between Unix and Windows // def uv_fileno(handle: Handle, fd: Ptr[CInt]): ErrorCode = extern + /** Get the event loop of a handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/handle.html#c.uv_handle_get_loop LibUv docs]] + * @group base_handle + */ def uv_handle_get_loop(handle: Handle): Loop = extern + /** Get the user data attached to a handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/handle.html#c.uv_handle_get_data LibUv docs]] + * @group base_handle + */ def uv_handle_get_data(handle: Handle): Ptr[Byte] = extern + /** Set the user data attached to a handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/handle.html#c.uv_handle_set_data LibUv docs]] + * @group base_handle + */ def uv_handle_set_data(handle: Handle, data: Ptr[Byte]): Unit = extern + /** Get the type of a handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/handle.html#c.uv_handle_get_type LibUv docs]] + * @group base_handle + */ def uv_handle_get_type(handle: Handle): HandleType = extern + /** Get the name of a handle type. + * + * @see + * [[https://docs.libuv.org/en/v1.x/handle.html#c.uv_handle_type_name LibUv docs]] + * @group base_handle + */ def uv_handle_type_name(handleType: HandleType): CString = extern // ========================================================= // Base request + /** Cancels a request. + * + * @see + * [[https://docs.libuv.org/en/v1.x/request.html#c.uv_cancel LibUv docs]] + * @group base_request + */ def uv_cancel(req: Req): ErrorCode = extern + /** Get the size of a request structure. + * + * @see + * [[https://docs.libuv.org/en/v1.x/request.html#c.uv_req_size LibUv docs]] + * @group base_request + */ def uv_req_size(req_type: RequestType): CSize = extern + /** Gets th user data attached to a request. + * + * @see + * [[https://docs.libuv.org/en/v1.x/request.html#c.uv_req_get_data LibUv docs]] + * @group base_request + */ def uv_req_get_data(req: Req): Ptr[Byte] = extern + /** Sets the user data attached to a request. + * + * @see + * [[https://docs.libuv.org/en/v1.x/request.html#c.uv_req_set_data LibUv docs]] + * @group base_request + */ def uv_req_set_data(req: Req, data: Ptr[Byte]): Unit = extern + /** Gets the type of a request. + * + * @see + * [[https://docs.libuv.org/en/v1.x/request.html#c.uv_req_get_type LibUv docs]] + * @group base_request + */ def uv_req_get_type(req: Req): RequestType = extern + /** Gets the name of a request type. + * + * @see + * [[https://docs.libuv.org/en/v1.x/request.html#c.uv_req_type_name LibUv docs]] + * @group base_request + */ def uv_req_type_name(reqType: RequestType): CString = extern // ========================================================= // Timer handle + /** Callback for timers. + * + * @see + * [[https://docs.libuv.org/en/v1.x/timer.html#c.uv_timer_cb LibUv docs]] + * @group timer_handle + */ type TimerCallback = CFuncPtr1[TimerHandle, Unit] + /** Initialize a timer handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/timer.html#c.uv_timer_init LibUv docs]] + * @group timer_handle + */ def uv_timer_init(loop: Loop, handle: TimerHandle): ErrorCode = extern + /** Start a timer. + * + * @see + * [[https://docs.libuv.org/en/v1.x/timer.html#c.uv_timer_start LibUv docs]] + * @group timer_handle + */ def uv_timer_start( handle: TimerHandle, callback: TimerCallback, @@ -115,76 +409,208 @@ object LibUv { repeatMillis: CUnsignedLong ): ErrorCode = extern + /** Stop a timer. + * + * @see + * [[https://docs.libuv.org/en/v1.x/timer.html#c.uv_timer_stop LibUv docs]] + * @group timer_handle + */ def uv_timer_stop(handle: TimerHandle): ErrorCode = extern + /** Stop and repeat a timer. + * + * @see + * [[https://docs.libuv.org/en/v1.x/timer.html#c.uv_timer_again LibUv docs]] + * @group timer_handle + */ def uv_timer_again(handle: TimerHandle): ErrorCode = extern + /** Set the repeat interval of a timer. + * + * @see + * [[https://docs.libuv.org/en/v1.x/timer.html#c.uv_timer_set_repeat LibUv docs]] + * @group timer_handle + */ def uv_timer_set_repeat( handle: TimerHandle, repeatMillis: CUnsignedLongLong ): Unit = extern + /** Gets the repeat interval of a timer. + * + * @see + * [[https://docs.libuv.org/en/v1.x/timer.html#c.uv_timer_get_repeat LibUv docs]] + * @group timer_handle + */ def uv_timer_get_repeat(handle: TimerHandle): CUnsignedLongLong = extern + /** Gets the time until a timer is due. + * + * @see + * [[https://docs.libuv.org/en/v1.x/timer.html#c.uv_timer_get_due_in LibUv docs]] + * @group timer_handle + */ def uv_timer_get_due_in(handle: TimerHandle): CUnsignedLongLong = extern // ========================================================= // Prepare handle + /** Callback for prepare handles. + * + * @see + * [[https://docs.libuv.org/en/v1.x/prepare.html#c.uv_prepare_cb LibUv docs]] + * @group prepare_handle + */ type PrepareCallback = CFuncPtr1[PrepareHandle, Unit] + /** Initialize a prepare handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/prepare.html#c.uv_prepare_init LibUv docs]] + * @group prepare_handle + */ def uv_prepare_init(loop: Loop, handle: PrepareHandle): ErrorCode = extern + /** Start a prepare handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/prepare.html#c.uv_prepare_start LibUv docs]] + * @group prepare_handle + */ def uv_prepare_start( handle: PrepareHandle, callback: PrepareCallback ): ErrorCode = extern + /** Stop a prepare handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/prepare.html#c.uv_prepare_stop LibUv docs]] + * @group prepare_handle + */ def uv_prepare_stop(handle: PrepareHandle): ErrorCode = extern // ========================================================= // Check handle + /** Callback for check handles. + * + * @see + * [[https://docs.libuv.org/en/v1.x/check.html#c.uv_check_cb LibUv docs]] + * @group check_handle + */ type CheckCallback = CFuncPtr1[CheckHandle, Unit] + /** Initialize a check handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/check.html#c.uv_check_init LibUv docs]] + * @group check_handle + */ def uv_check_init(loop: Loop, handle: CheckHandle): ErrorCode = extern + /** Start a check handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/check.html#c.uv_check_start LibUv docs]] + * @group check_handle + */ def uv_check_start(handle: CheckHandle, callback: CheckCallback): ErrorCode = extern + /** Stop a check handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/check.html#c.uv_check_stop LibUv docs]] + * @group check_handle + */ def uv_check_stop(handle: CheckHandle): ErrorCode = extern // ========================================================= // Idle handle + /** Callback for idle handles. + * + * @see + * [[https://docs.libuv.org/en/v1.x/idle.html#c.uv_idle_cb LibUv docs]] + * @group idle_handle + */ type IdleCallback = CFuncPtr1[IdleHandle, Unit] + /** Initialize an idle handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/idle.html#c.uv_idle_init LibUv docs]] + * @group idle_handle + */ def uv_idle_init(loop: Loop, handle: IdleHandle): ErrorCode = extern + /** Start an idle handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/idle.html#c.uv_idle_start LibUv docs]] + * @group idle_handle + */ def uv_idle_start(handle: IdleHandle, callback: IdleCallback): ErrorCode = extern + /** Stop an idle handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/idle.html#c.uv_idle_stop LibUv docs]] + * @group idle_handle + */ def uv_idle_stop(handle: IdleHandle): ErrorCode = extern // ========================================================= // Async handle + /** Callback for async handles. + * + * @see + * [[https://docs.libuv.org/en/v1.x/async.html#c.uv_async_cb LibUv docs]] + * @group async_handle + */ type AsyncCallback = CFuncPtr1[AsyncHandle, Unit] + /** Initialize an async handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/async.html#c.uv_async_init LibUv docs]] + * @group async_handle + */ def uv_async_init( loop: Loop, handle: AsyncHandle, callback: AsyncCallback ): ErrorCode = extern + /** Send a signal to an async handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/async.html#c.uv_async_send LibUv docs]] + * @group async_handle + */ def uv_async_send(handle: AsyncHandle): ErrorCode = extern // ========================================================= // Poll handle + /** Callback for poll handles. + * + * @see + * [[https://docs.libuv.org/en/v1.x/poll.html#c.uv_poll_cb LibUv docs]] + * @group poll_handle + */ type PollCallback = CFuncPtr3[PollHandle, ErrorCode, CInt, Unit] + /** Initialize a poll handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/poll.html#c.uv_poll_init LibUv docs]] + * @group poll_handle + */ def uv_poll_init(loop: Loop, handle: PollHandle, fd: CInt): ErrorCode = extern @@ -195,33 +621,75 @@ object LibUv { // socket: OsSocketHandle // ): ErrorCode = extern + /** Start a poll handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/poll.html#c.uv_poll_start LibUv docs]] + * @group poll_handle + */ def uv_poll_start( handle: PollHandle, events: CInt, callback: PollCallback ): ErrorCode = extern + /** Stop a poll handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/poll.html#c.uv_poll_stop LibUv docs]] + * @group poll_handle + */ def uv_poll_stop(handle: PollHandle): ErrorCode = extern // ========================================================= // Signal handle + /** Callback for signal handles. + * + * @see + * [[https://docs.libuv.org/en/v1.x/signal.html#c.uv_signal_cb LibUv docs]] + * @group signal_handle + */ type SignalCallback = CFuncPtr2[SignalHandle, CInt, Unit] + /** Initialize a signal handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/signal.html#c.uv_signal_init LibUv docs]] + * @group signal_handle + */ def uv_signal_init(loop: Loop, handle: SignalHandle): ErrorCode = extern + /** Start a signal handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/signal.html#c.uv_signal_start LibUv docs]] + * @group signal_handle + */ def uv_signal_start( handle: SignalHandle, callback: SignalCallback, signum: CInt ): ErrorCode = extern + /** Start a one-shot signal handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/signal.html#c.uv_signal_start_one_shot LibUv docs]] + * @group signal_handle + */ def uv_signal_start_one_shot( handle: SignalHandle, callback: SignalCallback, signum: CInt ): ErrorCode = extern + /** Stop a signal handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/signal.html#c.uv_signal_stop LibUv docs]] + * @group signal_handle + */ def uv_signal_stop(handle: SignalHandle): ErrorCode = extern // ========================================================= @@ -259,41 +727,107 @@ object LibUv { // ========================================================= // Stream handle + /** Callback for reading from a stream. + * + * @see + * [[https://docs.libuv.org/en/v1.x/stream.html#c.uv_read_cb LibUv docs]] + * @group stream_handle + */ type StreamReadCallback = CFuncPtr3[StreamHandle, CSSize, Buffer, Unit] + /** Callback for writing to a stream. + * + * @see + * [[https://docs.libuv.org/en/v1.x/stream.html#c.uv_write_cb LibUv docs]] + * @group stream_handle + */ type StreamWriteCallback = CFuncPtr2[WriteReq, CInt, Unit] + /** Callback for connecting a stream. + * + * @see + * [[https://docs.libuv.org/en/v1.x/stream.html#c.uv_connect_cb LibUv docs]] + * @group stream_handle + */ type ConnectCallback = CFuncPtr2[ConnectReq, CInt, Unit] + /** Callback for shutting down a stream. + * + * @see + * [[https://docs.libuv.org/en/v1.x/stream.html#c.uv_shutdown_cb LibUv docs]] + * @group stream_handle + */ type ShutdownCallback = CFuncPtr2[Req, CInt, Unit] + /** Callback for accepting an incoming connection. + * + * @see + * [[https://docs.libuv.org/en/v1.x/stream.html#c.uv_connection_cb LibUv docs]] + * @group stream_handle + */ type ConnectionCallback = CFuncPtr2[StreamHandle, ErrorCode, Unit] + /** Shudown a stream. + * + * @see + * [[https://docs.libuv.org/en/v1.x/stream.html#c.uv_shutdown LibUv docs]] + * @group stream_handle + */ def uv_shutdown( req: ShutdownReq, handle: StreamHandle, cb: ShutdownCallback ): ErrorCode = extern + /** Listen for incoming connections. + * + * @see + * [[https://docs.libuv.org/en/v1.x/stream.html#c.uv_listen LibUv docs]] + * @group stream_handle + */ def uv_listen( stream: StreamHandle, backlog: CInt, cb: ConnectionCallback ): ErrorCode = extern + /** Accept an incoming connection. + * + * @see + * [[https://docs.libuv.org/en/v1.x/stream.html#c.uv_accept LibUv docs]] + * @group stream_handle + */ def uv_accept( server: StreamHandle, client: StreamHandle ): ErrorCode = extern + /** Start reading from a stream. + * + * @see + * [[https://docs.libuv.org/en/v1.x/stream.html#c.uv_read_start LibUv docs]] + * @group stream_handle + */ def uv_read_start( stream: StreamHandle, alloc_cb: AllocCallback, read_cb: StreamReadCallback ): ErrorCode = extern + /** Stop reading from a stream. + * + * @see + * [[https://docs.libuv.org/en/v1.x/stream.html#c.uv_read_stop LibUv docs]] + * @group stream_handle + */ def uv_read_stop(stream: StreamHandle): ErrorCode = extern + /** Write to a stream. + * + * @see + * [[https://docs.libuv.org/en/v1.x/stream.html#c.uv_write LibUv docs]] + * @group stream_handle + */ def uv_write( req: WriteReq, handle: StreamHandle, @@ -302,6 +836,12 @@ object LibUv { cb: StreamWriteCallback ): ErrorCode = extern + /** Write to a stream with a handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/stream.html#c.uv_write2 LibUv docs]] + * @group stream_handle + */ def uv_write2( req: WriteReq, handle: StreamHandle, @@ -311,12 +851,24 @@ object LibUv { cb: StreamWriteCallback ): ErrorCode = extern + /** Try writing to a stream. + * + * @see + * [[https://docs.libuv.org/en/v1.x/stream.html#c.uv_try_write LibUv docs]] + * @group stream_handle + */ def uv_try_write( handle: StreamHandle, bufs: Buffer, numberOfBufs: CUnsignedInt ): CInt = extern + /** Try writing to a stream with a handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/stream.html#c.uv_try_write2 LibUv docs]] + * @group stream_handle + */ def uv_try_write2( handle: StreamHandle, bufs: Buffer, @@ -324,57 +876,141 @@ object LibUv { sendHandle: StreamHandle ): CInt = extern + /** Check if a stream is readable. + * + * @see + * [[https://docs.libuv.org/en/v1.x/stream.html#c.uv_is_readable LibUv docs]] + * @group stream_handle + */ def uv_is_readable(handle: StreamHandle): CInt = extern + /** Check if a stream is writable. + * + * @see + * [[https://docs.libuv.org/en/v1.x/stream.html#c.uv_is_writable LibUv docs]] + * @group stream_handle + */ def uv_is_writable(handle: StreamHandle): CInt = extern + /** Set the blocking mode of a stream. + * + * @see + * [[https://docs.libuv.org/en/v1.x/stream.html#c.uv_stream_set_blocking LibUv docs]] + * @group stream_handle + */ def uv_stream_set_blocking(handle: StreamHandle, blocking: CInt): CInt = extern + /** Get the write queue size of a stream. + * + * @see + * [[https://docs.libuv.org/en/v1.x/stream.html#c.uv_stream_get_write_queue_size LibUv docs]] + * @group stream_handle + */ def uv_stream_get_write_queue_size(handle: StreamHandle): CSize = extern // ========================================================= // TCP handle + /** Initializes a TCP handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/tcp.html#c.uv_tcp_init LibUv docs]] + * @group tcp_handle + */ def uv_tcp_init(loop: Loop, handle: TcpHandle): ErrorCode = extern + /** Initializes a TCP handle with additional flags. + * + * @see + * [[https://docs.libuv.org/en/v1.x/tcp.html#c.uv_tcp_init_ex LibUv docs]] + * @group tcp_handle + */ def uv_tcp_init_ex( loop: Loop, handle: TcpHandle, flags: CUnsignedInt ): ErrorCode = extern + /** Opens a TCP handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/tcp.html#c.uv_tcp_open LibUv docs]] + * @group tcp_handle + */ def uv_tcp_open(handle: TcpHandle, sock: CInt): ErrorCode = extern + /** Sets the no-delay status of a TCP handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/tcp.html#c.uv_tcp_nodelay LibUv docs]] + * @group tcp_handle + */ def uv_tcp_no_delay(handle: TcpHandle, enable: CInt): ErrorCode = extern + /** Sets the keep-alive status of a TCP handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/tcp.html#c.uv_tcp_keepalive LibUv docs]] + * @group tcp_handle + */ def uv_tcp_keepalive( handle: TcpHandle, enable: CInt, delay: CUnsignedInt ): ErrorCode = extern + /** Sets the number of simultaneous accepts for a TCP handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/tcp.html#c.uv_tcp_simultaneous_accepts LibUv docs]] + * @group tcp_handle + */ def uv_tcp_simultaneous_accepts(handle: TcpHandle, enable: CInt): ErrorCode = extern + /** Binds a TCP handle to an address. + * + * @see + * [[https://docs.libuv.org/en/v1.x/tcp.html#c.uv_tcp_bind LibUv docs]] + * @group tcp_handle + */ def uv_tcp_bind( handle: TcpHandle, addr: SocketAddress, flags: CUnsignedInt ): ErrorCode = extern + /** Gets the socket address bound for a handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/tcp.html#c.uv_tcp_getsockname LibUv docs]] + * @group tcp_handle + */ def uv_tcp_getsockname( handle: TcpHandle, name: SocketAddress, namelen: Ptr[CInt] ): ErrorCode = extern + /** Gets the socket address of the peer for a handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/tcp.html#c.uv_tcp_getpeername LibUv docs]] + * @group tcp_handle + */ def uv_tcp_getpeername( handle: TcpHandle, name: SocketAddress, namelen: Ptr[CInt] ): ErrorCode = extern + /** Connects a TCP handle to an address. + * + * @see + * [[https://docs.libuv.org/en/v1.x/tcp.html#c.uv_tcp_connect LibUv docs]] + * @group tcp_handle + */ def uv_tcp_connect( req: Req, handle: TcpHandle, @@ -382,6 +1018,12 @@ object LibUv { cb: ConnectCallback ): ErrorCode = extern + /** Closes and resets a TCP handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/tcp.html#c.uv_tcp_close_reset LibUv docs]] + * @group tcp_handle + */ def uv_tcp_close_reset(handle: TcpHandle, cb: CloseCallback): ErrorCode = extern @@ -397,22 +1039,46 @@ object LibUv { // ========================================================= // Pipe handle + /** Initializes a pipe handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_init LibUv docs]] + * @group pipe_handle + */ def uv_pipe_init( loop: Loop, handle: PipeHandle, ipc: CInt ): ErrorCode = extern + /** Opens a pipe handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_open LibUv docs]] + * @group pipe_handle + */ def uv_pipe_open( handle: PipeHandle, file: FileHandle ): ErrorCode = extern + /** Binds a pipe handle to a name. + * + * @see + * [[https://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_bind LibUv docs]] + * @group pipe_handle + */ def uv_pipe_bind( handle: PipeHandle, name: CString ): ErrorCode = extern + /** Binds a pipe handle to a name with additional flags. + * + * @see + * [[https://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_bind2 LibUv docs]] + * @group pipe_handle + */ def uv_pipe_bind2( handle: PipeHandle, name: CString, @@ -420,6 +1086,12 @@ object LibUv { flags: CUnsignedInt ): ErrorCode = extern + /** Connects a pipe handle to a name. + * + * @see + * [[https://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_connect LibUv docs]] + * @group pipe_handle + */ def uv_pipe_connect( req: ConnectReq, handle: PipeHandle, @@ -427,6 +1099,12 @@ object LibUv { cb: ConnectCallback ): Unit = extern + /** Connects a pipe handle to a name with additional flags. + * + * @see + * [[https://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_connect2 LibUv docs]] + * @group pipe_handle + */ def uv_pipe_connect2( req: ConnectReq, handle: PipeHandle, @@ -436,29 +1114,71 @@ object LibUv { cb: ConnectCallback ): Unit = extern + /** Gets the name of a pipe handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_getsockname LibUv docs]] + * @group pipe_handle + */ def uv_pipe_getsockname( handle: PipeHandle, buffer: CString, nameLength: Ptr[CSize] ): ErrorCode = extern + /** Gets the name of the peer of a pipe handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_getpeername LibUv docs]] + * @group pipe_handle + */ def uv_pipe_getpeername( handle: PipeHandle, buffer: CString, nameLength: Ptr[CSize] ): ErrorCode = extern + /** Sets the pending instance count of a pipe handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_pending_instances LibUv docs]] + * @group pipe_handle + */ def uv_pipe_pending_instances( handle: PipeHandle, count: CInt ): Unit = extern + /** Gets the pending count of a pipe handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_pending_count LibUv docs]] + * @group pipe_handle + */ def uv_pipe_pending_count(handle: PipeHandle): CSize = extern + /** Gets the pending type of a pipe handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_pending_type LibUv docs]] + * @group pipe_handle + */ def uv_pipe_pending_type(handle: PipeHandle): HandleType = extern + /** Chmod a pipe handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe_chmod LibUv docs]] + * @group pipe_handle + */ def uv_pipe_chmod(handle: PipeHandle, flags: CInt): ErrorCode = extern + /** Creates a pair of connected pipe handles. + * + * @see + * [[https://docs.libuv.org/en/v1.x/pipe.html#c.uv_pipe LibUv docs]] + * @group pipe_handle + */ def uv_pipe( fileHandles: Ptr[FileHandle], readFlags: CInt, @@ -468,6 +1188,12 @@ object LibUv { // ========================================================= // TTY handle + /** Initializes a TTY handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_init LibUv docs]] + * @group tty_handle + */ def uv_tty_init( loop: Loop, handle: TtyHandle, @@ -475,30 +1201,84 @@ object LibUv { unused: CInt ): ErrorCode = extern + /** Resets a TTY handle mode. + * + * @see + * [[https://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_reset_mode LibUv docs]] + * @group tty_handle + */ def uv_tty_set_mode(handle: TtyHandle, mode: TtyMode): ErrorCode = extern + /** Resets a TTY handle mode. + * + * @see + * [[https://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_reset_mode LibUv docs]] + * @group tty_handle + */ def uv_tty_reset_mode(): ErrorCode = extern + /** Gets the window size of a TTY handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_get_winsize LibUv docs]] + * @group tty_handle + */ def uv_tty_get_winsize( handle: TtyHandle, width: Ptr[CInt], height: Ptr[CInt] ): ErrorCode = extern + /** Sets the virtual terminal state of a TTY handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_set_vterm_state LibUv docs]] + * @group tty_handle + */ def uv_tty_set_vterm_state(state: TtyVtermState): ErrorCode = extern + /** Gets the virtual terminal state of a TTY handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_get_vterm_state LibUv docs]] + * @group tty_handle + */ def uv_tty_get_vterm_state(state: Ptr[TtyVtermState]): ErrorCode = extern // ========================================================= // UDP handle + /** Callback for sending a UDP message. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_send_cb LibUv docs]] + * @group udp_handle + */ type UdpSendCallback = CFuncPtr2[UdpSendReq, ErrorCode, Unit] + /** Callback for receiving a UDP message. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_recv_cb LibUv docs]] + * @group udp_handle + */ type UdpRecvCallback = CFuncPtr5[UdpHandle, CSSize, Buffer, SocketAddress, CUnsignedInt, Unit] + /** Initializes a UDP handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_init LibUv docs]] + * @group udp_handle + */ def uv_udp_init(loop: Loop, handle: UdpHandle): ErrorCode = extern + /** Initializes a UDP handle with additional flags. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_init_ex LibUv docs]] + * @group udp_handle + */ def uv_udp_init_ex( loop: Loop, handle: UdpHandle, @@ -509,29 +1289,59 @@ object LibUv { // TODO: what type to use for OsSocketHandle? // def uv_udp_open(handle: UdpHandle, sock: OsSocketHandle): ErrorCode = extern + /** Binds a UDP handle to an address. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_bind LibUv docs]] + * @group udp_handle + */ def uv_udp_bind( handle: UdpHandle, addr: SocketAddress, flags: CUnsignedInt ): ErrorCode = extern + /** Connects a UDP handle to an address. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_connect LibUv docs]] + * @group udp_handle + */ def uv_udp_connect( handle: UdpHandle, addr: SocketAddress ): ErrorCode = extern + /** Gets the socket address of the peer for a UDP handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_getpeername LibUv docs]] + * @group udp_handle + */ def uv_udp_getpeername( handle: UdpHandle, name: SocketAddress, namelen: Ptr[CInt] ): ErrorCode = extern + /** Gets the socket address bound for a UDP handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_getsockname LibUv docs]] + * @group udp_handle + */ def uv_udp_getsockname( handle: UdpHandle, name: SocketAddress, namelen: Ptr[CInt] ): ErrorCode = extern + /** Sets the membership for a multicast address on a UDP handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_set_membership LibUv docs]] + * @group udp_handle + */ def uv_udp_set_membership( handle: UdpHandle, multicastAddress: CString, @@ -539,6 +1349,12 @@ object LibUv { membership: Membership ): ErrorCode = extern + /** Sets the source membership for a multicast address on a UDP handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_set_source_membership LibUv docs]] + * @group udp_handle + */ def uv_udp_set_source_membership( handle: UdpHandle, multicastAddress: CString, @@ -547,21 +1363,57 @@ object LibUv { membership: Membership ): ErrorCode = extern + /** Sets the multicast loopback status for a UDP handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_set_multicast_loop LibUv docs]] + * @group udp_handle + */ def uv_udp_set_multicast_loop(handle: UdpHandle, on: CInt): ErrorCode = extern + /** Sets the multicast TTL for a UDP handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_set_multicast_ttl LibUv docs]] + * @group udp_handle + */ def uv_udp_set_multicast_ttl(handle: UdpHandle, ttl: CInt): ErrorCode = extern + /** Sets the multicast interface for a UDP handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_set_multicast_interface LibUv docs]] + * @group udp_handle + */ def uv_udp_set_multicast_interface( handle: UdpHandle, interfaceAddress: CString ): ErrorCode = extern + /** Sets the broadcast status for a UDP handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_set_broadcast LibUv docs]] + * @group udp_handle + */ def uv_udp_set_broadcast(handle: UdpHandle, on: CInt): ErrorCode = extern + /** Sets the TTL for a UDP handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_set_ttl LibUv docs]] + * @group udp_handle + */ def uv_udp_set_ttl(handle: UdpHandle, ttl: CInt): ErrorCode = extern + /** Sends a UDP message. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_send LibUv docs]] + * @group udp_handle + */ def uv_udp_send( req: UdpSendReq, handle: UdpHandle, @@ -571,6 +1423,12 @@ object LibUv { sendCb: UdpSendCallback ): ErrorCode = extern + /** Tries to send a UDP message. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_try_send LibUv docs]] + * @group udp_handle + */ def uv_udp_try_send( handle: UdpHandle, bufs: Buffer, @@ -578,23 +1436,59 @@ object LibUv { addr: SocketAddress ): CInt = extern + /** Starts reading from a UDP handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_recv_start LibUv docs]] + * @group udp_handle + */ def uv_udp_recv_start( handle: UdpHandle, alloc_cb: AllocCallback, recv_cb: UdpRecvCallback ): ErrorCode = extern + /** Indicates if the handle is using `UV_UDP_RECVMMSG`. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_using_recvmmsg LibUv docs]] + * @group udp_handle + */ def uv_udp_using_recvmmsg(handle: UdpHandle): CInt = extern + /** Stops reading from a UDP handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_recv_stop LibUv docs]] + * @group udp_handle + */ def uv_udp_recv_stop(handle: UdpHandle): ErrorCode = extern + /** Gets the send queue size of a UDP handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_get_send_queue_size LibUv docs]] + * @group udp_handle + */ def uv_udp_get_send_queue_size(handle: UdpHandle): CSize = extern + /** Gets the send queue count of a UDP handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/udp.html#c.uv_udp_get_send_queue_count LibUv docs]] + * @group udp_handle + */ def uv_udp_get_send_queue_count(handle: UdpHandle): CSize = extern // ========================================================= // FS Event handle + /** Callback for file system events. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_event_cb LibUv docs]] + * @group fs_event_handle + */ type FsEventCallback = CFuncPtr4[ FsEventHandle, CString, @@ -603,11 +1497,23 @@ object LibUv { Unit ] + /** Initializes a file system event handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_event_init LibUv docs]]` + * @group fs_event_handle + */ def uv_fs_event_init( loop: Loop, handle: FsEventHandle ): ErrorCode = extern + /** Starts a file system event handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_event_start LibUv docs]] + * @group fs_event_handle + */ def uv_fs_event_start( handle: FsEventHandle, cb: FsEventCallback, @@ -615,8 +1521,20 @@ object LibUv { flags: CUnsignedInt ): ErrorCode = extern + /** Stops a file system event handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_event_stop LibUv docs]] + * @group fs_event_handle + */ def uv_fs_event_stop(handle: FsEventHandle): ErrorCode = extern + /** Gets the path of a file system event handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_event_getpath LibUv docs]] + * @group fs_event_handle + */ def uv_fs_event_getpath( handle: FsEventHandle, buffer: CString, @@ -626,13 +1544,31 @@ object LibUv { // ========================================================= // FS Poll handle + /** Callback for file system polls. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_poll_cb LibUv docs]] + * @group fs_poll_handle + */ type FsPollCallback = CFuncPtr4[FsPollHandle, ErrorCode, Stat, Stat, Unit] + /** Initializes a file system poll handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_poll_init LibUv docs]] + * @group fs_poll_handle + */ def uv_fs_poll_init( loop: Loop, handle: FsPollHandle ): ErrorCode = extern + /** Starts a file system poll handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_poll_start LibUv docs]] + * @group fs_poll_handle + */ def uv_fs_poll_start( handle: FsPollHandle, cb: FsPollCallback, @@ -640,8 +1576,20 @@ object LibUv { interval: CUnsignedInt ): ErrorCode = extern + /** Stops a file system poll handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_poll_stop LibUv docs]] + * @group fs_poll_handle + */ def uv_fs_poll_stop(handle: FsPollHandle): ErrorCode = extern + /** Gets the path of a file system poll handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_poll_getpath LibUv docs]] + * @group fs_poll_handle + */ def uv_fs_poll_getpath( handle: FsPollHandle, buffer: CString, @@ -651,8 +1599,20 @@ object LibUv { // ========================================================= // File system operations + /** Pointer to time strucutre. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_timespec_t LibUv docs]] + * @group fs + */ type TimeSpec = Ptr[CStruct2[CLong, CLong]] + /** Pointer to file `stat` strcture. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_stat_t LibUv docs]] + * @group fs + */ type Stat = Ptr[CStruct16[ CUnsignedLongLong, CUnsignedLongLong, @@ -672,6 +1632,12 @@ object LibUv { TimeSpec ]] + /** Pointer to `struct statfs`. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_statfs_t LibUv docs]] + * @group fs + */ type StatFs = Ptr[CStruct11[ CUnsignedLongLong, CUnsignedLongLong, @@ -686,14 +1652,53 @@ object LibUv { CUnsignedLongLong ]] + /** Pointer to directory entry structure. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_dirent_t LibUv docs]] + * @group fs + */ type DirEnt = Ptr[CStruct2[CString, DirEntType]] + /** Pointer to directory structure. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_dir_t LibUv docs]] + * @group fs + */ type Dir = Ptr[CStruct2[DirEnt, CSize]] + /** Callback for file system requests. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_cb LibUv docs]] + * @group fs + */ type FsCallback = CFuncPtr1[Req, Unit] + /** Cleans up a file system request. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_req_cleanup LibUv docs]] + * @group fs + */ def uv_fs_req_cleanup(req: FileReq): Unit = extern + /** Closes a file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_close LibUv docs]] + * @group fs + * + * @param loop + * The event loop + * @param req + * The file system request + * @param file + * The file to be closed. + * @param callback + * The callback to be called after the file is closed. + */ def uv_fs_close( loop: Loop, req: FileReq, @@ -701,6 +1706,27 @@ object LibUv { callback: FsCallback ): ErrorCode = extern + /** Opens a file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_open LibUv docs]] + * @group fs + * + * @param loop + * The event loop + * @param req + * The file system request + * @param path + * The path to the file to be opened + * @param flags + * The flags to be used when opening the file + * @param mode + * The mode to apply when creating a file. + * @param callback + * The callback to be called after the file is opened + * @return + * The file handle, < 0 if an error occurred. + */ def uv_fs_open( loop: Loop, req: FileReq, @@ -710,6 +1736,29 @@ object LibUv { callback: FsCallback ): FileHandle = extern + /** Reads from a file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_read LibUv docs]] + * @group fs + * + * @param loop + * The event loop + * @param req + * The file system request + * @param file + * The file to be read from + * @param bufs + * The buffer to read into + * @param numberOfBufs + * The number of buffers + * @param offset + * The offset to read from + * @param callback + * The callback to be called after the file is read + * @return + * 0 if successful, < 0 if an error occurred. + */ def uv_fs_read( loop: Loop, req: FileReq, @@ -720,6 +1769,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Unlinks a file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_unlink LibUv docs]] + * @group fs + */ def uv_fs_unlink( loop: Loop, req: FileReq, @@ -727,6 +1782,29 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Writes to a file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_write LibUv docs]] + * @group fs + * + * @param loop + * The event loop + * @param req + * The file system request + * @param file + * The file to be written to + * @param bufs + * The buffer to write from + * @param numberOfBufs + * The number of buffers + * @param offset + * The offset to write to + * @param callback + * The callback to be called after the file is written + * @return + * 0 if successful, < 0 if an error occurred. + */ def uv_fs_write( loop: Loop, req: FileReq, @@ -737,6 +1815,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Makes a directory. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_mkdir LibUv docs]] + * @group fs + */ def uv_fs_mkdir( loop: Loop, req: FileReq, @@ -745,6 +1829,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Makes a temporary directory. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_mkdtemp LibUv docs]] + * @group fs + */ def uv_fs_mkdtemp( loop: Loop, req: FileReq, @@ -752,6 +1842,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Makes a temporary file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_mkstemp LibUv docs]] + * @group fs + */ def uv_fs_mkstemp( loop: Loop, req: FileReq, @@ -759,6 +1855,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Removes a directory. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_rmdir LibUv docs]] + * @group fs + */ def uv_fs_rmdir( loop: Loop, req: FileReq, @@ -766,6 +1868,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Opens a directory. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_opendir LibUv docs]] + * @group fs + */ def uv_fs_opendir( loop: Loop, req: FileReq, @@ -773,6 +1881,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Closes a directory. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_closedir LibUv docs]] + * @group fs + */ def uv_fs_closedir( loop: Loop, req: FileReq, @@ -780,6 +1894,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Reads a directory. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_readdir LibUv docs]] + * @group fs + */ def uv_fs_readdir( loop: Loop, req: FileReq, @@ -787,6 +1907,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Scans a directory. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_scandir LibUv docs]] + * @group fs + */ def uv_fs_scandir( loop: Loop, req: FileReq, @@ -795,11 +1921,23 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Moves to the next item in a directory scan. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_scandir_next LibUv docs]] + * @group fs + */ def uv_fs_scandir_next( req: FileReq, ent: Ptr[DirEnt] ): ErrorCode = extern + /** Gets the stats of a file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_stat LibUv docs]] + * @group fs + */ def uv_fs_stat( loop: Loop, req: FileReq, @@ -807,6 +1945,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Gets the stats of a file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_fstat LibUv docs]] + * @group fs + */ def uv_fs_fstat( loop: Loop, req: FileReq, @@ -814,6 +1958,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Gets the stats of a file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_lstat LibUv docs]] + * @group fs + */ def uv_fs_lstat( loop: Loop, req: FileReq, @@ -821,6 +1971,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Gets the stats of a file system. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_statfs LibUv docs]] + * @group fs + */ def uv_fs_statfs( loop: Loop, req: FileReq, @@ -828,6 +1984,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Renames a file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_rename LibUv docs]] + * @group fs + */ def uv_fs_rename( loop: Loop, req: FileReq, @@ -836,6 +1998,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Syncs a file to disk. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_fsync LibUv docs]] + * @group fs + */ def uv_fs_fsync( loop: Loop, req: FileReq, @@ -843,6 +2011,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Syncs a file to disk. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_fdatasync LibUv docs]] + * @group fs + */ def uv_fs_fdatasync( loop: Loop, req: FileReq, @@ -850,6 +2024,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Truncates a file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_ftruncate LibUv docs]] + * @group fs + */ def uv_fs_ftruncate( loop: Loop, req: FileReq, @@ -858,6 +2038,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Copies a file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_copyfile LibUv docs]] + * @group fs + */ def uv_fs_copyfile( loop: Loop, req: FileReq, @@ -867,6 +2053,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Sends a file to another file handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_sendfile LibUv docs]] + * @group fs + */ def uv_fs_sendfile( loop: Loop, req: FileReq, @@ -877,6 +2069,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Checks access to a file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_access LibUv docs]] + * @group fs + */ def uv_fs_access( loop: Loop, req: FileReq, @@ -885,6 +2083,12 @@ object LibUv { cb: FsCallback ): CInt = extern + /** Changes the permissions of a file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_chmod LibUv docs]] + * @group fs + */ def uv_fs_chmod( loop: Loop, req: FileReq, @@ -893,6 +2097,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Changes the permissions of a file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_fchmod LibUv docs]] + * @group fs + */ def uv_fs_fchmod( loop: Loop, req: FileReq, @@ -901,6 +2111,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Sets the access and modification times of a file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_utime LibUv docs]] + * @group fs + */ def uv_fs_utime( loop: Loop, req: FileReq, @@ -910,6 +2126,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Sets the access and modification times of a file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_futime LibUv docs]] + * @group fs + */ def uv_fs_futime( loop: Loop, req: FileReq, @@ -919,6 +2141,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Sets the access and modification times of a file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_lutime LibUv docs]] + * @group fs + */ def uv_fs_lutime( loop: Loop, req: FileReq, @@ -928,6 +2156,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Creates a hard link to a file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_link LibUv docs]] + * @group fs + */ def uv_fs_link( loop: Loop, req: FileReq, @@ -936,6 +2170,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Creates a symbolic link to a file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_symlink LibUv docs]] + * @group fs + */ def uv_fs_symlink( loop: Loop, req: FileReq, @@ -945,6 +2185,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Reads the value of a symbolic link. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_readlink LibUv docs]] + * @group fs + */ def uv_fs_readlink( loop: Loop, req: FileReq, @@ -952,6 +2198,12 @@ object LibUv { cb: FsCallback ): ErrorCode = extern + /** Resolves the real path of a file. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_realpath LibUv docs]] + * @group fs + */ def uv_fs_realpath( loop: Loop, req: FileReq, @@ -986,16 +2238,53 @@ object LibUv { // cb: FsCallback // ): ErrorCode = extern + /** Gets the type of a file request. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_get_type LibUv docs]] + * @group fs + */ def uv_fs_get_type(req: FileReq): FsType = extern + /** Gets the result of a file request. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_get_result LibUv docs]] + * @group fs + */ def uv_fs_get_result(req: FileReq): CSSize = extern + /** Gets the platform specific error code of a file request. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_get_system_error LibUv docs]] + * @group fs + */ def uv_fs_get_system_error(req: FileReq): ErrorCode = extern + /** Gets the request pointer. What it points at depends on the type of + * request. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_get_ptr LibUv docs]] + * @group fs + */ def uv_fs_get_ptr(req: FileReq): Ptr[Byte] = extern + /** Gets the path of a file request. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_get_path LibUv docs]] + * @group fs + */ def uv_fs_get_path(req: FileReq): CString = extern + /** Gets the stat buffer of a file request. + * + * @see + * [[https://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_get_statbuf LibUv docs]] + * @group fs + */ def uv_fs_get_statbuf(req: FileReq): Stat = extern // TODO: what type to use for OsFileHandle? @@ -1006,10 +2295,28 @@ object LibUv { // ========================================================= // Thread pool work scheduling + /** Callback to perform work on the thread pool. + * + * @see + * [[https://docs.libuv.org/en/v1.x/threadpool.html#c.uv_work_cb LibUv docs]] + * @group thread_pool + */ type WorkCallback = CFuncPtr1[WorkReq, Unit] + /** Callback to perform work on the thread pool after the work is done. + * + * @see + * [[https://docs.libuv.org/en/v1.x/threadpool.html#c.uv_after_work_cb LibUv docs]] + * @group thread_pool + */ type AfterWorkCallback = CFuncPtr2[WorkReq, ErrorCode, Unit] + /** Enqueues work to be performed by the thread pool. + * + * @see + * [[https://docs.libuv.org/en/v1.x/threadpool.html#c.uv_queue_work LibUv docs]] + * @group thread_pool + */ def uv_queue_work( loop: Loop, req: WorkReq, @@ -1020,34 +2327,61 @@ object LibUv { // ========================================================= // DNS utility functions - type GetAddrInfo = Ptr[Byte] - - type GetAddrInfoCallback = CFuncPtr3[GetAddrInfo, ErrorCode, AddrInfo, Unit] - - type GetNameInfo = Ptr[Byte] - + /** Callback for getting address info from DNS. + * + * @see + * [[https://docs.libuv.org/en/v1.x/dns.html#c.uv_getaddrinfo_cb LibUv docs]] + * @group dns + */ + type GetAddrInfoCallback = + CFuncPtr3[GetAddrInfoReq, ErrorCode, AddrInfo, Unit] + + /** Callback for getting name info from DNS. + * + * @see + * [[https://docs.libuv.org/en/v1.x/dns.html#c.uv_getnameinfo_cb LibUv docs]] + * @group dns + */ type GetNameInfoCallback = CFuncPtr4[ - GetNameInfo, + GetNameInfoReq, ErrorCode, CString, CString, Unit ] + /** Get address info from DNS. + * + * @see + * [[https://docs.libuv.org/en/v1.x/dns.html#c.uv_getaddrinfo LibUv docs]] + * @group dns + */ def uv_getaddrinfo( loop: Loop, - req: GetAddrInfo, + req: GetAddrInfoReq, getaddrinfo_cb: GetAddrInfoCallback, node: CString, service: CString, hints: Ptr[AddrInfo] ): ErrorCode = extern + /** Free address info. + * + * @see + * [[https://docs.libuv.org/en/v1.x/dns.html#c.uv_freeaddrinfo LibUv docs]] + * @group dns + */ def uv_freeaddrinfo(ai: AddrInfo): Unit = extern + /** Get name info from DNS. + * + * @see + * [[https://docs.libuv.org/en/v1.x/dns.html#c.uv_getnameinfo LibUv docs]] + * @group dns + */ def uv_getnameinfo( loop: Loop, - req: GetNameInfo, + req: GetNameInfoReq, getnameinfo_cb: GetNameInfoCallback, addr: SocketAddress, flags: CInt @@ -1056,18 +2390,60 @@ object LibUv { // ========================================================= // Threading and synchronization utilities + /** Callback for thread operations. + * + * @see + * [[https://docs.libuv.org/en/v1.x/thread.html#c.uv_thread_cb LibUv docs]] + * @group thread + */ type ThreadCallback = CFuncPtr1[Thread, Unit] + /** Initialise a mutex handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/thread.html#c.uv_mutex_init LibUv docs]] + * @group thread + */ def uv_mutex_init(mutex: Mutex): ErrorCode = extern + /** Initialise a recursive mutex handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/thread.html#c.uv_mutex_init_recursive LibUv docs]] + * @group thread + */ def uv_mutex_init_recursive(mutex: Mutex): ErrorCode = extern + /** Destroy a mutex handle. + * + * @see + * [[https://docs.libuv.org/en/v1.x/thread.html#c.uv_mutex_destroy LibUv docs]] + * @group thread + */ def uv_mutex_destroy(mutex: Mutex): Unit = extern + /** Lock a mutex. + * + * @see + * [[https://docs.libuv.org/en/v1.x/thread.html#c.uv_mutex_lock LibUv docs]] + * @group thread + */ def uv_mutex_lock(mutex: Mutex): Unit = extern + /** Try to lock a mutex. + * + * @see + * [[https://docs.libuv.org/en/v1.x/thread.html#c.uv_mutex_trylock LibUv docs]] + * @group thread + */ def uv_mutex_trylock(mutex: Mutex): ErrorCode = extern + /** Unlock a mutex. + * + * @see + * [[https://docs.libuv.org/en/v1.x/thread.html#c.uv_mutex_unlock LibUv docs]] + * @group thread + */ def uv_mutex_unlock(mutex: Mutex): Unit = extern // ========================================================= @@ -1079,20 +2455,60 @@ object LibUv { // TODO: 32bit on Unix, 64bit on Windows // type OsFileHandle = Nothing + /** PID type. + * + * @group misc + */ type Pid = CInt + /** Time type. + * + * @group misc + */ type TimeVal = Ptr[CStruct2[CLong, CLong]] + /** 64-bit time type. + * + * @group misc + */ type TimeVal64 = Ptr[CStruct2[Long, Int]] + /** 64-bit time type. + * + * @group misc + */ type TimeSpec64 = Ptr[CStruct2[Long, Int]] + /** Gets the error message for the given error code. + * + * @see + * [[https://docs.libuv.org/en/v1.x/misc.html#c.uv_strerror_r LibUv docs]] + * @group misc + */ def uv_strerror_r(err: CInt, buf: CString, buflen: CSize): CString = extern + /** Gets the error name for the given error code. + * + * @see + * [[https://docs.libuv.org/en/v1.x/misc.html#c.uv_err_name_r LibUv docs]] + * @group misc + */ def uv_err_name_r(err: CInt, buf: CString, buflen: CSize): CString = extern + /** Gets the libuv error code equivalent for a platform error. + * + * @see + * [[https://docs.libuv.org/en/v1.x/misc.html#c.uv_translate_sys_error LibUv docs]] + * @group misc + */ def uv_translate_sys_error(sys_errno: CInt): CInt = extern + /** Converts an IPv4 address string to an address structure. + * + * @see + * [[https://docs.libuv.org/en/v1.x/misc.html#c.uv_ip4_addr LibUv docs]] + * @group misc + */ def uv_ip4_addr( ip: CString, port: CInt, @@ -1100,6 +2516,12 @@ object LibUv { ): ErrorCode = extern + /** Converts an IPv6 address string to an address structure. + * + * @see + * [[https://docs.libuv.org/en/v1.x/misc.html#c.uv_ip6_addr LibUv docs]] + * @group misc + */ def uv_ip6_addr( ip: CString, port: CInt, @@ -1107,12 +2529,24 @@ object LibUv { ): ErrorCode = extern + /** Converts an IPv4 address structure to a string. + * + * @see + * [[https://docs.libuv.org/en/v1.x/misc.html#c.uv_ip4_name LibUv docs]] + * @group misc + */ def uv_ip4_name( src: Ptr[SocketAddressIp4], dst: CString, size: CSize ): ErrorCode = extern + /** Converts an IPv6 address structure to a string. + * + * @see + * [[https://docs.libuv.org/en/v1.x/misc.html#c.uv_ip6_name LibUv docs]] + * @group misc + */ def uv_ip6_name( src: Ptr[SocketAddressIp6], dst: CString, diff --git a/src/main/scala/scalauv/Req.scala b/src/main/scala/scalauv/Req.scala index 900aaa4..dc44ef0 100644 --- a/src/main/scala/scalauv/Req.scala +++ b/src/main/scala/scalauv/Req.scala @@ -3,12 +3,22 @@ package scalauv import scalanative.unsafe.* import scala.scalanative.libc.stdlib +/** Representation of a `uv_req_t*` native type. + */ opaque type Req = Ptr[Byte] +/** Constructors for the [[scalauv.Req Req]] opaque type that represents a + * pointer to the `uv_req_t` native C type. While this object can be used to + * allocate requests by providing a request type, it is more common to use the + * equivalent allocation methods for the exact request type you want, for + * example `ConnectReq.malloc()`. + */ object Req { given Tag[Req] = Tag.Ptr(Tag.Byte) + /** Cast a native pointer to a request structure to the `Req` type. + */ inline def unsafeFromPtr(ptr: Ptr[Byte]): Req = ptr /** Allocate the specified type of request on the stack. @@ -23,16 +33,24 @@ object Req { inline def stackAllocate(requestType: RequestType): Req = stackalloc[Byte](LibUv.uv_req_size(requestType)) + /** Zone allocate the specified type of request. + */ inline def zoneAllocate(requestType: RequestType)(using Zone): Req = alloc[Byte](LibUv.uv_req_size(requestType)) + /** Allocate the specified type of request. + */ inline def malloc(requestType: RequestType): Req = stdlib.malloc(LibUv.uv_req_size(requestType)).asInstanceOf[Req] extension (r: Req) { + /** Casts this request to a native pointer. + */ inline def toPtr: Ptr[Byte] = r + /** Frees this request structure. + */ inline def free(): Unit = stdlib.free(r) } @@ -41,6 +59,8 @@ object Req { opaque type RequestType = CInt +/** Constants for all the request types supported by libuv. + */ object RequestType { val UNKNOWN_REQ: RequestType = 0 val REQ: RequestType = 1 @@ -81,6 +101,21 @@ object ConnectReq { opaque type ShutdownReq <: Req = Ptr[Byte] +object ShutdownReq { + + given Tag[ShutdownReq] = Tag.Ptr(Tag.Byte) + + inline def stackAllocate(): ShutdownReq = + Req.stackAllocate(RequestType.SHUTDOWN) + + inline def zoneAllocate()(using Zone): ShutdownReq = + Req.zoneAllocate(RequestType.SHUTDOWN) + + inline def malloc(): ShutdownReq = + Req.malloc(RequestType.SHUTDOWN) + +} + opaque type WriteReq <: Req = Ptr[Byte] object WriteReq { @@ -100,6 +135,21 @@ object WriteReq { opaque type UdpSendReq <: Req = Ptr[Byte] +object UdpSendReq { + + given Tag[UdpSendReq] = Tag.Ptr(Tag.Byte) + + inline def stackAllocate(): UdpSendReq = + Req.stackAllocate(RequestType.UDP_SEND) + + inline def zoneAllocate()(using Zone): UdpSendReq = + Req.zoneAllocate(RequestType.UDP_SEND) + + inline def malloc(): UdpSendReq = + Req.malloc(RequestType.UDP_SEND) + +} + opaque type FileReq <: Req = Ptr[Byte] object FileReq { @@ -107,6 +157,12 @@ object FileReq { inline def stackAllocate(): FileReq = Req.stackAllocate(RequestType.FS) + inline def zoneAllocate()(using Zone): FileReq = + Req.zoneAllocate(RequestType.FS) + + inline def malloc(): FileReq = + Req.malloc(RequestType.FS) + /** Allocate a new file request on the stack, provide it to the specified * function, and clean it up after the function returns. Note this is only * safe to use for **blocking** FS operations. @@ -123,3 +179,52 @@ object FileReq { } opaque type WorkReq <: Req = Ptr[Byte] + +object WorkReq { + + given Tag[WorkReq] = Tag.Ptr(Tag.Byte) + + inline def stackAllocate(): WorkReq = + Req.stackAllocate(RequestType.WORK) + + inline def zoneAllocate()(using Zone): WorkReq = + Req.zoneAllocate(RequestType.WORK) + + inline def malloc(): WorkReq = + Req.malloc(RequestType.WORK) + +} + +opaque type GetAddrInfoReq <: Req = Ptr[Byte] + +object GetAddrInfoReq { + + given Tag[GetAddrInfoReq] = Tag.Ptr(Tag.Byte) + + inline def stackAllocate(): GetAddrInfoReq = + Req.stackAllocate(RequestType.GETADDRINFO) + + inline def zoneAllocate()(using Zone): GetAddrInfoReq = + Req.zoneAllocate(RequestType.GETADDRINFO) + + inline def malloc(): GetAddrInfoReq = + Req.malloc(RequestType.GETADDRINFO) + +} + +opaque type GetNameInfoReq <: Req = Ptr[Byte] + +object GetNameInfoReq { + + given Tag[GetNameInfoReq] = Tag.Ptr(Tag.Byte) + + inline def stackAllocate(): GetNameInfoReq = + Req.stackAllocate(RequestType.GETNAMEINFO) + + inline def zoneAllocate()(using Zone): GetNameInfoReq = + Req.zoneAllocate(RequestType.GETNAMEINFO) + + inline def malloc(): GetNameInfoReq = + Req.malloc(RequestType.GETNAMEINFO) + +} diff --git a/src/main/scala/scalauv/UvUtils.scala b/src/main/scala/scalauv/UvUtils.scala index 0040bfe..f603a94 100644 --- a/src/main/scala/scalauv/UvUtils.scala +++ b/src/main/scala/scalauv/UvUtils.scala @@ -10,8 +10,23 @@ import java.nio.charset.Charset import scala.util.control.NonFatal import scala.collection.mutable.Stack +/** More convenient Scala 3 version of a `Zone` block. Instead of `Zone { + * implicit zone => f }` you can use `withZone { f }`. + * + * @param f + * The function that requires a given `Zone`. + */ inline def withZone[A](f: Zone ?=> A): A = Zone(z => f(using z)) +/** Converts a Scala string to a native C string allocated using `malloc`. + * + * @param s + * The Scala string. + * @param charset + * The character set to use to encode the C string, defaults to UTF8. + * @return + * A pointer to the C string allocated with `malloc`. + */ def mallocCString( s: String, charset: Charset = StandardCharsets.UTF_8 @@ -27,11 +42,15 @@ def mallocCString( } } +/** Useful utilities to make it easier to use libuv from Scala. + */ object UvUtils { private val ErrorCodeNameMax: CSize = 80.toUInt - inline def errorName(errorCode: CInt): String = { + /** Gets the name of a libuv error code as a Scala string. + */ + inline def errorName(errorCode: ErrorCode): String = { val cString = stackalloc[Byte](ErrorCodeNameMax) LibUv.uv_err_name_r(errorCode, cString, ErrorCodeNameMax) fromCString(cString) @@ -39,12 +58,16 @@ object UvUtils { private val ErrorCodeMessageMex: CSize = 200.toUInt + /** Gets the error message for a libuv error code as a Scala string. + */ inline def errorMessage(errorCode: ErrorCode): String = withZone { val cString = alloc[Byte](ErrorCodeMessageMex) LibUv.uv_strerror_r(errorCode, cString, ErrorCodeMessageMex) fromCString(cString) } + /** Gets the name and message for a libuv error code in a single Scala string. + */ def errorNameAndMessage(errorCode: ErrorCode): String = withZone { val cString = alloc[Byte](ErrorCodeMessageMex) LibUv.uv_err_name_r(errorCode, cString, ErrorCodeMessageMex) @@ -74,6 +97,13 @@ object UvUtils { case success => Some(success) } + /** Accumulates cleanup operations in an "attempt" block. + * + * @see + * [[scalauv.UvUtils.attempt]] + * @see + * [[scalauv.UvUtils.attemptCatch]] + */ final class Cleanup private[UvUtils] () { private val onCompleteActions = Stack.empty[Option[Throwable] => Unit] @@ -93,6 +123,25 @@ object UvUtils { } + /** Attempts to run a block of code, allowing cleanup operations to be + * registered. The passed function receives `Cleanup` as context, allowing it + * to register cleanup via `onFail` and `onComplete`. If `f` throws an + * exception, any cleanup operations registered so far will be run in reverse + * order. This function requires catching all thrown exceptions, and is + * designed for use where exceptions cannot be thrown any further up the call + * stack, such as native C function pointers. + * + * @see + * [[scalauv.UvUtils.onFail]] + * @see + * [[scalauv.UvUtils.onComplete]] + * + * @param f + * The operation to attempt. + * @param handleError + * A function to handle any exceptions that are thrown. + * @return + */ def attemptCatch[A](f: Cleanup ?=> A)(handleError: Throwable => A): A = { given cleanup: Cleanup = Cleanup() try f @@ -103,6 +152,21 @@ object UvUtils { } finally cleanup.completed(None) } + /** Attempts to run a block of code, allowing cleanup operations to be + * registered. The passed function receives `Cleanup` as context, allowing it + * to register cleanup via `onFail` and `onComplete`. If `f` throws an + * exception, any cleanup operations registered so far will be run in reverse + * order. After cleanup is run, the exception is propagated up the call + * stack. + * + * @see + * [[scalauv.UvUtils.onFail]] + * @see + * [[scalauv.UvUtils.onComplete]] + * + * @param f + * The operation to attempt. + */ def attempt[A](f: Cleanup ?=> A): A = { given cleanup: Cleanup = Cleanup() try f @@ -113,12 +177,28 @@ object UvUtils { } finally cleanup.completed(None) } + /** Register a cleanup operation to be run if the code block fails. + * + * @param f + * A cleanup operation that receives the failure exception. + */ inline def onFailWith(f: Throwable => Unit)(using cleanup: Cleanup): Unit = cleanup.addOnErrorAction(f) + /** Register a cleanup operation to be run if the code block fails. + * + * @param f + * A cleanup operation. + */ inline def onFail(f: => Unit)(using Cleanup): Unit = onFailWith(_ => f) + /** Register a cleanup operation to be run when the code block completes, + * whether successful or not. + * + * @param f + * A cleanup operation. + */ inline def onComplete(f: => Unit)(using cleanup: Cleanup): Unit = cleanup.addOnCompleteAction(_ => f) @@ -135,9 +215,24 @@ extension (uvResult: CInt) { inline def checkErrorThrow(f: String => Exception): CInt = UvUtils.checkErrorThrow(uvResult)(f) + /** Checks the result of a libuv operation, and throws an `IOException` if the + * result indicates failure. + * + * @throws java.io.IOException + * if the result is < 0 + * @return + * the result if it is >= 0 + */ inline def checkErrorThrowIO(): CInt = UvUtils.checkErrorThrowIO(uvResult) + /** Performs an action only if the result indicates failure. + * + * @param f + * The operation to perform on failure. + * @return + * The result. + */ inline def onFail(f: => Unit): CInt = { if uvResult < 0 then f uvResult diff --git a/src/main/scala/scalauv/errors.scala b/src/main/scala/scalauv/errors.scala index a9b4fd6..58ba586 100644 --- a/src/main/scala/scalauv/errors.scala +++ b/src/main/scala/scalauv/errors.scala @@ -2,8 +2,14 @@ package scalauv import scala.scalanative.unsafe.* +/** Type alias for native C integer, which is returned by all libuv functions + * that can fail to indicate the error. If the result is < 0, then it is an + * error code. + */ type ErrorCode = CInt +/** All possible error codes that libuv functions can return. + */ object ErrorCodes { import errors.* diff --git a/src/main/scala/scalauv/helpers.scala b/src/main/scala/scalauv/helpers.scala index aa2eb1c..395e834 100644 --- a/src/main/scala/scalauv/helpers.scala +++ b/src/main/scala/scalauv/helpers.scala @@ -13,8 +13,12 @@ private[scalauv] object helpers { def scala_uv_buf_base(buffer: Ptr[Byte]): Ptr[Byte] = extern + def scala_uv_buf_base_set(buffer: Ptr[Byte], base: Ptr[Byte]): Unit = extern + def scala_uv_buf_len(buffer: Ptr[Byte]): CSize = extern + def scala_uv_buf_len_set(buffer: Ptr[Byte], len: CSize): Unit = extern + def scala_uv_buf_struct_size(): CSize = extern def scala_uv_mutex_t_size(): CSize = extern diff --git a/src/main/scala/Main.scala b/src/main/scala/scalauv/main/Main.scala similarity index 51% rename from src/main/scala/Main.scala rename to src/main/scala/scalauv/main/Main.scala index 9062030..c6648b1 100644 --- a/src/main/scala/Main.scala +++ b/src/main/scala/scalauv/main/Main.scala @@ -1,42 +1,11 @@ -import scalauv.* +package scalauv +package main import scala.scalanative.* import unsafe.* import unsigned.* import LibUv.* -final class Test { - - private var done = false - - def callback: AsyncCallback = { (handle: AsyncHandle) => - println("Callback!!") - done = true - uv_close(handle, null) - } - - def run() = { - - withZone { - - val loop = uv_default_loop() - - val asyncHandle = AsyncHandle.zoneAllocate() - uv_async_init(loop, asyncHandle, callback).checkErrorThrowIO() - - uv_async_send(asyncHandle).checkErrorThrowIO() - - println(s"Test before, done = $done") - uv_run(loop, RunMode.DEFAULT).checkErrorThrowIO() - println(s"Test after, done = $done") - } - - } - -} - -object Test - object Main { private var done = false @@ -61,9 +30,6 @@ object Main { uv_run(loop, RunMode.DEFAULT).checkErrorThrowIO() println(s"Main after, done = $done") } - - // val test = new Test - // test.run() } } diff --git a/src/test/scala/scalauv/TcpSpec.scala b/src/test/scala/scalauv/TcpSpec.scala index b4967b7..dddda93 100644 --- a/src/test/scala/scalauv/TcpSpec.scala +++ b/src/test/scala/scalauv/TcpSpec.scala @@ -136,8 +136,8 @@ object TcpSpec { uv_close(handle, onClose) setFailed(UvUtils.errorMessage(code.toInt)) case _ => - val (text, done) = - buf.asUtf8String(numRead.toInt).span(_ != DoneMarker) + buf.length = numRead.toInt + val (text, done) = buf.asUtf8String.span(_ != DoneMarker) recordReceived(text) if done.nonEmpty then { val listenHandle = Handle.unsafeFromPtr(uv_handle_get_data(handle))