diff options
author | Josh Haberman <haberman@google.com> | 2013-02-15 16:27:18 -0800 |
---|---|---|
committer | Josh Haberman <haberman@google.com> | 2013-02-15 16:27:18 -0800 |
commit | 7d3e2bd2c4cfd1296d1d6f996d7548de26540d41 (patch) | |
tree | b4b35967b3322c65cfb1a32220e8718de09d85fc /upb/sink.c | |
parent | ea198bdcf947ba4bd51474bdd4f7b82b5e4cf41d (diff) |
Sync with 8 months of Google-internal development.
Many things have changed and been simplified.
The memory-management story for upb_def and upb_handlers
is much more robust; upb_def and upb_handlers should be
fairly stable interfaces now. There is still much work
to do for the runtime component (upb_sink).
Diffstat (limited to 'upb/sink.c')
-rw-r--r-- | upb/sink.c | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/upb/sink.c b/upb/sink.c new file mode 100644 index 0000000..d829fa9 --- /dev/null +++ b/upb/sink.c @@ -0,0 +1,205 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2011-2012 Google Inc. See LICENSE for details. + * Author: Josh Haberman <jhaberman@gmail.com> + */ + +#include "upb/sink.h" + +static bool chkstack(upb_sink *s) { + if (s->top + 1 >= s->limit) { + upb_status_seterrliteral(&s->status, "Nesting too deep."); + return false; + } else { + return true; + } +} + +static upb_selector_t getselector(const upb_fielddef *f, + upb_handlertype_t type) { + upb_selector_t selector; + bool ok = upb_getselector(f, type, &selector); + UPB_ASSERT_VAR(ok, ok); + return selector; +} + +void upb_sink_init(upb_sink *s, const upb_handlers *h) { + s->limit = &s->stack[UPB_MAX_NESTING]; + s->top = NULL; + s->stack[0].h = h; + upb_status_init(&s->status); +} + +void upb_sink_reset(upb_sink *s, void *closure) { + s->top = s->stack; + s->top->closure = closure; +} + +void upb_sink_uninit(upb_sink *s) { + upb_status_uninit(&s->status); +} + +bool upb_sink_startmsg(upb_sink *s) { + const upb_handlers *h = s->top->h; + upb_startmsg_handler *startmsg = upb_handlers_getstartmsg(h); + return startmsg ? startmsg(s->top->closure) : true; +} + +void upb_sink_endmsg(upb_sink *s, upb_status *status) { + UPB_UNUSED(status); + assert(s->top == s->stack); + upb_endmsg_handler *endmsg = upb_handlers_getendmsg(s->top->h); + if (endmsg) endmsg(s->top->closure, &s->status); +} + +#define PUTVAL(type, ctype, htype) \ + bool upb_sink_put ## type(upb_sink *s, const upb_fielddef *f, ctype val) { \ + upb_selector_t selector; \ + if (!upb_getselector(f, UPB_HANDLER_ ## htype, &selector)) return false; \ + upb_ ## type ## _handler *handler = (upb_ ## type ## _handler*) \ + upb_handlers_gethandler(s->top->h, selector); \ + if (handler) { \ + void *data = upb_handlers_gethandlerdata(s->top->h, selector); \ + if (!handler(s->top->closure, data, val)) return false; \ + } \ + return true; \ + } + +PUTVAL(int32, int32_t, INT32); +PUTVAL(int64, int64_t, INT64); +PUTVAL(uint32, uint32_t, UINT32); +PUTVAL(uint64, uint64_t, UINT64); +PUTVAL(float, float, FLOAT); +PUTVAL(double, double, DOUBLE); +PUTVAL(bool, bool, BOOL); +#undef PUTVAL + +size_t upb_sink_putstring(upb_sink *s, const upb_fielddef *f, + const char *buf, size_t n) { + upb_selector_t selector; + if (!upb_getselector(f, UPB_HANDLER_STRING, &selector)) return false; + upb_string_handler *handler = (upb_string_handler*) + upb_handlers_gethandler(s->top->h, selector); + if (handler) { + void *data = upb_handlers_gethandlerdata(s->top->h, selector); \ + return handler(s->top->closure, data, buf, n); + } + return n; +} + +bool upb_sink_startseq(upb_sink *s, const upb_fielddef *f) { + assert(upb_fielddef_isseq(f)); + if (!chkstack(s)) return false; + + void *subc = s->top->closure; + const upb_handlers *h = s->top->h; + upb_selector_t selector; + if (!upb_getselector(f, UPB_HANDLER_STARTSEQ, &selector)) return false; + upb_startfield_handler *startseq = + (upb_startfield_handler*)upb_handlers_gethandler(h, selector); + if (startseq) { + subc = startseq(s->top->closure, upb_handlers_gethandlerdata(h, selector)); + if (!subc) return false; + } + + ++s->top; + s->top->end = getselector(f, UPB_HANDLER_ENDSEQ); + s->top->h = h; + s->top->closure = subc; + return true; +} + +bool upb_sink_endseq(upb_sink *s, const upb_fielddef *f) { + upb_selector_t selector = s->top->end; + assert(selector == getselector(f, UPB_HANDLER_ENDSEQ)); + --s->top; + + const upb_handlers *h = s->top->h; + upb_endfield_handler *endseq = + (upb_endfield_handler*)upb_handlers_gethandler(h, selector); + return endseq ? + endseq(s->top->closure, upb_handlers_gethandlerdata(h, selector)) : + true; +} + +bool upb_sink_startstr(upb_sink *s, const upb_fielddef *f, size_t size_hint) { + assert(upb_fielddef_isstring(f)); + if (!chkstack(s)) return false; + + void *subc = s->top->closure; + const upb_handlers *h = s->top->h; + upb_selector_t selector; + if (!upb_getselector(f, UPB_HANDLER_STARTSTR, &selector)) return false; + upb_startstr_handler *startstr = + (upb_startstr_handler*)upb_handlers_gethandler(h, selector); + if (startstr) { + subc = startstr( + s->top->closure, upb_handlers_gethandlerdata(h, selector), size_hint); + if (!subc) return false; + } + + ++s->top; + s->top->end = getselector(f, UPB_HANDLER_ENDSTR); + s->top->h = h; + s->top->closure = subc; + return true; +} + +bool upb_sink_endstr(upb_sink *s, const upb_fielddef *f) { + upb_selector_t selector = s->top->end; + assert(selector == getselector(f, UPB_HANDLER_ENDSTR)); + --s->top; + + const upb_handlers *h = s->top->h; + upb_endfield_handler *endstr = + (upb_endfield_handler*)upb_handlers_gethandler(h, selector); + return endstr ? + endstr(s->top->closure, upb_handlers_gethandlerdata(h, selector)) : + true; +} + +bool upb_sink_startsubmsg(upb_sink *s, const upb_fielddef *f) { + assert(upb_fielddef_issubmsg(f)); + if (!chkstack(s)) return false; + + const upb_handlers *h = s->top->h; + upb_selector_t selector; + if (!upb_getselector(f, UPB_HANDLER_STARTSUBMSG, &selector)) return false; + upb_startfield_handler *startsubmsg = + (upb_startfield_handler*)upb_handlers_gethandler(h, selector); + void *subc = s->top->closure; + + if (startsubmsg) { + void *data = upb_handlers_gethandlerdata(h, selector); + subc = startsubmsg(s->top->closure, data); + if (!subc) return false; + } + + ++s->top; + s->top->end = getselector(f, UPB_HANDLER_ENDSUBMSG); + s->top->h = upb_handlers_getsubhandlers(h, f); + s->top->closure = subc; + upb_sink_startmsg(s); + return true; +} + +bool upb_sink_endsubmsg(upb_sink *s, const upb_fielddef *f) { + upb_selector_t selector = s->top->end; + assert(selector == getselector(f, UPB_HANDLER_ENDSUBMSG)); + + upb_endmsg_handler *endmsg = upb_handlers_getendmsg(s->top->h); + if (endmsg) endmsg(s->top->closure, &s->status); + --s->top; + + const upb_handlers *h = s->top->h; + upb_endfield_handler *endfield = + (upb_endfield_handler*)upb_handlers_gethandler(h, selector); + return endfield ? + endfield(s->top->closure, upb_handlers_gethandlerdata(h, selector)) : + true; +} + +const upb_handlers *upb_sink_tophandlers(upb_sink *s) { + return s->top->h; +} |