This library provides ease of use convenience wrappers for libuv combined with the power of c-raii, a high level memory management library similar to other languages, among other features. Like coroutine support, the otherwise callback needed, is now automatically back to the caller with results.
- All functions requiring allocation and passing pointers, now returns them instead, if needed.
- The general naming convention is to drop
uv_prefix and require only necessary arguments/options. - This integration also requires the use of
uv_main(int argc, char **argv)
as the startup entry routine:
libuv example from https://github.com/libuv/libuv/tree/master/docs/code/
helloworld.c | helloworld/main.c |
---|---|
#include "uv_coro.h"
int uv_main(int argc, char **argv) {
printf("Now quitting.\n");
yielding();
return coro_err_code();
} |
#include <stdio.h>
#include <stdlib.h>
#include <uv.h>
int main() {
uv_loop_t *loop = malloc(sizeof(uv_loop_t));
uv_loop_init(loop);
printf("Now quitting.\n");
uv_run(loop, UV_RUN_DEFAULT);
uv_loop_close(loop);
free(loop);
return 0;
} |
This general means there will be a dramatic reduction of lines of code repeated, repeatedly.
Libuv guides/examples:
- Reading/Writing files as in uvcat/main.c - 62 line script.
- Buffers and Streams as in uvtee/main.c - 79 line script.
- Networking/TCP as in tcp-echo-server/main.c - 87 line script.
Reduced to:
uvcat.c - 13 lines | uvtee.c - 20 lines |
---|---|
#include "uv_coro.h"
int uv_main(int argc, char **argv) {
uv_file fd = fs_open(argv[1], O_RDONLY, 0);
if (fd > 0) {
string text = fs_read(fd, -1);
fs_write(STDOUT_FILENO, text, -1);
return fs_close(fd);
}
return fd;
} |
#include "uv_coro.h"
int uv_main(int argc, char **argv) {
string text = nullptr;
uv_file fd = fs_open(argv[1], O_CREAT | O_RDWR, 0644);
if (fd > 0) {
pipe_file_t *file_pipe = pipe_file(fd, false);
pipe_out_t *stdout_pipe = pipe_stdout(false);
pipe_in_t *stdin_pipe = pipe_stdin(false);
while (text = stream_read(stdin_pipe->reader)) {
if (stream_write(stdout_pipe->writer, text)
|| stream_write(file_pipe->handle, text))
break;
}
return fs_close(fd);
}
return fd;
} |
tcp-echo-server.c - 27 lines |
---|
#include "uv_coro.h"
#define DEFAULT_PORT 7000
#define DEFAULT_BACKLOG 128
void new_connection(uv_stream_t *socket) {
string data = stream_read(socket);
stream_write(socket, data);
}
int uv_main(int argc, char **argv) {
uv_stream_t *client, *server;
char addr[UV_MAXHOSTNAMESIZE] = nil;
if (snprintf(addr, sizeof(addr), "0.0.0.0:%d", DEFAULT_PORT)) {
server = stream_bind(addr, 0);
while (server) {
if (is_empty(client = stream_listen(server, DEFAULT_BACKLOG))) {
fprintf(stderr, "Listen error %s\n", uv_strerror(coro_err_code()));
break;
}
stream_handler(new_connection, client);
}
}
return coro_err_code();
} |
See branches
for previous setup, main
is an complete makeover of previous implementation approaches.
Similar approach has been made for C++20, an implementation in uvco. The tests presented there currently being reimplemented for C89 here, this project will be considered stable when completed. And another approach in libasync mixing libco with libuv. Both approaches are Linux only.
The build system uses cmake, that produces static libraries by default.
Linux
mkdir build
cd build
cmake .. -D CMAKE_BUILD_TYPE=Debug/Release -D BUILD_EXAMPLES=ON -D BUILD_TESTS=ON # use to build files in tests/examples folder
cmake --build .
Windows
mkdir build
cd build
cmake .. -D BUILD_EXAMPLES=ON -D BUILD_TESTS=ON # use to build files in tests/examples folder
cmake --build . --config Debug/Release
Contributions are encouraged and welcome; I am always happy to get feedback or pull requests on Github :) Create Github Issues for bugs and new features and comment on the ones you are interested in.
The MIT License (MIT). Please see License File for more information.