summaryrefslogtreecommitdiff
path: root/src/upb_handlers.c
diff options
context:
space:
mode:
authorJoshua Haberman <joshua@reverberate.org>2011-05-20 11:26:27 -0700
committerJoshua Haberman <joshua@reverberate.org>2011-05-20 11:26:27 -0700
commit0941664215ed7fa4a8d53b6387d50c56df6757d0 (patch)
tree9125c22f6892015e05fa709426a6cc8b082972ad /src/upb_handlers.c
parent74102e836d285bcfcb4c22cbe72a3a36828d30cb (diff)
Add startseq/endseq handlers.
Startseq/endseq handlers are called at the beginning and end of a sequence of repeated values. Protobuf does not really have direct support for this (repeated primitive fields do not delimit "begin" and "end" of the sequence) but we can infer them from the bytestream. The benefit of supporting them explicitly is that they get their own stack frame and closure, so we can avoid having to find the array's address over and over and deciding if we need to initialize it. This will also pave the way for better support of JSON, which does have explicit "startseq/endseq" markers: [].
Diffstat (limited to 'src/upb_handlers.c')
-rw-r--r--src/upb_handlers.c78
1 files changed, 67 insertions, 11 deletions
diff --git a/src/upb_handlers.c b/src/upb_handlers.c
index 0be02aa..7be43ce 100644
--- a/src/upb_handlers.c
+++ b/src/upb_handlers.c
@@ -26,12 +26,12 @@ upb_flow_t upb_value_nop(void *closure, upb_value fval, upb_value val) {
return UPB_CONTINUE;
}
-upb_sflow_t upb_startsubmsg_nop(void *closure, upb_value fval) {
+upb_sflow_t upb_startfield_nop(void *closure, upb_value fval) {
(void)fval;
return UPB_CONTINUE_WITH(closure);
}
-upb_flow_t upb_endsubmsg_nop(void *closure, upb_value fval) {
+upb_flow_t upb_endfield_nop(void *closure, upb_value fval) {
(void)closure;
(void)fval;
return UPB_CONTINUE;
@@ -57,9 +57,11 @@ static upb_fhandlers *_upb_mhandlers_newfield(upb_mhandlers *m, uint32_t n,
upb_fhandlers *f = upb_inttable_lookup(&m->fieldtab, tag);
if (f) abort();
upb_fhandlers new_f = {false, type, repeated,
- repeated && upb_isprimitivetype(type), n, NULL, UPB_NO_VALUE,
- &upb_value_nop, &upb_startsubmsg_nop, &upb_endsubmsg_nop, 0, 0, 0, NULL};
- if (upb_issubmsgtype(type)) new_f.startsubmsg = &upb_startsubmsg_nop;
+ repeated && upb_isprimitivetype(type), n, m, NULL, UPB_NO_VALUE,
+ &upb_value_nop,
+ &upb_startfield_nop, &upb_endfield_nop,
+ &upb_startfield_nop, &upb_endfield_nop,
+ 0, 0, 0, NULL};
upb_inttable_insert(&m->fieldtab, tag, &new_f);
f = upb_inttable_lookup(&m->fieldtab, tag);
assert(f);
@@ -170,13 +172,13 @@ upb_mhandlers *upb_handlers_newmsg(upb_handlers *h) {
static upb_fhandlers toplevel_f = {
false, UPB_TYPE(GROUP), false, false, 0,
- NULL, // submsg
+ NULL, NULL, // submsg
#ifdef NDEBUG
{{0}},
#else
{{0}, UPB_VALUETYPE_RAW},
#endif
- NULL, NULL, NULL, 0, 0, 0, NULL};
+ NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL};
void upb_dispatcher_init(upb_dispatcher *d, upb_handlers *h,
upb_skip_handler *skip, upb_exit_handler *exit,
@@ -199,6 +201,7 @@ upb_dispatcher_frame *upb_dispatcher_reset(upb_dispatcher *d, void *closure) {
d->dispatch_table = &d->msgent->fieldtab;
d->top = d->stack;
d->top->closure = closure;
+ d->top->is_sequence = false;
return d->top;
}
@@ -219,8 +222,59 @@ void upb_dispatch_endmsg(upb_dispatcher *d, upb_status *status) {
upb_copyerr(status, &d->status);
}
+void indent(upb_dispatcher *d) {
+ for (int i = 0; i < (d->top - d->stack); i++) printf(" ");
+}
+
+void indentm1(upb_dispatcher *d) {
+ for (int i = 0; i < (d->top - d->stack - 1); i++) printf(" ");
+}
+
+upb_dispatcher_frame *upb_dispatch_startseq(upb_dispatcher *d,
+ upb_fhandlers *f) {
+ //indent(d);
+ //printf("START SEQ: %d\n", f->number);
+ if((d->top+1) >= d->limit) {
+ upb_seterr(&d->status, UPB_ERROR, "Nesting too deep.");
+ _upb_dispatcher_unwind(d, UPB_BREAK);
+ return d->top; // Dummy.
+ }
+
+ upb_sflow_t sflow = f->startseq(d->top->closure, f->fval);
+ if (sflow.flow != UPB_CONTINUE) {
+ _upb_dispatcher_unwind(d, sflow.flow);
+ return d->top; // Dummy.
+ }
+
+ ++d->top;
+ d->top->f = f;
+ d->top->is_sequence = true;
+ d->top->closure = sflow.closure;
+ return d->top;
+}
+
+upb_dispatcher_frame *upb_dispatch_endseq(upb_dispatcher *d) {
+ //indentm1(d);
+ //printf("END SEQ\n");
+ assert(d->top > d->stack);
+ assert(d->top->is_sequence);
+ upb_fhandlers *f = d->top->f;
+ --d->top;
+ upb_flow_t flow = f->endseq(d->top->closure, f->fval);
+ if (flow != UPB_CONTINUE) {
+ printf("YO, UNWINDING!\n");
+ _upb_dispatcher_unwind(d, flow);
+ return d->top; // Dummy.
+ }
+ d->msgent = d->top->f->submsg ? d->top->f->submsg : d->handlers->msgs[0];
+ d->dispatch_table = &d->msgent->fieldtab;
+ return d->top;
+}
+
upb_dispatcher_frame *upb_dispatch_startsubmsg(upb_dispatcher *d,
upb_fhandlers *f) {
+ //indent(d);
+ //printf("START SUBMSG: %d\n", f->number);
if((d->top+1) >= d->limit) {
upb_seterr(&d->status, UPB_ERROR, "Nesting too deep.");
_upb_dispatcher_unwind(d, UPB_BREAK);
@@ -244,14 +298,16 @@ upb_dispatcher_frame *upb_dispatch_startsubmsg(upb_dispatcher *d,
}
upb_dispatcher_frame *upb_dispatch_endsubmsg(upb_dispatcher *d) {
+ //indentm1(d);
+ //printf("END SUBMSG\n");
assert(d->top > d->stack);
- void *c = d->top->closure;
+ assert(!d->top->is_sequence);
upb_fhandlers *f = d->top->f;
+ d->msgent->endmsg(d->top->closure, &d->status);
+ d->msgent = d->top->f->msg;
+ d->dispatch_table = &d->msgent->fieldtab;
--d->top;
- d->msgent->endmsg(c, &d->status);
upb_flow_t flow = f->endsubmsg(d->top->closure, f->fval);
- d->msgent = d->top->f->submsg ? d->top->f->submsg : d->handlers->msgs[0];
- d->dispatch_table = &d->msgent->fieldtab;
if (flow != UPB_CONTINUE) _upb_dispatcher_unwind(d, flow);
return d->top;
}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback