src: move methods to separate read-only structure
This commit is contained in:
parent
efbf1ba323
commit
27b6c247c5
34
README.md
34
README.md
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
],
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue