diff options
author | Joshua Haberman <joshua@reverberate.org> | 2011-02-25 18:31:22 -0800 |
---|---|---|
committer | Joshua Haberman <joshua@reverberate.org> | 2011-02-25 18:31:22 -0800 |
commit | a75a305c77acd6800b81204f387f7a437a62fe6b (patch) | |
tree | dbd83530befface0868b7fdca37769590b61d5ed /src/upb_msg.c | |
parent | abfc897b50532e5ed64f7f5497f80ef56abd3b26 (diff) |
Implemented upb_stringsink, upb_msgtotext, and exposed the latter to Lua.
Diffstat (limited to 'src/upb_msg.c')
-rw-r--r-- | src/upb_msg.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/src/upb_msg.c b/src/upb_msg.c index 89913dd..a3fd825 100644 --- a/src/upb_msg.c +++ b/src/upb_msg.c @@ -180,6 +180,77 @@ upb_value upb_msg_get(upb_msg *msg, upb_fielddef *f) { } } +static upb_flow_t upb_msg_dispatch(upb_msg *msg, upb_msgdef *md, + upb_dispatcher *d, upb_status *s); + +static upb_flow_t upb_msg_pushval(upb_value val, upb_fielddef *f, + upb_dispatcher *d, upb_status *s) { +#define CHECK_FLOW(x) do { \ + flow = x; if (flow != UPB_CONTINUE) return flow; \ + } while(0) + +// For when a SKIP can be implemented just through an early return. +#define CHECK_FLOW_LOCAL(x) do { \ + flow = x; \ + if (flow != UPB_CONTINUE) { \ + if (flow == UPB_SKIPSUBMSG) flow = UPB_CONTINUE; \ + goto end; \ + } \ +} while (0) + upb_flow_t flow; + if (upb_issubmsg(f)) { + upb_msg *msg = upb_value_getmsg(val); + CHECK_FLOW_LOCAL(upb_dispatch_startsubmsg(d, f)); + CHECK_FLOW_LOCAL(upb_msg_dispatch(msg, upb_downcast_msgdef(f->def), d, s)); + CHECK_FLOW(upb_dispatch_endsubmsg(d, f)); + } else { + CHECK_FLOW(upb_dispatch_value(d, f, val)); + } + +end: + return flow; +} + +static upb_flow_t upb_msg_dispatch(upb_msg *msg, upb_msgdef *md, + upb_dispatcher *d, upb_status *s) { + upb_msg_iter i; + upb_flow_t flow; + for(i = upb_msg_begin(md); !upb_msg_done(i); i = upb_msg_next(md, i)) { + upb_fielddef *f = upb_msg_iter_field(i); + if (!upb_msg_has(msg, f)) continue; + upb_value val = upb_msg_get(msg, f); + if (upb_isarray(f)) { + upb_array *arr = upb_value_getarr(val); + for (uint32_t j = 0; j < upb_array_len(arr); ++j) { + CHECK_FLOW_LOCAL(upb_msg_pushval(upb_array_get(arr, f, j), f, d, s)); + } + } else { + CHECK_FLOW_LOCAL(upb_msg_pushval(val, f, d, s)); + } + } + return UPB_CONTINUE; + +end: + // Need to copy/massage the error. + upb_copyerr(s, d->top->handlers.status); + if (upb_ok(s)) { + upb_seterr(s, UPB_ERROR, "Callback returned UPB_BREAK"); + } + return flow; +#undef CHECK_FLOW +#undef CHECK_FLOW_LOCAL +} + +void upb_msg_runhandlers(upb_msg *msg, upb_msgdef *md, upb_handlers *h, + upb_status *status) { + upb_dispatcher d; + upb_dispatcher_init(&d); + upb_dispatcher_reset(&d, h, true); + + if (upb_dispatch_startmsg(&d) != UPB_CONTINUE) return; + if (upb_msg_dispatch(msg, md, &d, status) != UPB_CONTINUE) return; + if (upb_dispatch_endmsg(&d) != UPB_CONTINUE) return; +} static upb_valueptr upb_msg_getappendptr(upb_msg *msg, upb_fielddef *f) { upb_valueptr p = _upb_msg_getptr(msg, f); |