summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorJoshua Haberman <joshua@reverberate.org>2010-08-02 10:25:24 -0700
committerJoshua Haberman <joshua@reverberate.org>2010-08-02 10:25:24 -0700
commita9e998159c5ac8c4f2644b5ed0eda2e8ff1f8706 (patch)
treefc9324a56042e65d96ac04a4b39412783062007e /core
parent4e7dc9d8b6baa598ec63a9991e8b11aede576ac1 (diff)
Fleshed out upb_msg: test_vs_proto2 compiles but fails.
Diffstat (limited to 'core')
-rw-r--r--core/upb.h98
-rw-r--r--core/upb_atomic.h4
-rw-r--r--core/upb_def.c65
-rw-r--r--core/upb_def.h28
-rw-r--r--core/upb_msg.c123
-rw-r--r--core/upb_msg.h114
6 files changed, 408 insertions, 24 deletions
diff --git a/core/upb.h b/core/upb.h
index b605fd9..7ee0469 100644
--- a/core/upb.h
+++ b/core/upb.h
@@ -80,24 +80,16 @@ enum upb_wire_type {
typedef uint8_t upb_wire_type_t;
-// Value type as defined in a .proto file. eg. string, int32, etc. The
+// Type of a field as defined in a .proto file. eg. string, int32, etc. The
// integers that represent this are defined by descriptor.proto. Note that
// descriptor.proto reserves "0" for errors, and we use it to represent
// exceptional circumstances.
-typedef uint8_t upb_field_type_t;
+typedef uint8_t upb_fieldtype_t;
// For referencing the type constants tersely.
#define UPB_TYPE(type) GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_ ## type
#define UPB_LABEL(type) GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_ ## type
-INLINE bool upb_issubmsgtype(upb_field_type_t type) {
- return type == UPB_TYPE(GROUP) || type == UPB_TYPE(MESSAGE);
-}
-
-INLINE bool upb_isstringtype(upb_field_type_t type) {
- return type == UPB_TYPE(STRING) || type == UPB_TYPE(BYTES);
-}
-
// Info for a given field type.
typedef struct {
uint8_t align;
@@ -129,6 +121,10 @@ typedef union {
struct _upb_string;
typedef struct _upb_string upb_string;
+struct _upb_array;
+typedef struct _upb_array upb_array;
+struct _upb_msg;
+typedef struct _upb_msg upb_msg;
typedef uint32_t upb_strlen_t;
@@ -142,6 +138,11 @@ typedef union {
uint32_t uint32;
uint64_t uint64;
bool _bool;
+ upb_string *str;
+ upb_msg *msg;
+ upb_array *arr;
+ upb_atomic_refcount_t *refcount;
+ void *_void;
} upb_value;
// A pointer to a .proto value. The owner must have an out-of-band way of
@@ -155,13 +156,90 @@ typedef union {
uint32_t *uint32;
uint64_t *uint64;
bool *_bool;
+ upb_string **str;
+ upb_msg **msg;
+ upb_array **arr;
+ void *_void;
} upb_valueptr;
+// The type of a upb_value. This is like a upb_fieldtype_t, but adds the
+// constant UPB_VALUETYPE_ARRAY to represent an array.
+typedef uint8_t upb_valuetype_t;
+#define UPB_VALUETYPE_ARRAY 32
+
INLINE upb_valueptr upb_value_addrof(upb_value *val) {
upb_valueptr ptr = {&val->_double};
return ptr;
}
+// Converts upb_value_ptr -> upb_value by reading from the pointer. We need to
+// know the value type to perform this operation, because we need to know how
+// much memory to copy.
+INLINE upb_value upb_value_read(upb_valueptr ptr, upb_fieldtype_t ft) {
+ upb_value val;
+
+#define CASE(t, member_name) \
+ case UPB_TYPE(t): val.member_name = *ptr.member_name; break;
+
+ switch(ft) {
+ CASE(DOUBLE, _double)
+ CASE(FLOAT, _float)
+ CASE(INT32, int32)
+ CASE(INT64, int64)
+ CASE(UINT32, uint32)
+ CASE(UINT64, uint64)
+ CASE(SINT32, int32)
+ CASE(SINT64, int64)
+ CASE(FIXED32, uint32)
+ CASE(FIXED64, uint64)
+ CASE(SFIXED32, int32)
+ CASE(SFIXED64, int64)
+ CASE(BOOL, _bool)
+ CASE(ENUM, int32)
+ CASE(STRING, str)
+ CASE(BYTES, str)
+ CASE(MESSAGE, msg)
+ CASE(GROUP, msg)
+ default: break;
+ }
+ return val;
+
+#undef CASE
+}
+
+// Writes a upb_value to a upb_value_ptr location. We need to know the value
+// type to perform this operation, because we need to know how much memory to
+// copy.
+INLINE void upb_value_write(upb_valueptr ptr, upb_value val,
+ upb_fieldtype_t ft) {
+#define CASE(t, member_name) \
+ case UPB_TYPE(t): *ptr.member_name = val.member_name; break;
+
+ switch(ft) {
+ CASE(DOUBLE, _double)
+ CASE(FLOAT, _float)
+ CASE(INT32, int32)
+ CASE(INT64, int64)
+ CASE(UINT32, uint32)
+ CASE(UINT64, uint64)
+ CASE(SINT32, int32)
+ CASE(SINT64, int64)
+ CASE(FIXED32, uint32)
+ CASE(FIXED64, uint64)
+ CASE(SFIXED32, int32)
+ CASE(SFIXED64, int64)
+ CASE(BOOL, _bool)
+ CASE(ENUM, int32)
+ CASE(STRING, str)
+ CASE(BYTES, str)
+ CASE(MESSAGE, msg)
+ CASE(GROUP, msg)
+ default: break;
+ }
+
+#undef CASE
+}
+
// Status codes used as a return value. Codes >0 are not fatal and can be
// resumed.
enum upb_status_code {
diff --git a/core/upb_atomic.h b/core/upb_atomic.h
index 01fc8a2..1cd848b 100644
--- a/core/upb_atomic.h
+++ b/core/upb_atomic.h
@@ -127,6 +127,10 @@ INLINE bool upb_atomic_unref(upb_atomic_refcount_t *a) {
Implement them or compile with UPB_THREAD_UNSAFE.
#endif
+INLINE bool upb_atomic_only(upb_atomic_refcount_t *a) {
+ return upb_atomic_read(a) == 1;
+}
+
/* Reader/Writer lock. ********************************************************/
#ifdef UPB_THREAD_UNSAFE
diff --git a/core/upb_def.c b/core/upb_def.c
index e117455..1c8fbdc 100644
--- a/core/upb_def.c
+++ b/core/upb_def.c
@@ -12,6 +12,16 @@
#define CHECKSRC(x) if(!(x)) goto src_err
#define CHECK(x) if(!(x)) goto err
+/* Rounds p up to the next multiple of t. */
+static size_t upb_align_up(size_t val, size_t align) {
+ return val % align == 0 ? val : val + align - (val % align);
+}
+
+static int upb_div_round_up(int numerator, int denominator) {
+ /* cf. http://stackoverflow.com/questions/17944/how-to-round-up-the-result-of-integer-division */
+ return numerator > 0 ? (numerator - 1) / denominator + 1 : 0;
+}
+
// A little dynamic array for storing a growing list of upb_defs.
typedef struct {
upb_def **defs;
@@ -409,6 +419,19 @@ src_err:
/* upb_msgdef *****************************************************************/
+static int upb_compare_typed_fields(upb_fielddef *f1, upb_fielddef *f2) {
+ // Sort by data size (ascending) to reduce padding.
+ size_t size1 = upb_types[f1->type].size;
+ size_t size2 = upb_types[f2->type].size;
+ if (size1 != size2) return size1 - size2;
+ // Otherwise return in number order (just so we get a reproduceable order.
+ return f1->number - f2->number;
+}
+
+static int upb_compare_fields(const void *f1, const void *f2) {
+ return upb_compare_typed_fields(*(void**)f1, *(void**)f2);
+}
+
// Processes a google.protobuf.DescriptorProto, adding defs to "defs."
static bool upb_addmsg(upb_src *src, upb_deflist *defs, upb_status *status)
{
@@ -418,7 +441,6 @@ static bool upb_addmsg(upb_src *src, upb_deflist *defs, upb_status *status)
upb_inttable_init(&m->itof, 4, sizeof(upb_itof_ent));
upb_strtable_init(&m->ntof, 4, sizeof(upb_ntof_ent));
int32_t start_count = defs->len;
-
upb_fielddef *f;
while((f = upb_src_getdef(src)) != NULL) {
switch(f->number) {
@@ -451,6 +473,45 @@ static bool upb_addmsg(upb_src *src, upb_deflist *defs, upb_status *status)
upb_seterr(status, UPB_STATUS_ERROR, "Encountered message with no name.");
goto err;
}
+
+
+ // Create an ordering over the fields.
+ upb_field_count_t n = upb_msgdef_numfields(m);
+ upb_fielddef **sorted_fields = malloc(sizeof(upb_fielddef*) * n);
+ upb_field_count_t field = 0;
+ upb_msg_iter i;
+ for (i = upb_msg_begin(m); !upb_msg_done(i); i = upb_msg_next(m, i)) {
+ sorted_fields[field++]= upb_msg_iter_field(i);
+ }
+ qsort(sorted_fields, n, sizeof(*sorted_fields), upb_compare_fields);
+
+ // Assign offsets in the msg.
+ m->set_flags_bytes = upb_div_round_up(n, 8);
+ m->size = sizeof(upb_atomic_refcount_t) + m->set_flags_bytes;
+
+ size_t max_align = 0;
+ for (int i = 0; i < n; i++) {
+ upb_fielddef *f = sorted_fields[i];
+ upb_type_info *type_info = &upb_types[f->type];
+
+ // This identifies the set bit. When we implement is_initialized (a
+ // general check about whether all required bits are set) we will probably
+ // want to use a different ordering that puts all the required bits
+ // together.
+ f->field_index = i;
+
+ // General alignment rules are: each member must be at an address that is a
+ // multiple of that type's alignment. Also, the size of the structure as a
+ // whole must be a multiple of the greatest alignment of any member.
+ size_t offset = upb_align_up(m->size, type_info->align);
+ // Offsets are relative to the end of the refcount.
+ f->byte_offset = offset - sizeof(upb_atomic_refcount_t);
+ m->size = offset + type_info->size;
+ max_align = UPB_MAX(max_align, type_info->align);
+ }
+
+ if (max_align > 0) m->size = upb_align_up(m->size, max_align);
+
upb_deflist_qualify(defs, m->base.fqname, start_count);
upb_deflist_push(defs, UPB_UPCAST(m));
return true;
@@ -664,7 +725,7 @@ bool upb_resolverefs(upb_strtable *tmptab, upb_strtable *symtab,
}
// Check the type of the found def.
- upb_field_type_t expected = upb_issubmsg(f) ? UPB_DEF_MSG : UPB_DEF_ENUM;
+ upb_fieldtype_t expected = upb_issubmsg(f) ? UPB_DEF_MSG : UPB_DEF_ENUM;
if(found->def->type != expected) {
upb_seterr(status, UPB_STATUS_ERROR, "Unexpected type");
return false;
diff --git a/core/upb_def.h b/core/upb_def.h
index 3294a8d..9eb961a 100644
--- a/core/upb_def.h
+++ b/core/upb_def.h
@@ -103,7 +103,7 @@ typedef struct _upb_fielddef {
upb_field_count_t field_index; // Indicates set bit.
upb_field_number_t number;
- upb_field_type_t type;
+ upb_fieldtype_t type;
upb_label_t label;
// True if we own a ref on "def" (above). This is true unless this edge is
// part of a cycle.
@@ -112,10 +112,10 @@ typedef struct _upb_fielddef {
// A variety of tests about the type of a field.
INLINE bool upb_issubmsg(upb_fielddef *f) {
- return upb_issubmsgtype(f->type);
+ return f->type == UPB_TYPE(GROUP) || f->type == UPB_TYPE(MESSAGE);
}
INLINE bool upb_isstring(upb_fielddef *f) {
- return upb_isstringtype(f->type);
+ return f->type == UPB_TYPE(STRING) || f->type == UPB_TYPE(BYTES);
}
INLINE bool upb_isarray(upb_fielddef *f) {
return f->label == UPB_LABEL(REPEATED);
@@ -125,6 +125,19 @@ INLINE bool upb_hasdef(upb_fielddef *f) {
return upb_issubmsg(f) || f->type == UPB_TYPE(ENUM);
}
+INLINE upb_valuetype_t upb_field_valuetype(upb_fielddef *f) {
+ if (upb_isarray(f)) {
+ return UPB_VALUETYPE_ARRAY;
+ } else {
+ return f->type;
+ }
+}
+
+INLINE upb_valuetype_t upb_elem_valuetype(upb_fielddef *f) {
+ assert(upb_isarray(f));
+ return f->type;
+}
+
INLINE bool upb_field_ismm(upb_fielddef *f) {
return upb_isarray(f) || upb_isstring(f) || upb_issubmsg(f);
}
@@ -139,6 +152,8 @@ INLINE bool upb_elem_ismm(upb_fielddef *f) {
typedef struct _upb_msgdef {
upb_def base;
upb_atomic_refcount_t cycle_refcount;
+ uint32_t size;
+ uint32_t set_flags_bytes;
// Tables for looking up fields by number and name.
upb_inttable itof; // int to field
@@ -169,9 +184,14 @@ INLINE upb_fielddef *upb_msgdef_ntof(upb_msgdef *m, upb_string *name) {
return e ? e->f : NULL;
}
+INLINE upb_field_count_t upb_msgdef_numfields(upb_msgdef *m) {
+ return upb_strtable_count(&m->ntof);
+}
+
// Iteration over fields. The order is undefined.
// upb_msg_iter i;
-// for(i = upb_msg_begin(m); !upb_msg_done(&i); i = upb_msg_next(&i)) {
+// for(i = upb_msg_begin(m); !upb_msg_done(i); i = upb_msg_next(m, i)) {
+// upb_fielddef *f = upb_msg_iter_field(i);
// // ...
// }
typedef upb_itof_ent *upb_msg_iter;
diff --git a/core/upb_msg.c b/core/upb_msg.c
new file mode 100644
index 0000000..75f7a35
--- /dev/null
+++ b/core/upb_msg.c
@@ -0,0 +1,123 @@
+/*
+ * upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2010 Joshua Haberman. See LICENSE for details.
+ *
+ * Data structure for storing a message of protobuf data.
+ */
+
+#include "upb_msg.h"
+
+void _upb_elem_free(upb_value v, upb_fielddef *f) {
+ switch(f->type) {
+ case UPB_TYPE(MESSAGE):
+ case UPB_TYPE(GROUP):
+ _upb_msg_free(v.msg, upb_downcast_msgdef(f->def));
+ break;
+ case UPB_TYPE(STRING):
+ case UPB_TYPE(BYTES):
+ _upb_string_free(v.str);
+ break;
+ default:
+ abort();
+ }
+}
+
+void _upb_field_free(upb_value v, upb_fielddef *f) {
+ if (upb_isarray(f)) {
+ _upb_array_free(v.arr, f);
+ } else {
+ _upb_elem_free(v, f);
+ }
+}
+
+upb_msg *upb_msg_new(upb_msgdef *md) {
+ upb_msg *msg = malloc(md->size);
+ // Clear all set bits and cached pointers.
+ memset(msg, 0, md->size);
+ upb_atomic_refcount_init(&msg->refcount, 1);
+ return msg;
+}
+
+void _upb_msg_free(upb_msg *msg, upb_msgdef *md) {
+ // Need to release refs on all sub-objects.
+ upb_msg_iter i;
+ for(i = upb_msg_begin(md); !upb_msg_done(i); i = upb_msg_next(md, i)) {
+ upb_fielddef *f = upb_msg_iter_field(i);
+ upb_valueptr p = _upb_msg_getptr(msg, f);
+ upb_valuetype_t type = upb_field_valuetype(f);
+ if (upb_field_ismm(f)) _upb_field_unref(upb_value_read(p, type), f);
+ }
+ free(msg);
+}
+
+upb_array *upb_array_new(void) {
+ upb_array *arr = malloc(sizeof(*arr));
+ upb_atomic_refcount_init(&arr->refcount, 1);
+ arr->size = 0;
+ arr->len = 0;
+ arr->elements._void = NULL;
+ return arr;
+}
+
+void _upb_array_free(upb_array *arr, upb_fielddef *f) {
+ if (upb_elem_ismm(f)) {
+ // Need to release refs on sub-objects.
+ upb_valuetype_t type = upb_elem_valuetype(f);
+ for (upb_arraylen_t i = 0; i < arr->size; i++) {
+ upb_valueptr p = _upb_array_getptr(arr, f, i);
+ _upb_elem_unref(upb_value_read(p, type), f);
+ }
+ }
+ if (arr->elements._void) free(arr->elements._void);
+ free(arr);
+}
+
+upb_value upb_field_new(upb_fielddef *f, upb_valuetype_t type) {
+ upb_value v;
+ switch(type) {
+ case UPB_TYPE(MESSAGE):
+ case UPB_TYPE(GROUP):
+ v.msg = upb_msg_new(upb_downcast_msgdef(f->def));
+ case UPB_TYPE(STRING):
+ case UPB_TYPE(BYTES):
+ v.str = upb_string_new();
+ case UPB_VALUETYPE_ARRAY:
+ v.arr = upb_array_new();
+ default:
+ abort();
+ }
+ return v;
+}
+
+static void upb_field_recycle(upb_value val) {
+ (void)val;
+}
+
+upb_value upb_field_tryrecycle(upb_valueptr p, upb_value val, upb_fielddef *f,
+ upb_valuetype_t type) {
+ if (val._void == NULL || !upb_atomic_only(val.refcount)) {
+ if (val._void != NULL) upb_atomic_unref(val.refcount);
+ val = upb_field_new(f, type);
+ upb_value_write(p, val, type);
+ } else {
+ upb_field_recycle(val);
+ }
+ return val;
+}
+
+void upb_msg_decodestr(upb_msg *msg, upb_msgdef *md, upb_string *str,
+ upb_status *status) {
+ (void)msg;
+ (void)md;
+ (void)str;
+ (void)status;
+}
+
+void upb_msg_encodestr(upb_msg *msg, upb_msgdef *md, upb_string *str,
+ upb_status *status) {
+ (void)msg;
+ (void)md;
+ (void)str;
+ (void)status;
+}
diff --git a/core/upb_msg.h b/core/upb_msg.h
index 5215bd9..2db67c0 100644
--- a/core/upb_msg.h
+++ b/core/upb_msg.h
@@ -9,14 +9,39 @@
#ifndef UPB_MSG_H
#define UPB_MSG_H
+#include "upb.h"
+#include "upb_def.h"
+#include <stdlib.h>
+
#ifdef __cplusplus
extern "C" {
#endif
-typedef struct {
+upb_value upb_field_tryrecycle(upb_valueptr p, upb_value v, upb_fielddef *f,
+ upb_valuetype_t type);
+
+INLINE void _upb_value_ref(upb_value v) { upb_atomic_ref(v.refcount); }
+
+void _upb_field_free(upb_value v, upb_fielddef *f);
+void _upb_elem_free(upb_value v, upb_fielddef *f);
+INLINE void _upb_field_unref(upb_value v, upb_fielddef *f) {
+ assert(upb_field_ismm(f));
+ if (v.refcount && upb_atomic_unref(v.refcount))
+ _upb_field_free(v, f);
+}
+INLINE void _upb_elem_unref(upb_value v, upb_fielddef *f) {
+ assert(upb_elem_ismm(f));
+ if (v.refcount && upb_atomic_unref(v.refcount))
+ _upb_elem_free(v, f);
+}
+
+/* upb_array ******************************************************************/
+
+typedef uint32_t upb_arraylen_t;
+struct _upb_array {
upb_atomic_refcount_t refcount;
- uint32_t len;
- uint32_t size;
+ upb_arraylen_t len;
+ upb_arraylen_t size;
upb_valueptr elements;
};
@@ -31,29 +56,70 @@ INLINE void upb_array_unref(upb_array *a, upb_fielddef *f) {
if (upb_atomic_unref(&a->refcount)) _upb_array_free(a, f);
}
+INLINE upb_valueptr _upb_array_getptr(upb_array *a, upb_fielddef *f,
+ uint32_t elem) {
+ upb_valueptr p;
+ p._void = &a->elements.uint8[elem * upb_types[f->type].size];
+ return p;
+}
+
INLINE upb_value upb_array_get(upb_array *a, upb_fielddef *f, uint32_t elem) {
assert(elem < upb_array_len(a));
return upb_value_read(_upb_array_getptr(a, f, elem), f->type);
}
// For string or submessages, will release a ref on the previously set value.
+// and take a ref on the new value. The array must already be at least "elem"
+// long; to append use append_mutable.
INLINE void upb_array_set(upb_array *a, upb_fielddef *f, uint32_t elem,
upb_value val) {
+ assert(elem < upb_array_len(a));
+ upb_valueptr p = _upb_array_getptr(a, f, elem);
+ if (upb_elem_ismm(f)) {
+ _upb_elem_unref(upb_value_read(p, f->type), f);
+ _upb_value_ref(val);
+ }
+ upb_value_write(p, val, f->type);
}
-// Append an element with the default value, returning it. For strings or
-// submessages, this will try to reuse previously allocated memory.
-INLINE upb_value upb_array_append_mutable(upb_array *a, upb_fielddef *f) {
+INLINE void upb_array_resize(upb_array *a, upb_fielddef *f) {
+ if (a->len == a->size) {
+ a->len *= 2;
+ a->elements._void = realloc(a->elements._void,
+ a->len * upb_types[f->type].size);
+ }
}
-typedef struct {
+// Append an element to an array of string or submsg with the default value,
+// returning it. This will try to reuse previously allocated memory.
+INLINE upb_value upb_array_appendmutable(upb_array *a, upb_fielddef *f) {
+ assert(upb_elem_ismm(f));
+ upb_array_resize(a, f);
+ upb_valueptr p = _upb_array_getptr(a, f, a->len++);
+ upb_valuetype_t type = upb_elem_valuetype(f);
+ upb_value val = upb_value_read(p, type);
+ val = upb_field_tryrecycle(p, val, f, type);
+ return val;
+}
+
+
+/* upb_msg ********************************************************************/
+
+struct _upb_msg {
upb_atomic_refcount_t refcount;
uint8_t data[4]; // We allocate the appropriate amount per message.
-} upb_msg;
+};
// Creates a new msg of the given type.
upb_msg *upb_msg_new(upb_msgdef *md);
+// Returns a pointer to the given field.
+INLINE upb_valueptr _upb_msg_getptr(upb_msg *msg, upb_fielddef *f) {
+ upb_valueptr p;
+ p._void = &msg->data[f->byte_offset];
+ return p;
+}
+
void _upb_msg_free(upb_msg *msg, upb_msgdef *md);
INLINE void upb_msg_unref(upb_msg *msg, upb_msgdef *md) {
if (upb_atomic_unref(&msg->refcount)) _upb_msg_free(msg, md);
@@ -65,6 +131,10 @@ INLINE bool upb_msg_has(upb_msg *msg, upb_fielddef *f) {
return (msg->data[f->field_index/8] & (1 << (f->field_index % 8))) != 0;
}
+INLINE void upb_msg_sethas(upb_msg *msg, upb_fielddef *f) {
+ msg->data[f->field_index/8] |= (1 << (f->field_index % 8));
+}
+
// Returns the current value of the given field if set, or the default value if
// not set.
INLINE upb_value upb_msg_get(upb_msg *msg, upb_fielddef *f) {
@@ -79,12 +149,29 @@ INLINE upb_value upb_msg_get(upb_msg *msg, upb_fielddef *f) {
// Otherwise sets it and returns an empty instance, attempting to reuse any
// previously allocated memory.
INLINE upb_value upb_msg_getmutable(upb_msg *msg, upb_fielddef *f) {
+ assert(upb_field_ismm(f));
+ upb_valueptr p = _upb_msg_getptr(msg, f);
+ upb_valuetype_t type = upb_field_valuetype(f);
+ upb_value val = upb_value_read(p, type);
+ if (!upb_msg_has(msg, f)) {
+ upb_msg_sethas(msg, f);
+ val = upb_field_tryrecycle(p, val, f, type);
+ }
+ return val;
}
// Sets the current value of the field. If this is a string, array, or
// submessage field, releases a ref on the value (if any) that was previously
// set.
INLINE void upb_msg_set(upb_msg *msg, upb_fielddef *f, upb_value val) {
+ upb_valueptr p = _upb_msg_getptr(msg, f);
+ upb_valuetype_t type = upb_field_valuetype(f);
+ if (upb_field_ismm(f)) {
+ _upb_field_unref(upb_value_read(p, type), f);
+ _upb_value_ref(val);
+ }
+ upb_msg_sethas(msg, f);
+ upb_value_write(p, val, upb_field_valuetype(f));
}
// Unsets all field values back to their defaults.
@@ -92,6 +179,17 @@ INLINE void upb_msg_clear(upb_msg *msg, upb_msgdef *md) {
memset(msg->data, 0, md->set_flags_bytes);
}
+// A convenience function for decoding an entire protobuf all at once, without
+// having to worry about setting up the appropriate objects.
+void upb_msg_decodestr(upb_msg *msg, upb_msgdef *md, upb_string *str,
+ upb_status *status);
+
+// A convenience function for encoding an entire protobuf all at once. If an
+// error occurs, the null string is returned and the status object contains
+// the error.
+void upb_msg_encodestr(upb_msg *msg, upb_msgdef *md, upb_string *str,
+ upb_status *status);
+
#ifdef __cplusplus
} /* extern "C" */
#endif
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback