src: move methods to separate read-only structure

This commit is contained in:
Fedor Indutny 2016-05-26 02:50:14 -04:00
parent efbf1ba323
commit 27b6c247c5
8 changed files with 129 additions and 58 deletions

View File

@ -1,7 +1,37 @@
# uv_link_t
[![Build Status](https://secure.travis-ci.org/indutny/uv_link_t.png)](http://travis-ci.org/indutny/uv_link_t)
WIP
**HIGHLY UNSTABLE**
Chainable [libuv][0] streams.
## Why?
It is quite easy to write a TCP server/client in [libuv][0]. Writing HTTP
server/client is a bit harder. Writing HTTP server/client on top of TLS server
could be unwieldy.
`uv_link_t` aims to solve complexity problem that quickly escalates once using
multiple layers of protocols in [libuv][0] by providing a way to implement
protocols separately and chain them together in easy and high-performant way
using very narrow interfaces.
## How?
_(NOTE: chain is built from links)_
_(NOTE: many of these API methods have return values, check them!)_
First, a `uv_stream_t*` instance needs to be picked. It will act as a source
link in a chain:
```c
uv_stream_t* stream = ...;
uv_link_source_t source;
uv_link_source_init(uv_default_loop(), &source, stream);
```
To be continued
## LICENSE
@ -27,3 +57,5 @@ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
[0]: https://github.com/libuv/libuv

View File

@ -36,6 +36,10 @@
}
},
"cflags": [
"-Wno-unused-function",
],
"xcode_settings": {
"GCC_VERSION": "com.apple.compilers.llvm.clang.1_0",
"GCC_WARN_ABOUT_MISSING_NEWLINE": "YES", # -Wnewline-eof
@ -49,6 +53,7 @@
"-Wendif-labels",
"-W",
"-Wno-unused-parameter",
"-Wno-unused-function",
"-Wundeclared-selector",
"-Wno-parentheses-equality",
],

View File

