Added an example, constified some more methods.

pull/13171/head
Joshua Haberman 13 years ago
parent bda3269a42
commit 887abe669f
  1. 6
      Makefile
  2. 15
      examples/example.proto
  3. 59
      examples/msg.c
  4. 4
      tests/test_vs_proto2.cc
  5. 4
      upb/def.h
  6. 24
      upb/msg.c
  7. 87
      upb/msg.h
  8. 14
      upb/pb/glue.c
  9. 19
      upb/pb/glue.h
  10. 7
      upb/table.h

@ -185,7 +185,11 @@ descriptorgen: upb/descriptor.pb tools/upbc
tools/upbc: tools/upbc.c $(LIBUPB) tools/upbc: tools/upbc.c $(LIBUPB)
$(E) CC $< $(E) CC $<
$(Q) $(CC) $(CFLAGS) $(CPPFLAGS) $(DEF_OPT) -o $@ $< $(LIBUPB) $(Q) $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $< $(LIBUPB)
examples/msg: examples/msg.c $(LIBUPB)
$(E) CC $<
$(Q) $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $< $(LIBUPB)
# Tests. ####################################################################### # Tests. #######################################################################

@ -0,0 +1,15 @@
//
// upb - a minimalist implementation of protocol buffers.
//
// Copyright (c) 2011 Google Inc. See LICENSE for details.
// Author: Josh Haberman <jhaberman@gmail.com>
//
// A .proto file for the examples in this directory.
package example;
message SampleMessage {
optional string name = 1;
optional int32 id = 2;
optional string email = 3;
}

@ -0,0 +1,59 @@
/*
* upb - a minimalist implementation of protocol buffers.
*
* Copyright (c) 2011 Google Inc. See LICENSE for details.
* Author: Josh Haberman <jhaberman@gmail.com>
*
* A simple example that demonstrates creating a standard message object
* and parsing into it, using a dynamic reflection-based approach.
*
* Note that with this approach there are no strongly-typed struct or class
* definitions to use from C -- this is essentially a reflection-based
* interface. Note that parsing and serializing are still very fast since
* they are JIT-based.
*
* If this seems a bit verbose, you may prefer an approach that generates
* strongly-typed struct definitions (upb will likely provide this, but it is
* not yet implemented).
*
* TODO: make this file compiled as part of "make examples"
* TODO: test that this actually works (WARNING: UNTESTED!)
*/
#include "upb/msg.h"
#include "upb/pb/glue.h"
const char *descfile = "example.proto.pb";
const char *type = "example.SampleMessage";
const char *msgfile = "sample_message.pb";
int main() {
// First we load the descriptor that describes the message into a upb_msgdef.
// This could come from a string that is compiled into the program or from a
// separate file as we do here. Since defs always live in a symtab, we
// create one of those also.
upb_symtab *s = upb_symtab_new();
upb_status status = UPB_STATUS_INIT;
if (!upb_load_descriptor_file_into_symtab(s, descfile, &status)) {
fprintf(stderr, "Couldn't load descriptor file '%s': %s\n", descfile,
upb_status_getstr(&status));
return -1;
}
const upb_msgdef *md = upb_symtab_lookupmsg(s, type);
if (!md) {
fprintf(stderr, "Descriptor did not contain type '%s'\n", type);
return -1;
}
// Parse a file into a new message object.
void *msg = upb_filetonewmsg(msgfile, md, &status);
if (!msg) {
fprintf(stderr, "Error parsing message file '%s': %s\n", msgfile,
upb_status_getstr(&status));
return -1;
}
// TODO: Inspect some fields.
return 0;
}

@ -30,8 +30,8 @@ void compare_arrays(const google::protobuf::Reflection *r,
{ {
ASSERT(upb_msg_has(upb_msg, upb_f)); ASSERT(upb_msg_has(upb_msg, upb_f));
ASSERT(upb_isseq(upb_f)); ASSERT(upb_isseq(upb_f));
void *arr = upb_value_getptr(upb_msg_getseq(upb_msg, upb_f)); const void *arr = upb_value_getptr(upb_msg_getseq(upb_msg, upb_f));
void *iter = upb_seq_begin(arr, upb_f); const void *iter = upb_seq_begin(arr, upb_f);
for(int i = 0; for(int i = 0;
i < r->FieldSize(proto2_msg, proto2_f); i < r->FieldSize(proto2_msg, proto2_f);
i++, iter = upb_seq_next(arr, iter, upb_f)) { i++, iter = upb_seq_next(arr, iter, upb_f)) {

@ -294,13 +294,13 @@ void upb_msgdef_layout(upb_msgdef *m);
// Looks up a field by name or number. While these are written to be as fast // Looks up a field by name or number. While these are written to be as fast
// as possible, it will still be faster to cache the results of this lookup if // as possible, it will still be faster to cache the results of this lookup if
// possible. These return NULL if no such field is found. // possible. These return NULL if no such field is found.
INLINE upb_fielddef *upb_msgdef_itof(upb_msgdef *m, uint32_t i) { INLINE upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i) {
upb_itof_ent *e = (upb_itof_ent*) upb_itof_ent *e = (upb_itof_ent*)
upb_inttable_fastlookup(&m->itof, i, sizeof(upb_itof_ent)); upb_inttable_fastlookup(&m->itof, i, sizeof(upb_itof_ent));
return e ? e->f : NULL; return e ? e->f : NULL;
} }
INLINE upb_fielddef *upb_msgdef_ntof(upb_msgdef *m, const char *name) { INLINE upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name) {
upb_ntof_ent *e = (upb_ntof_ent*)upb_strtable_lookup(&m->ntof, name); upb_ntof_ent *e = (upb_ntof_ent*)upb_strtable_lookup(&m->ntof, name);
return e ? e->f : NULL; return e ? e->f : NULL;
} }

@ -89,9 +89,9 @@ void upb_stdmsg_sethas(void *_m, upb_value fval) {
if (f->hasbit >= 0) m[f->hasbit / 8] |= (1 << (f->hasbit % 8)); if (f->hasbit >= 0) m[f->hasbit / 8] |= (1 << (f->hasbit % 8));
} }
bool upb_stdmsg_has(void *_m, upb_value fval) { bool upb_stdmsg_has(const void *_m, upb_value fval) {
assert(_m != NULL); assert(_m != NULL);
char *m = _m; const char *m = _m;
const upb_fielddef *f = upb_value_getfielddef(fval); const upb_fielddef *f = upb_value_getfielddef(fval);
return f->hasbit < 0 || (m[f->hasbit / 8] & (1 << (f->hasbit % 8))); return f->hasbit < 0 || (m[f->hasbit / 8] & (1 << (f->hasbit % 8)));
} }
@ -116,15 +116,15 @@ bool upb_stdmsg_has(void *_m, upb_value fval) {
return UPB_CONTINUE; \ return UPB_CONTINUE; \
} \ } \
\ \
upb_value upb_stdmsg_get ## type(void *_m, upb_value fval) { \ upb_value upb_stdmsg_get ## type(const void *_m, upb_value fval) { \
assert(_m != NULL); \ assert(_m != NULL); \
uint8_t *m = _m; \ const uint8_t *m = _m; \
const upb_fielddef *f = upb_value_getfielddef(fval); \ const upb_fielddef *f = upb_value_getfielddef(fval); \
upb_value ret; \ upb_value ret; \
upb_value_set ## type(&ret, *(ctype*)&m[f->offset]); \ upb_value_set ## type(&ret, *(ctype*)&m[f->offset]); \
return ret; \ return ret; \
} \ } \
upb_value upb_stdmsg_seqget ## type(void *i) { \ upb_value upb_stdmsg_seqget ## type(const void *i) { \
assert(i != NULL); \ assert(i != NULL); \
upb_value val; \ upb_value val; \
upb_value_set ## type(&val, *(ctype*)i); \ upb_value_set ## type(&val, *(ctype*)i); \
@ -176,12 +176,12 @@ upb_flow_t upb_stdmsg_setstr_r(void *a, upb_value fval, upb_value val) {
return UPB_CONTINUE; return UPB_CONTINUE;
} }
upb_value upb_stdmsg_getstr(void *m, upb_value fval) { upb_value upb_stdmsg_getstr(const void *m, upb_value fval) {
assert(m != NULL); assert(m != NULL);
return upb_stdmsg_getptr(m, fval); return upb_stdmsg_getptr(m, fval);
} }
upb_value upb_stdmsg_seqgetstr(void *i) { upb_value upb_stdmsg_seqgetstr(const void *i) {
assert(i != NULL); assert(i != NULL);
return upb_stdmsg_seqgetptr(i); return upb_stdmsg_seqgetptr(i);
} }
@ -275,15 +275,15 @@ upb_sflow_t upb_stdmsg_startsubmsg_r(void *a, upb_value fval) {
return UPB_CONTINUE_WITH(*subm); return UPB_CONTINUE_WITH(*subm);
} }
void *upb_stdmsg_seqbegin(void *_a) { const void *upb_stdmsg_seqbegin(const void *_a) {
upb_stdarray *a = _a; const upb_stdarray *a = _a;
return a->len > 0 ? a->ptr : NULL; return a->len > 0 ? a->ptr : NULL;
} }
#define NEXTFUNC(size) \ #define NEXTFUNC(size) \
void *upb_stdmsg_ ## size ## byte_seqnext(void *_a, void *iter) { \ const void *upb_stdmsg_ ## size ## byte_seqnext(const void *_a, const void *iter) {\
upb_stdarray *a = _a; \ const upb_stdarray *a = _a; \
void *next = (char*)iter + size; \ const void *next = (char*)iter + size; \
return (char*)next < (char*)a->ptr + (a->len * size) ? next : NULL; \ return (char*)next < (char*)a->ptr + (a->len * size) ? next : NULL; \
} }

