From 5743636ad19eafb11eddeefd29f2803052dadff2 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Wed, 9 Jun 2010 20:28:44 -0700 Subject: [PATCH] Decoder compiler but doesn't work yet. --- src/upb.c | 8 ++ src/upb.h | 21 +++-- src/upb_decoder.c | 172 +++++++++++++++++++++++++++-------------- src/upb_srcsink.h | 83 +++----------------- src/upb_srcsink_vtbl.h | 93 ++++++++++++++++++++++ src/upb_string.h | 5 +- 6 files changed, 235 insertions(+), 147 deletions(-) create mode 100644 src/upb_srcsink_vtbl.h diff --git a/src/upb.c b/src/upb.c index 938c72d8f9..bd41613ab2 100644 --- a/src/upb.c +++ b/src/upb.c @@ -7,6 +7,7 @@ #include #include +#include #include "upb.h" @@ -21,3 +22,10 @@ void upb_seterr(upb_status *status, enum upb_status_code code, va_end(args); } } + +void upb_copyerr(upb_status *to, upb_status *from) +{ + to->code = from->code; + strcpy(to->msg, from->msg); +} + diff --git a/src/upb.h b/src/upb.h index 4991c50db9..16817631a8 100644 --- a/src/upb.h +++ b/src/upb.h @@ -71,7 +71,11 @@ enum upb_wire_type { UPB_WIRE_TYPE_DELIMITED = 2, UPB_WIRE_TYPE_START_GROUP = 3, UPB_WIRE_TYPE_END_GROUP = 4, - UPB_WIRE_TYPE_32BIT = 5 + UPB_WIRE_TYPE_32BIT = 5, + + // This isn't a real wire type, but we use this constant to describe varints + // that are expected to be a maximum of 32 bits. + UPB_WIRE_TYPE_32BIT_VARINT = 8 }; typedef uint8_t upb_wire_type_t; @@ -121,14 +125,8 @@ typedef upb_atomic_refcount_t upb_data; typedef uint32_t upb_strlen_t; -struct upb_norefcount_string; -struct upb_refcounted_string; -typedef union { - // Must be first, for the UPB_STATIC_STRING_PTR_INIT() macro. - struct upb_norefcount_string *norefcount; - struct upb_refcounted_string *refcounted; - upb_data *base; -} upb_strptr; +struct _upb_string; +typedef struct _upb_string upb_string; typedef uint32_t upb_arraylen_t; @@ -149,7 +147,7 @@ typedef union { uint32_t uint32; uint64_t uint64; bool _bool; - upb_strptr str; + upb_string *str; upb_arrayptr arr; upb_msg *msg; upb_data *data; @@ -166,7 +164,7 @@ typedef union { uint32_t *uint32; uint64_t *uint64; bool *_bool; - upb_strptr *str; + upb_string **str; upb_arrayptr *arr; upb_msg **msg; upb_data **data; @@ -290,6 +288,7 @@ INLINE void upb_reset(upb_status *status) { void upb_seterr(upb_status *status, enum upb_status_code code, const char *msg, ...); +void upb_copyerr(upb_status *to, upb_status *from); #ifdef __cplusplus } /* extern "C" */ diff --git a/src/upb_decoder.c b/src/upb_decoder.c index 916f0db729..5d352c2e27 100644 --- a/src/upb_decoder.c +++ b/src/upb_decoder.c @@ -10,9 +10,16 @@ #include #include +#define UPB_GROUP_END_OFFSET UINT32_MAX + +static bool upb_check_type(upb_wire_type_t wt, upb_field_type_t ft) { + // Fake implementation. + return ft + wt > 3; +} + /* Functions to read wire values. *********************************************/ -int8_t upb_get_v_uint64_full(const uint8_t *buf, uint64_t *val); +static uint8_t upb_get_v_uint64_full(const uint8_t *buf, uint64_t *val); // Gets a varint (wire type: UPB_WIRE_TYPE_VARINT). Caller promises that >=10 // bytes are available at buf. Returns the number of bytes consumed, or 11 if @@ -66,19 +73,19 @@ INLINE void upb_get_f_uint64(const uint8_t *buf, uint64_t *val) // Skips a varint (wire type: UPB_WIRE_TYPE_VARINT). Caller promises that 10 // bytes are available at "buf". Returns the number of bytes that were // skipped. -INLINE const uint8_t upb_skip_v_uint64(const uint8_t *buf) +INLINE uint8_t upb_skip_v_uint64(const uint8_t *buf) { const uint8_t *const maxend = buf + 10; uint8_t last = 0x80; for(; buf < maxend && (last & 0x80); buf++) last = *buf; - return + return 0; // TODO } // Parses remining bytes of a 64-bit varint that has already had its first byte // parsed. -const uint8_t upb_get_v_uint64_full(const uint8_t *buf, uint64_t *val) +static uint8_t upb_get_v_uint64_full(const uint8_t *buf, uint64_t *val) { uint8_t bytes = 0; @@ -101,7 +108,7 @@ INLINE int64_t upb_zzdec_64(uint64_t n) { return (n >> 1) ^ -(int64_t)(n & 1); } typedef struct { upb_msgdef *msgdef; upb_fielddef *field; - int32_t end_offset; // For groups, -1. + upb_strlen_t end_offset; // For groups, -1. } upb_decoder_frame; struct upb_decoder { @@ -132,6 +139,14 @@ struct upb_decoder { // Wire type of the key we just read. upb_wire_type_t wire_type; + + // Delimited length of the string field we are reading. + upb_strlen_t delimited_len; + + upb_strlen_t packed_end_offset; + + // String we return for string values. We try to recycle it if possible. + upb_string *str; }; @@ -144,6 +159,7 @@ upb_decoder *upb_decoder_new(upb_msgdef *msgdef) d->limit = &d->stack[UPB_MAX_NESTING]; d->buf = NULL; d->nextbuf = NULL; + d->str = upb_string_new(); return d; } @@ -159,8 +175,9 @@ void upb_decoder_reset(upb_decoder *d, upb_bytesrc *bytesrc) d->top = d->stack; d->top->msgdef = d->toplevel_msgdef; // The top-level message is not delimited (we can keep receiving data for it - // indefinitely), so we treat it like a group. - d->top->end_offset = 0; + // indefinitely), so we set the end offset as high as possible, but not equal + // to UINT32_MAX so it doesn't equal UPB_GROUP_END_OFFSET. + d->top->end_offset = UINT32_MAX - 1; d->bytesrc = bytesrc; d->buf = NULL; d->nextbuf = NULL; @@ -171,6 +188,11 @@ void upb_decoder_reset(upb_decoder *d, upb_bytesrc *bytesrc) /* upb_decoder buffering. *****************************************************/ +static upb_strlen_t upb_decoder_offset(upb_decoder *d) +{ + return d->buf_endoffset - d->buf_bytesleft; +} + // Discards the current buffer if we are done with it, make the next buffer // current if there is one. static void upb_decoder_advancebuf(upb_decoder *d) @@ -186,10 +208,10 @@ static void upb_decoder_advancebuf(upb_decoder *d) static bool upb_decoder_pullnextbuf(upb_decoder *d) { if(!d->nextbuf) { - d->nextbuf = upb_bytesrc_get(d->bytesrc); + d->nextbuf = upb_bytesrc_get(d->bytesrc, UPB_MAX_ENCODED_SIZE); if(!d->nextbuf && !upb_bytesrc_eof(d->bytesrc)) { // There was an error in the byte stream, halt the decoder. - upb_copyerr(&d->status, upb_bytesrc_status(d->bytesrc)); + upb_copyerr(&d->src.status, upb_bytesrc_status(d->bytesrc)); return false; } } @@ -206,6 +228,9 @@ static bool upb_decoder_skipbytes(upb_decoder *d, int32_t bytes) return true; } +bool upb_decoder_skipval(upb_decoder *d); +upb_fielddef *upb_decoder_getdef(upb_decoder *d); + static bool upb_decoder_skipgroup(upb_decoder *d) { // This will be mututally recursive with upb_decoder_skipval() if the group @@ -217,21 +242,28 @@ static bool upb_decoder_skipgroup(upb_decoder *d) } // If we are at the end of the group like we want to be, then // upb_decoder_getdef() returned NULL because of eof, not error. - return upb_ok(&d->status); + return upb_ok(&d->src.status); } -static const uint8_t *upb_decoder_getbuf_full(upb_decoder *d, int32_t *bytes) +upb_strlen_t upb_decoder_append(uint8_t *buf, upb_string *frombuf, + upb_strlen_t len, upb_strlen_t total_len); + +static const uint8_t *upb_decoder_getbuf_full(upb_decoder *d, uint32_t *bytes) { upb_decoder_pullnextbuf(d); upb_decoder_advancebuf(d); if(d->buf_bytesleft >= UPB_MAX_ENCODED_SIZE) { - return upb_string_getrobuf(d->buf) + upb_string_len(d->buf) - + *bytes = d->buf_bytesleft; + return (uint8_t*)upb_string_getrobuf(d->buf) + upb_string_len(d->buf) - d->buf_bytesleft; } else { - upb_strlen_t total = 0; - if(d->buf) total += upb_decoder_append(d->tmpbuf, d->buf, total); - if(d->nextbuf) total += upb_decoder_append(d->tmpbuf, d->nextbuf, total); - memset(d->tmpbuf + total, 0x80, UPB_MAX_ENCODED_SIZE - total); + upb_strlen_t len = 0; + if(d->buf) + len += upb_decoder_append(d->tmpbuf, d->buf, len, UPB_MAX_ENCODED_SIZE); + if(d->nextbuf) + len += upb_decoder_append(d->tmpbuf, d->nextbuf, len, UPB_MAX_ENCODED_SIZE); + *bytes = len; + memset(d->tmpbuf + len, 0x80, UPB_MAX_ENCODED_SIZE - len); return d->tmpbuf; } } @@ -241,13 +273,13 @@ static const uint8_t *upb_decoder_getbuf_full(upb_decoder *d, int32_t *bytes) // those bytes span multiple buffers). *bytes is set to the number of actual // stream bytes that are available in the returned buffer. If // *bytes < UPB_MAX_ENCODED_SIZE, the buffer is padded with 0x80 bytes. -INLINE static const uint8_t *upb_decoder_getbuf(upb_decoder *d, int32_t *bytes) +INLINE const uint8_t *upb_decoder_getbuf(upb_decoder *d, uint32_t *bytes) { if(d->buf_bytesleft >= UPB_MAX_ENCODED_SIZE) { // The common case; only when we get to the last ten bytes of the buffer // do we have to do tricky things. *bytes = d->buf_bytesleft; - return upb_string_getrobuf(d->buf) + upb_string_len(d->buf) - + return (uint8_t*)upb_string_getrobuf(d->buf) + upb_string_len(d->buf) - d->buf_bytesleft; } else { return upb_decoder_getbuf_full(d, bytes); @@ -256,33 +288,37 @@ INLINE static const uint8_t *upb_decoder_getbuf(upb_decoder *d, int32_t *bytes) /* upb_src implementation for upb_decoder. ************************************/ +bool upb_decoder_get_v_uint32(upb_decoder *d, uint32_t *key); + upb_fielddef *upb_decoder_getdef(upb_decoder *d) { + uint32_t key; + upb_wire_type_t wire_type; + // Detect end-of-submessage. if(upb_decoder_offset(d) >= d->top->end_offset) { - d->eof = true; + d->src.eof = true; return NULL; } // Handles the packed field case. if(d->field) return d->field; -again: - uint32_t key; - upb_wire_type_t wire_type; + again: if(!upb_decoder_get_v_uint32(d, &key)) { return NULL; + } wire_type = key & 0x7; if(wire_type == UPB_WIRE_TYPE_DELIMITED) { // For delimited wire values we parse the length now, since we need it in // all cases. - if(!upb_decoder_get_v_uint32(d, &d->delim_len)) return NULL; + if(!upb_decoder_get_v_uint32(d, &d->delimited_len)) return NULL; } else if(wire_type == UPB_WIRE_TYPE_END_GROUP) { - if(isgroup(d->top->submsg_end)) { - d->eof = true; + if(d->top->end_offset == UPB_GROUP_END_OFFSET) { + d->src.eof = true; } else { - upb_seterr(d->status, UPB_STATUS_ERROR, "End group seen but current " + upb_seterr(&d->src.status, UPB_STATUS_ERROR, "End group seen but current " "message is not a group, byte offset: %zd", upb_decoder_offset(d)); } @@ -302,7 +338,7 @@ again: // return NULL and report the error. upb_decoder_skipval(d); // TODO: better error message. - upb_seterr(&d->status, UPB_STATUS_ERROR, "Incorrect wire type.\n"); + upb_seterr(&d->src.status, UPB_STATUS_ERROR, "Incorrect wire type.\n"); return NULL; } d->field = f; @@ -312,30 +348,32 @@ again: bool upb_decoder_getval(upb_decoder *d, upb_valueptr val) { - if(expected_type_for_field == UPB_DELIMITED) { + int expected_type_for_field = 0; + if(expected_type_for_field == UPB_WIRE_TYPE_DELIMITED) { // A string, bytes, or a length-delimited submessage. The latter isn't // technically a string, but can be gotten as one to perform lazy parsing. d->str = upb_string_tryrecycle(d->str); const upb_strlen_t total_len = d->delimited_len; - if (total_len <= d->buf_bytesleft) { + if ((int32_t)total_len <= d->buf_bytesleft) { // The entire string is inside our current buffer, so we can just // return a substring of the buffer without copying. upb_string_substr(d->str, d->buf, upb_string_len(d->buf) - d->buf_bytesleft, total_len); - upb_decoder_consume(total_len); + d->buf_bytesleft -= total_len; *val.str = d->str; } else { // The string spans buffers, so we must copy from the current buffer, // the next buffer (if we have one), and finally from the bytesrc. - char *str = upb_string_getrwbuf(d->str, d->); + uint8_t *str = (uint8_t*)upb_string_getrwbuf(d->str, total_len); upb_strlen_t len = 0; len += upb_decoder_append(str, d->buf, len, total_len); upb_decoder_advancebuf(d); if(d->buf) len += upb_decoder_append(str, d->buf, len, total_len); + upb_string_getrwbuf(d->str, len); // Cheap resize. if(len < total_len) { - if(!upb_bytesrc_append(d->bytesrc, d->str, len - bytes)) { - upb_status_copy(&d->error, upb_bytesrc_status(d->bytesrc)); + if(!upb_bytesrc_append(d->bytesrc, d->str, total_len - len)) { + upb_copyerr(&d->src.status, upb_bytesrc_status(d->bytesrc)); return false; } } @@ -346,22 +384,22 @@ bool upb_decoder_getval(upb_decoder *d, upb_valueptr val) // contiguous buffer. uint32_t bytes_available; uint32_t bytes_consumed; - const uint8_t *buf = upb_decoder_getbuf(d, &bytes_available) + const uint8_t *buf = upb_decoder_getbuf(d, &bytes_available); switch(expected_type_for_field) { - case UPB_64BIT_VARINT: + case UPB_WIRE_TYPE_VARINT: if((bytes_consumed = upb_get_v_uint32(buf, val.uint32)) > 10) goto err; - if(f->type == UPB_TYPE(SINT64)) *val.int64 = upb_zzdec_64(*val.int64); + if(d->field->type == UPB_TYPE(SINT64)) *val.int64 = upb_zzdec_64(*val.int64); break; - case UPB_32BIT_VARINT: + case UPB_WIRE_TYPE_32BIT_VARINT: if((bytes_consumed = upb_get_v_uint64(buf, val.uint64)) > 5) goto err; - if(f->type == UPB_TYPE(SINT32)) *val.int32 = upb_zzdec_32(*val.int32); + if(d->field->type == UPB_TYPE(SINT32)) *val.int32 = upb_zzdec_32(*val.int32); break; - case UPB_64BIT_FIXED: + case UPB_WIRE_TYPE_64BIT: bytes_consumed = 8; if(bytes_available < bytes_consumed) goto err; upb_get_f_uint64(buf, val.uint64); break; - case UPB_32BIT_FIXED: + case UPB_WIRE_TYPE_32BIT: bytes_consumed = 4; if(bytes_available < bytes_consumed) goto err; upb_get_f_uint32(buf, val.uint32); @@ -370,33 +408,40 @@ bool upb_decoder_getval(upb_decoder *d, upb_valueptr val) // Including start/end group. goto err; } - upb_decoder_consume(bytes_consumed); - if(wire_type != UPB_WIRE_TYPE_DELIMITED || + d->buf_bytesleft -= bytes_consumed; + if(d->wire_type != UPB_WIRE_TYPE_DELIMITED || upb_decoder_offset(d) >= d->packed_end_offset) { d->field = NULL; } } return true; err: + return false; } bool upb_decoder_skipval(upb_decoder *d) { - switch(d->key.wire_type) { - case UPB_WIRE_TYPE_VARINT: - return upb_skip_v_uint64(buf, end, status); + switch(d->wire_type) { + case UPB_WIRE_TYPE_VARINT: { + uint32_t bytes_available; + const uint8_t *buf = upb_decoder_getbuf(d, &bytes_available); + uint8_t bytes = upb_skip_v_uint64(buf); + if(bytes > 10) return false; + upb_decoder_skipbytes(d, bytes); + return true; + } case UPB_WIRE_TYPE_64BIT: - return upb_decoder_skipbytes(8); + return upb_decoder_skipbytes(d, 8); case UPB_WIRE_TYPE_32BIT: - return upb_decoder_skipbytes(4); + return upb_decoder_skipbytes(d, 4); case UPB_WIRE_TYPE_START_GROUP: - return upb_decoder_skipgroup(); + return upb_decoder_skipgroup(d); case UPB_WIRE_TYPE_DELIMITED: // Works for both string/bytes *and* submessages. - return upb_decoder_skipbytes(d->delimited_len); + return upb_decoder_skipbytes(d, d->delimited_len); default: // Including UPB_WIRE_TYPE_END_GROUP. assert(false); - upb_seterr(&d->status, UPB_STATUS_ERROR, "Tried to skip an end group"); + upb_seterr(&d->src.status, UPB_STATUS_ERROR, "Tried to skip an end group"); return false; } } @@ -404,26 +449,33 @@ bool upb_decoder_skipval(upb_decoder *d) { bool upb_decoder_startmsg(upb_decoder *d) { d->top->field = d->field; if(++d->top >= d->limit) { - upb_seterr(d->status, UPB_ERROR_MAX_NESTING_EXCEEDED, + upb_seterr(&d->src.status, UPB_ERROR_MAX_NESTING_EXCEEDED, "Nesting exceeded maximum (%d levels)\n", UPB_MAX_NESTING); return false; } upb_decoder_frame *frame = d->top; - frame->end_offset = upb_decoder_offset(d) + d->delimited_len; - frame->msgdef = upb_downcast_msgdef(f->def); + frame->msgdef = upb_downcast_msgdef(d->field->def); + if(d->field->type == UPB_TYPE(GROUP)) { + frame->end_offset = UPB_GROUP_END_OFFSET; + } else { + frame->end_offset = upb_decoder_offset(d) + d->delimited_len; + } return true; } -bool upb_decoder_endmsg(upb_decoder *src) { - if(d->top > &d->stack) { +bool upb_decoder_endmsg(upb_decoder *d) { + if(d->top > d->stack) { --d->top; - if(!d->eof) { - if(d->top->f->type == UPB_TYPE(GROUP)) - upb_skip_group(); + if(!d->src.eof) { + if(d->top->field->type == UPB_TYPE(GROUP)) + upb_decoder_skipgroup(d); else - upb_skip_bytes(foo); + upb_decoder_skipbytes(d, d->top->end_offset - upb_decoder_offset(d)); } - d->eof = false; + d->src.eof = false; + return true; + } else { + return false; } } diff --git a/src/upb_srcsink.h b/src/upb_srcsink.h index 4a3d1e378f..8e5a09d2ad 100644 --- a/src/upb_srcsink.h +++ b/src/upb_srcsink.h @@ -1,8 +1,6 @@ /* * upb - a minimalist implementation of protocol buffers. * - * Copyright (c) 2010 Joshua Haberman. See LICENSE for details. - * * This file defines four general-purpose interfaces for pulling/pushing either * protobuf data or bytes: * @@ -13,12 +11,16 @@ * * These interfaces are used as general-purpose glue in upb. For example, the * decoder interface works by implementing a upb_src and calling a upb_bytesrc. + * + * Copyright (c) 2010 Joshua Haberman. See LICENSE for details. + * */ #ifndef UPB_SRCSINK_H #define UPB_SRCSINK_H #include "upb_def.h" +#include "upb_srcsink_vtbl.h" #ifdef __cplusplus extern "C" { @@ -28,9 +30,6 @@ extern "C" { // TODO: decide how to handle unknown fields. -struct upb_src; -typedef struct upb_src upb_src; - // Retrieves the fielddef for the next field in the stream. Returns NULL on // error or end-of-stream. upb_fielddef *upb_src_getdef(upb_src *src); @@ -51,14 +50,12 @@ bool upb_src_startmsg(upb_src *src); // which case the rest of the submessage is skipped. bool upb_src_endmsg(upb_src *src); -// Returns the current error status for the stream. -upb_status *upb_src_status(upb_src *src); +// Returns the current error/eof status for the stream. +INLINE upb_status *upb_src_status(upb_src *src) { return &src->status; } +INLINE bool upb_src_eof(upb_src *src) { return src->eof; } /* upb_sink *******************************************************************/ -struct upb_sink; -typedef struct upb_sink upb_sink; - // Puts the given fielddef into the stream. bool upb_sink_putdef(upb_sink *sink, upb_fielddef *def); @@ -76,9 +73,6 @@ upb_status *upb_sink_status(upb_sink *sink); /* upb_bytesrc ****************************************************************/ -struct upb_bytesrc; -typedef struct upb_bytesrc upb_bytesrc; - // Returns the next string in the stream. NULL is returned on error or eof. // The string must be at least "minlen" bytes long unless the stream is eof. // @@ -94,13 +88,11 @@ void upb_bytesrc_recycle(upb_bytesrc *src, upb_string *str); bool upb_bytesrc_append(upb_bytesrc *src, upb_string *str, upb_strlen_t len); // Returns the current error status for the stream. -upb_status *upb_bytesrc_status(upb_src *src); +INLINE upb_status *upb_bytesrc_status(upb_bytesrc *src) { return &src->status; } +INLINE bool upb_bytesrc_eof(upb_bytesrc *src) { return src->eof; } /* upb_bytesink ***************************************************************/ -struct upb_bytesink; -typedef struct upb_bytesink upb_bytesink; - // Puts the given string. Returns the number of bytes that were actually, // consumed, which may be fewer than were in the string, or <0 on error. int32_t upb_bytesink_put(upb_bytesink *sink, upb_string *str); @@ -108,63 +100,6 @@ int32_t upb_bytesink_put(upb_bytesink *sink, upb_string *str); // Returns the current error status for the stream. upb_status *upb_bytesink_status(upb_bytesink *sink); -/* Dynamic Dispatch implementation for src/sink interfaces ********************/ - -// The rest of this file only concerns components that are implementing any of -// the above interfaces. To simple clients the code below should be considered -// private. - -// Typedefs for function pointers to all of the above functions. -typedef upb_fielddef (*upb_src_getdef_fptr)(upb_src *src); -typedef bool (*upb_src_getval_fptr)(upb_src *src, upb_valueptr val); -typedef bool (*upb_src_skipval_fptr)(upb_src *src); -typedef bool (*upb_src_startmsg_fptr)(upb_src *src); -typedef bool (*upb_src_endmsg_fptr)(upb_src *src); -typedef upb_status *(*upb_src_status_fptr)(upb_src *src); - -typedef bool (*upb_sink_putdef_fptr)(upb_sink *sink, upb_fielddef *def); -typedef bool (*upb_sink_putval_fptr)(upb_sink *sink, upb_value val); -typedef bool (*upb_sink_startmsg_fptr)(upb_sink *sink); -typedef bool (*upb_sink_endmsg_fptr)(upb_sink *sink); -typedef upb_status *(*upb_sink_status_fptr)(upb_sink *sink); - -typedef upb_string *(*upb_bytesrc_get_fptr)(upb_bytesrc *src); -typedef bool (*upb_bytesrc_append_fptr)( - upb_bytesrc *src, upb_string *str, upb_strlen_t len); -typedef upb_status *(*upb_bytesrc_status_fptr)(upb_src *src); - -typedef int32_t (*upb_bytesink_put_fptr)(upb_bytesink *sink, upb_string *str); -typedef upb_status *(*upb_bytesink_status_fptr)(upb_bytesink *sink); - -// Vtables for the above interfaces. -typedef struct { - upb_src_getdef_fptr getdef; - upb_src_getval_fptr getval; - upb_src_skipval_fptr skipval; - upb_src_startmsg_fptr startmsg; - upb_src_endmsg_fptr endmsg; - upb_src_status_fptr status; -} upb_src_vtable; - -// "Base Class" definitions; components that implement these interfaces should -// contain one of these structures. - -struct upb_src { - upb_src_vtable *vtbl; - upb_status status; - bool eof; -#ifndef NDEBUG - int state; // For debug-mode checking of API usage. -#endif -}; - -INLINE void upb_sink_init(upb_src *s, upb_src_vtable *vtbl) { - s->vtbl = vtbl; -#ifndef DEBUG - // TODO: initialize debug-mode checking. -#endif -} - #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/upb_srcsink_vtbl.h b/src/upb_srcsink_vtbl.h new file mode 100644 index 0000000000..66cd3c2269 --- /dev/null +++ b/src/upb_srcsink_vtbl.h @@ -0,0 +1,93 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * vtable declarations for types that are implementing any of the src or sink + * interfaces. Only components that are implementing these interfaces need + * to worry about this file. + * + * Copyright (c) 2010 Joshua Haberman. See LICENSE for details. + */ + +#ifndef UPB_SRCSINK_VTBL_H_ +#define UPB_SRCSINK_VTBL_H_ + +#include "upb_def.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct upb_src; +typedef struct upb_src upb_src; +struct upb_sink; +typedef struct upb_sink upb_sink; +struct upb_bytesrc; +typedef struct upb_bytesrc upb_bytesrc; +struct upb_bytesink; +typedef struct upb_bytesink upb_bytesink; + +// Typedefs for function pointers to all of the virtual functions. +typedef upb_fielddef (*upb_src_getdef_fptr)(upb_src *src); +typedef bool (*upb_src_getval_fptr)(upb_src *src, upb_valueptr val); +typedef bool (*upb_src_skipval_fptr)(upb_src *src); +typedef bool (*upb_src_startmsg_fptr)(upb_src *src); +typedef bool (*upb_src_endmsg_fptr)(upb_src *src); + +typedef bool (*upb_sink_putdef_fptr)(upb_sink *sink, upb_fielddef *def); +typedef bool (*upb_sink_putval_fptr)(upb_sink *sink, upb_value val); +typedef bool (*upb_sink_startmsg_fptr)(upb_sink *sink); +typedef bool (*upb_sink_endmsg_fptr)(upb_sink *sink); + +typedef upb_string *(*upb_bytesrc_get_fptr)(upb_bytesrc *src); +typedef void (*upb_bytesrc_recycle_fptr)(upb_bytesrc *src, upb_string *str); +typedef bool (*upb_bytesrc_append_fptr)( + upb_bytesrc *src, upb_string *str, upb_strlen_t len); + +typedef int32_t (*upb_bytesink_put_fptr)(upb_bytesink *sink, upb_string *str); + +// Vtables for the above interfaces. +typedef struct { + upb_src_getdef_fptr getdef; + upb_src_getval_fptr getval; + upb_src_skipval_fptr skipval; + upb_src_startmsg_fptr startmsg; + upb_src_endmsg_fptr endmsg; +} upb_src_vtable; + +typedef struct { + upb_bytesrc_get_fptr get; + upb_bytesrc_append_fptr append; + upb_bytesrc_recycle_fptr recycle; +} upb_bytesrc_vtable; + +// "Base Class" definitions; components that implement these interfaces should +// contain one of these structures. + +struct upb_src { + upb_src_vtable *vtbl; + upb_status status; + bool eof; +#ifndef NDEBUG + int state; // For debug-mode checking of API usage. +#endif +}; + +struct upb_bytesrc { + upb_bytesrc_vtable *vtbl; + upb_status status; + bool eof; +}; + +INLINE void upb_sink_init(upb_src *s, upb_src_vtable *vtbl) { + s->vtbl = vtbl; + s->eof = false; +#ifndef DEBUG + // TODO: initialize debug-mode checking. +#endif +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/src/upb_string.h b/src/upb_string.h index 2c0303d7b2..9a3957c1a6 100644 --- a/src/upb_string.h +++ b/src/upb_string.h @@ -28,6 +28,7 @@ #include #include #include "upb_atomic.h" +#include "upb.h" #ifdef __cplusplus extern "C" { @@ -35,7 +36,7 @@ extern "C" { // All members of this struct are private, and may only be read/written through // the associated functions. Also, strings may *only* be allocated on the heap. -typedef struct _upb_string { +struct _upb_string { char *ptr; uint32_t len; uint32_t size; @@ -46,7 +47,7 @@ typedef struct _upb_string { // Used if this string is referencing external unowned memory. upb_atomic_refcount_t reader_count; } extra; -} upb_string; +}; // Returns a newly-created, empty, non-finalized string. When the string is no // longer needed, it should be unref'd, never freed directly.