From 27b6c247c5a19e0fe812c9fc9df1a56d5350ade7 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Thu, 26 May 2016 02:50:14 -0400 Subject: [PATCH] src: move methods to separate read-only structure --- README.md | 34 +++++++++++++++- common.gypi | 5 +++ include/uv_link_t.h | 62 ++++++++++++++++++++++-------- src/uv_link_observer_t.c | 35 ++++++++--------- src/uv_link_source_t.c | 22 +++++------ src/uv_link_t.c | 7 +++- test/src/test-uv-link-observer-t.c | 12 +++--- test/src/test-uv-link-source-t.c | 10 ++--- 8 files changed, 129 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index 7ca737d..041c41b 100644 --- a/README.md +++ b/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 diff --git a/common.gypi b/common.gypi index 3a9c481..dd1b08c 100644 --- a/common.gypi +++ b/common.gypi @@ -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", ], diff --git a/include/uv_link_t.h b/include/uv_link_t.h index 19b67ce..738c19f 100644 --- a/include/uv_link_t.h +++ b/include/uv_link_t.h @@ -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); diff --git a/src/uv_link_observer_t.c b/src/uv_link_observer_t.c index 2042dcb..cd389f6 100644 --- a/src/uv_link_observer_t.c +++ b/src/uv_link_observer_t.c @@ -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); diff --git a/src/uv_link_source_t.c b/src/uv_link_source_t.c index ff2af73..11907cc 100644 --- a/src/uv_link_source_t.c +++ b/src/uv_link_source_t.c @@ -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; } diff --git a/src/uv_link_t.c b/src/uv_link_t.c index df23dcd..769b269 100644 --- a/src/uv_link_t.c +++ b/src/uv_link_t.c @@ -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; } diff --git a/test/src/test-uv-link-observer-t.c b/test/src/test-uv-link-observer-t.c index cb4026d..3edf9ea 100644 --- a/test/src/test-uv-link-observer-t.c +++ b/test/src/test-uv-link-observer-t.c @@ -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; diff --git a/test/src/test-uv-link-source-t.c b/test/src/test-uv-link-source-t.c index 64ab200..404543a 100644 --- a/test/src/test-uv-link-source-t.c +++ b/test/src/test-uv-link-source-t.c @@ -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();