@ -40,13 +40,13 @@ extern "C" {
// for one specific upb_fielddef. Each field has a separate accessor, which // for one specific upb_fielddef. Each field has a separate accessor, which
// lives in the fielddef. // lives in the fielddef.
typedef bool upb_has_reader(void *m, upb_value fval); typedef bool upb_has_reader(const void *m, upb_value fval);
typedef upb_value upb_value_reader(void *m, upb_value fval); typedef upb_value upb_value_reader(const void *m, upb_value fval);
typedef void *upb_seqbegin_handler(void *s); typedef const void *upb_seqbegin_handler(const void *s);
typedef void *upb_seqnext_handler(void *s, void *iter); typedef const void *upb_seqnext_handler(const void *s, const void *iter);
typedef upb_value upb_seqget_handler(void *iter); typedef upb_value upb_seqget_handler(const void *iter);
INLINE bool upb_seq_done(void *iter) { return iter == NULL; } INLINE bool upb_seq_done(const void *iter) { return iter == NULL; }
typedef struct _upb_accessor_vtbl { typedef struct _upb_accessor_vtbl {
// Writers. These take an fval as a parameter because the callbacks are used // Writers. These take an fval as a parameter because the callbacks are used
@ -97,18 +97,18 @@ INLINE void upb_msg_clearbit(void *msg, const upb_fielddef *f) {
// or arrays. Also this could be desired to provide proto2 operations on // or arrays. Also this could be desired to provide proto2 operations on
// generated messages. // generated messages.
INLINE bool upb_msg_has(void *m, const upb_fielddef *f) { INLINE bool upb_msg_has(const void *m, const upb_fielddef *f) {
return f->accessor && f->accessor->has(m, f->fval); return f->accessor && f->accessor->has(m, f->fval);
} }
// May only be called for fields that have accessors. // May only be called for fields that have accessors.
INLINE upb_value upb_msg_get(void *m, const upb_fielddef *f) { INLINE upb_value upb_msg_get(const void *m, const upb_fielddef *f) {
assert(f->accessor && !upb_isseq(f)); assert(f->accessor && !upb_isseq(f));
return f->accessor->get(m, f->fval); return f->accessor->get(m, f->fval);
} }
// May only be called for fields that have accessors. // May only be called for fields that have accessors.
INLINE upb_value upb_msg_getseq(void *m, const upb_fielddef *f) { INLINE upb_value upb_msg_getseq(const void *m, const upb_fielddef *f) {
assert(f->accessor && upb_isseq(f)); assert(f->accessor && upb_isseq(f));
return f->accessor->getseq(m, f->fval); return f->accessor->getseq(m, f->fval);
} }
@ -118,21 +118,36 @@ INLINE void upb_msg_set(void *m, const upb_fielddef *f, upb_value val) {
f->accessor->set(m, f->fval, val); f->accessor->set(m, f->fval, val);
} }
INLINE void *upb_seq_begin(void *s, const upb_fielddef *f) { INLINE const void *upb_seq_begin(const void *s, const upb_fielddef *f) {
assert(f->accessor); assert(f->accessor);
return f->accessor->seqbegin(s); return f->accessor->seqbegin(s);
} }
INLINE void *upb_seq_next(void *s, void *iter, const upb_fielddef *f) { INLINE const void *upb_seq_next(const void *s, const void *iter,
const upb_fielddef *f) {
assert(f->accessor); assert(f->accessor);
assert(!upb_seq_done(iter)); assert(!upb_seq_done(iter));
return f->accessor->seqnext(s, iter); return f->accessor->seqnext(s, iter);
} }
INLINE upb_value upb_seq_get(void *iter, const upb_fielddef *f) { INLINE upb_value upb_seq_get(const void *iter, const upb_fielddef *f) {
assert(f->accessor); assert(f->accessor);
assert(!upb_seq_done(iter)); assert(!upb_seq_done(iter));
return f->accessor->seqget(iter); return f->accessor->seqget(iter);
} }
INLINE bool upb_msg_has_named(const void *m, const upb_msgdef *md,
const char *field_name) {
const upb_fielddef *f = upb_msgdef_ntof(md, field_name);
return f && upb_msg_has(m, f);
}
INLINE bool upb_msg_get_named(const void *m, const upb_msgdef *md,
const char *field_name, upb_value *val) {
const upb_fielddef *f = upb_msgdef_ntof(md, field_name);
if (!f) return false;
*val = upb_msg_get(m, f);
return true;
}
/* upb_msgvisitor *************************************************************/ /* upb_msgvisitor *************************************************************/
@ -264,30 +279,30 @@ upb_sflow_t upb_stdmsg_startsubmsg_r(void *c, upb_value fval);
/* Standard readers. **********************************************************/ /* Standard readers. **********************************************************/
bool upb_stdmsg_has(void *c, upb_value fval); bool upb_stdmsg_has(const void *c, upb_value fval);
void *upb_stdmsg_seqbegin(void *c); const void *upb_stdmsg_seqbegin(const void *c);
upb_value upb_stdmsg_getint64(void *c, upb_value fval); upb_value upb_stdmsg_getint64(const void *c, upb_value fval);
upb_value upb_stdmsg_getint32(void *c, upb_value fval); upb_value upb_stdmsg_getint32(const void *c, upb_value fval);
upb_value upb_stdmsg_getuint64(void *c, upb_value fval); upb_value upb_stdmsg_getuint64(const void *c, upb_value fval);
upb_value upb_stdmsg_getuint32(void *c, upb_value fval); upb_value upb_stdmsg_getuint32(const void *c, upb_value fval);
upb_value upb_stdmsg_getdouble(void *c, upb_value fval); upb_value upb_stdmsg_getdouble(const void *c, upb_value fval);
upb_value upb_stdmsg_getfloat(void *c, upb_value fval); upb_value upb_stdmsg_getfloat(const void *c, upb_value fval);
upb_value upb_stdmsg_getbool(void *c, upb_value fval); upb_value upb_stdmsg_getbool(const void *c, upb_value fval);
upb_value upb_stdmsg_getptr(void *c, upb_value fval); upb_value upb_stdmsg_getptr(const void *c, upb_value fval);
void *upb_stdmsg_8byte_seqnext(void *c, void *iter); const void *upb_stdmsg_8byte_seqnext(const void *c, const void *iter);
void *upb_stdmsg_4byte_seqnext(void *c, void *iter); const void *upb_stdmsg_4byte_seqnext(const void *c, const void *iter);
void *upb_stdmsg_1byte_seqnext(void *c, void *iter); const void *upb_stdmsg_1byte_seqnext(const void *c, const void *iter);
upb_value upb_stdmsg_seqgetint64(void *c); upb_value upb_stdmsg_seqgetint64(const void *c);
upb_value upb_stdmsg_seqgetint32(void *c); upb_value upb_stdmsg_seqgetint32(const void *c);
upb_value upb_stdmsg_seqgetuint64(void *c); upb_value upb_stdmsg_seqgetuint64(const void *c);
upb_value upb_stdmsg_seqgetuint32(void *c); upb_value upb_stdmsg_seqgetuint32(const void *c);
upb_value upb_stdmsg_seqgetdouble(void *c); upb_value upb_stdmsg_seqgetdouble(const void *c);
upb_value upb_stdmsg_seqgetfloat(void *c); upb_value upb_stdmsg_seqgetfloat(const void *c);
upb_value upb_stdmsg_seqgetbool(void *c); upb_value upb_stdmsg_seqgetbool(const void *c);
upb_value upb_stdmsg_seqgetptr(void *c); upb_value upb_stdmsg_seqgetptr(const void *c);
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

@ -30,6 +30,20 @@ void upb_strtomsg(const char *str, size_t len, void *msg, const upb_msgdef *md,
upb_decoder_uninit(&d); upb_decoder_uninit(&d);
} }
void *upb_filetonewmsg(const char *fname, const upb_msgdef *md, upb_status *s) {
void *msg = upb_stdmsg_new(md);
size_t len;
char *data = upb_readfile(fname, &len);
if (!data) goto err;
upb_strtomsg(data, len, msg, md, s);
if (!upb_ok(s)) goto err;
return msg;
err:
upb_stdmsg_free(msg, md);
return NULL;
}
#if 0 #if 0
void upb_msgtotext(upb_string *str, upb_msg *msg, upb_msgdef *md, void upb_msgtotext(upb_string *str, upb_msg *msg, upb_msgdef *md,
bool single_line) { bool single_line) {

@ -28,21 +28,20 @@
#include <stdbool.h> #include <stdbool.h>
#include "upb/upb.h" #include "upb/upb.h"
#include "upb/def.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
// Forward-declares so we don't have to include everything in this .h file.
// Clients should use the regular, typedef'd names (eg. upb_string).
struct _upb_msg;
struct _upb_msgdef;
struct _upb_symtab;
// Decodes the given string, which must be in protobuf binary format, to the // Decodes the given string, which must be in protobuf binary format, to the
// given upb_msg with msgdef "md", storing the status of the operation in "s". // given upb_msg with msgdef "md", storing the status of the operation in "s".
void upb_strtomsg(const char *str, size_t len, void *msg, void upb_strtomsg(const char *str, size_t len, void *msg,
const struct _upb_msgdef *md, upb_status *s); const upb_msgdef *md, upb_status *s);
// Parses the given file into a new message of the given type. Caller owns
// the returned message (or NULL if an error occurred).
void *upb_filetonewmsg(const char *fname, const upb_msgdef *md, upb_status *s);
//void upb_msgtotext(struct _upb_string *str, void *msg, //void upb_msgtotext(struct _upb_string *str, void *msg,
// struct _upb_msgdef *md, bool single_line); // struct _upb_msgdef *md, bool single_line);
@ -56,12 +55,12 @@ upb_def **upb_load_defs_from_descriptor(const char *str, size_t len, int *n,
upb_status *status); upb_status *status);
// Like the previous but also adds the loaded defs to the given symtab. // Like the previous but also adds the loaded defs to the given symtab.
bool upb_load_descriptor_into_symtab(struct _upb_symtab *symtab, const char *str, bool upb_load_descriptor_into_symtab(upb_symtab *symtab, const char *str,
size_t len, upb_status *status); size_t len, upb_status *status);
// Like the previous but also reads the descriptor from the given filename. // Like the previous but also reads the descriptor from the given filename.
bool upb_load_descriptor_file_into_symtab(struct _upb_symtab *symtab, bool upb_load_descriptor_file_into_symtab(upb_symtab *symtab, const char *fname,
const char *fname, upb_status *status); upb_status *status);
// Reads the given filename into a character string, returning NULL if there // Reads the given filename into a character string, returning NULL if there
// was an error. // was an error.

@ -149,9 +149,10 @@ INLINE size_t _upb_inttable_entrysize(size_t value_size) {
return upb_align_up(sizeof(upb_inttable_header) + value_size, 8); return upb_align_up(sizeof(upb_inttable_header) + value_size, 8);
} }
INLINE void *upb_inttable_fastlookup(upb_inttable *t, uint32_t key, INLINE void *upb_inttable_fastlookup(const upb_inttable *t, uint32_t key,
uint32_t value_size) { uint32_t value_size) {
return _upb_inttable_fastlookup(t, key, _upb_inttable_entrysize(value_size), value_size); return _upb_inttable_fastlookup(
t, key, _upb_inttable_entrysize(value_size), value_size);
} }
INLINE void *upb_inttable_lookup(upb_inttable *t, uint32_t key) { INLINE void *upb_inttable_lookup(upb_inttable *t, uint32_t key) {

Loading…
Cancel
Save