@ -4,6 +4,7 @@
#include "uv.h"
typedef struct uv_link_s uv_link_t;
typedef struct uv_link_methods_s uv_link_methods_t;
typedef struct uv_link_source_s uv_link_source_t;
typedef struct uv_link_observer_s uv_link_observer_t;
@ -16,16 +17,7 @@ typedef void (*uv_link_read_cb)(uv_link_t* link,
typedef void (*uv_link_write_cb)(uv_link_t* link, int status);
typedef void (*uv_link_shutdown_cb)(uv_link_t* link, int status);
struct uv_link_s {
uv_link_t* parent;
uv_link_t* child;
uv_link_alloc_cb alloc_cb;
uv_link_read_cb read_cb;
/* Read-only after assigning initial values */
/* Sort of virtual table */
struct uv_link_methods_s {
int (*read_start)(uv_link_t* link);
int (*read_stop)(uv_link_t* link);
@ -39,13 +31,26 @@ struct uv_link_s {
unsigned int nbufs);
int (*shutdown)(uv_link_t* link, uv_link_shutdown_cb cb);
};
struct uv_link_s {
uv_link_t* parent;
uv_link_t* child;
uv_link_alloc_cb alloc_cb;
uv_link_read_cb read_cb;
/* Read-only after assigning initial values */
/* Sort of virtual table */
uv_link_methods_t const* methods;
/* Private, used for chain/unchain */
uv_link_alloc_cb saved_alloc_cb;
uv_link_read_cb saved_read_cb;
};
UV_EXTERN int uv_link_init(uv_loop_t* loop, uv_link_t* link);
UV_EXTERN int uv_link_init(uv_link_t* link, uv_link_methods_t const* methods);
UV_EXTERN void uv_link_close(uv_link_t* link);
UV_EXTERN int uv_link_chain(uv_link_t* from,
@ -54,7 +59,7 @@ UV_EXTERN int uv_link_chain(uv_link_t* from,
uv_link_read_cb read_cb);
UV_EXTERN int uv_link_unchain(uv_link_t* from, uv_link_t* to);
/* Invoke read_cb and alloc_cb with proper link */
/* Use this to invoke methods */
UV_EXTERN void uv_link_invoke_alloc_cb(uv_link_t* link,
size_t suggested_size,
uv_buf_t* buf);
@ -62,6 +67,33 @@ UV_EXTERN void uv_link_invoke_read_cb(uv_link_t* link,
ssize_t nread,
const uv_buf_t* buf);
static int uv_link_read_start(uv_link_t* link) {
return link->methods->read_start(link);
}
static int uv_link_read_stop(uv_link_t* link) {
return link->methods->read_stop(link);
}
static int uv_link_write(uv_link_t* link,
const uv_buf_t bufs[],
unsigned int nbufs,
uv_stream_t* send_handle,
uv_link_write_cb cb) {
return link->methods->write(link, bufs, nbufs, send_handle, cb);
}
static int uv_link_try_write(uv_link_t* link,
const uv_buf_t bufs[],
unsigned int nbufs) {
return link->methods->try_write(link, bufs, nbufs);
}
static int uv_link_shutdown(uv_link_t* link, uv_link_shutdown_cb cb) {
return link->methods->shutdown(link, cb);
}
/* Source */
struct uv_link_source_s {
@ -71,8 +103,7 @@ struct uv_link_source_s {
};
/* NOTE: uses `stream->data` field */
UV_EXTERN int uv_link_source_init(uv_loop_t* loop,
uv_link_source_t* source,
UV_EXTERN int uv_link_source_init(uv_link_source_t* source,
uv_stream_t* stream);
UV_EXTERN void uv_link_source_close(uv_link_source_t* source);
@ -88,8 +119,7 @@ struct uv_link_observer_s {
const uv_buf_t* buf);
};
UV_EXTERN int uv_link_observer_init(uv_loop_t* loop,
uv_link_observer_t* observer,
UV_EXTERN int uv_link_observer_init(uv_link_observer_t* observer,
uv_link_t* target);
UV_EXTERN int uv_link_observer_close(uv_link_observer_t* observer);

View File

@ -9,7 +9,7 @@ static int uv_link_observer_read_start(uv_link_t* link) {
observer = container_of(link, uv_link_observer_t, link);
return observer->target->read_start(observer->target);
return uv_link_read_start(observer->target);
}
@ -18,7 +18,7 @@ static int uv_link_observer_read_stop(uv_link_t* link) {
observer = container_of(link, uv_link_observer_t, link);
return observer->target->read_stop(observer->target);
return uv_link_read_stop(observer->target);
}
@ -31,7 +31,7 @@ static int uv_link_observer_write(uv_link_t* link,
observer = container_of(link, uv_link_observer_t, link);
return observer->target->write(observer->target, bufs, nbufs, send_handle, cb);
return uv_link_write(observer->target, bufs, nbufs, send_handle, cb);
}
@ -42,7 +42,7 @@ static int uv_link_observer_try_write(uv_link_t* link,
observer = container_of(link, uv_link_observer_t, link);
return observer->target->try_write(observer->target, bufs, nbufs);
return uv_link_try_write(observer->target, bufs, nbufs);
}
@ -51,7 +51,7 @@ static int uv_link_observer_shutdown(uv_link_t* link, uv_link_shutdown_cb cb) {
observer = container_of(link, uv_link_observer_t, link);
return observer->target->shutdown(observer->target, cb);
return uv_link_shutdown(observer->target, cb);
}
@ -76,29 +76,28 @@ static void uv_link_observer_read_cb(uv_link_t* link,
}
int uv_link_observer_init(uv_loop_t* loop,
uv_link_observer_t* observer,
static uv_link_methods_t uv_link_observer_methods = {
.read_start = uv_link_observer_read_start,
.read_stop = uv_link_observer_read_stop,
.write = uv_link_observer_write,
.try_write = uv_link_observer_try_write,
.shutdown = uv_link_observer_shutdown
};
int uv_link_observer_init(uv_link_observer_t* observer,
uv_link_t* target) {
int err;
uv_link_t* l;
memset(observer, 0, sizeof(*observer));
err = uv_link_init(loop, &observer->link);
err = uv_link_init(&observer->link, &uv_link_observer_methods);
if (err != 0)
return err;
observer->target = target;
l = &observer->link;
l->read_start = uv_link_observer_read_start;
l->read_stop = uv_link_observer_read_stop;
l->write = uv_link_observer_write;
l->try_write = uv_link_observer_try_write;
l->shutdown = uv_link_observer_shutdown;
err = uv_link_chain(target, l, uv_link_observer_alloc_cb,
err = uv_link_chain(target, &observer->link, uv_link_observer_alloc_cb,
uv_link_observer_read_cb);
if (err != 0) {
uv_link_close(&observer->link);

View File

@ -129,28 +129,28 @@ static int uv_link_source_shutdown(uv_link_t* link, uv_link_shutdown_cb cb) {
}
int uv_link_source_init(uv_loop_t* loop,
uv_link_source_t* source,
static uv_link_methods_t uv_link_source_methods = {
.read_start = uv_link_source_read_start,
.read_stop = uv_link_source_read_stop,
.write = uv_link_source_write,
.try_write = uv_link_source_try_write,
.shutdown = uv_link_source_shutdown
};
int uv_link_source_init(uv_link_source_t* source,
uv_stream_t* stream) {
int err;
uv_link_t* l;
memset(source, 0, sizeof(*source));
err = uv_link_init(loop, &source->link);
err = uv_link_init(&source->link, &uv_link_source_methods);
if (err != 0)
return err;
source->stream = stream;
source->stream->data = source;
l = &source->link;
l->read_start = uv_link_source_read_start;
l->read_stop = uv_link_source_read_stop;
l->write = uv_link_source_write;
l->try_write = uv_link_source_try_write;
l->shutdown = uv_link_source_shutdown;
return 0;
}

View File

@ -22,17 +22,22 @@ static void uv_link_def_read_cb(uv_link_t* link,
}
int uv_link_init(uv_loop_t* loop, uv_link_t* link) {
int uv_link_init(uv_link_t* link, uv_link_methods_t const* methods) {
memset(link, 0, sizeof(*link));
link->alloc_cb = uv_link_def_alloc_cb;
link->read_cb = uv_link_def_read_cb;
link->methods = methods;
return 0;
}
void uv_link_close(uv_link_t* link) {
link->alloc_cb = NULL;
link->read_cb = NULL;
link->methods = NULL;
}

View File

@ -3,12 +3,15 @@
#include "test-common.h"
static uv_loop_t* loop;
static uv_link_t source;
static uv_link_observer_t observer;
static int observer_read_cb_called;
static uv_link_methods_t methods = {
/* no-op, won't be called */
};
static void observer_read_cb(uv_link_observer_t* o,
ssize_t nread,
const uv_buf_t* buf) {
@ -23,12 +26,9 @@ static void observer_read_cb(uv_link_observer_t* o,
TEST_IMPL(uv_link_observer_t) {
uv_buf_t buf;
loop = uv_default_loop();
CHECK_NE(loop, NULL, "uv_default_loop()");
CHECK_EQ(uv_link_init(&source, &methods), 0, "uv_link_init(source)");
CHECK_EQ(uv_link_init(loop, &source), 0, "uv_link_init(source)");
CHECK_EQ(uv_link_observer_init(loop, &observer, &source), 0,
CHECK_EQ(uv_link_observer_init(&observer, &source), 0,
"uv_link_observer_init()");
observer.read_cb = observer_read_cb;

View File

@ -38,7 +38,7 @@ static void test_writes() {
/* .write() should work */
buf = uv_buf_init("x", 1);
CHECK_EQ(source.link.write(&source.link, &buf, 1, NULL, source_write_cb), 0,
CHECK_EQ(uv_link_write(&source.link, &buf, 1, NULL, source_write_cb), 0,
"source.link.write() should return 0");
CHECK_EQ(uv_run(loop, UV_RUN_DEFAULT), 0, "uv_run()");
@ -46,7 +46,7 @@ static void test_writes() {
CHECK_EQ(write_cb_called, 1, "source_write_cb() must be called");
/* .try_write() should work too */
CHECK_EQ(source.link.try_write(&source.link, &buf, 1), 1,
CHECK_EQ(uv_link_try_write(&source.link, &buf, 1), 1,
"source.link.try_write() should return 1");
read_one();
}
@ -75,7 +75,7 @@ static void source_read_cb(uv_link_t* link,
CHECK_EQ(nread, 1, "source_read_cb must read one byte");
CHECK_EQ(buf->base[0], 'x', "source_read_cb must read correct one byte");
CHECK_EQ(source.link.read_stop(&source.link), 0, "source.link.read_stop()");
CHECK_EQ(uv_link_read_stop(&source.link), 0, "source.link.read_stop()");
}
@ -91,7 +91,7 @@ static void test_reads() {
while (err == -1 && errno == EINTR);
CHECK_EQ(err, 1, "write() == 1");
CHECK_EQ(source.link.read_start(&source.link), 0, "source.link.read_start()");
CHECK_EQ(uv_link_read_start(&source.link), 0, "source.link.read_start()");
CHECK_EQ(uv_run(loop, UV_RUN_DEFAULT), 0, "uv_run()");
CHECK_EQ(alloc_cb_called, 1, "alloc_cb must be called once");
@ -108,7 +108,7 @@ TEST_IMPL(uv_link_source_t) {
CHECK_EQ(uv_pipe_init(loop, &pair_right, 0), 0, "uv_pipe_init(pair_right)");
CHECK_EQ(uv_pipe_open(&pair_right, fds[1]), 0, "uv_pipe_open(pair_right)");
CHECK_EQ(uv_link_source_init(loop, &source, (uv_stream_t*) &pair_right), 0,
CHECK_EQ(uv_link_source_init(&source, (uv_stream_t*) &pair_right), 0,
"uv_link_source_init()");
test_writes();