Decoder compiler but doesn't work yet.

pull/13171/head
Joshua Haberman 15 years ago
parent 992a03be55
commit 5743636ad1
  1. 8
      src/upb.c
  2. 21
      src/upb.h
  3. 168
      src/upb_decoder.c
  4. 83
      src/upb_srcsink.h
  5. 93
      src/upb_srcsink_vtbl.h
  6. 5
      src/upb_string.h

@ -7,6 +7,7 @@
#include <stdarg.h>
#include <stddef.h>
#include <string.h>
#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);
}

@ -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" */

@ -10,9 +10,16 @@
#include <stddef.h>
#include <stdlib.h>
#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,11 +288,16 @@ 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;
}
@ -268,21 +305,20 @@ upb_fielddef *upb_decoder_getdef(upb_decoder *d)
if(d->field) return d->field;
again:
uint32_t key;
upb_wire_type_t wire_type;
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->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;
frame->msgdef = upb_downcast_msgdef(f->def);
}
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;
}
}

@ -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

@ -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

@ -28,6 +28,7 @@
#include <assert.h>
#include <string.h>
#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.

Loading…
Cancel
Save