From 559e23c796f973a65d05c76e211835b126ee8ac8 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Fri, 17 Jun 2011 10:34:29 -0700 Subject: Major refactoring: abandon upb_msg, add upb_accessors. Next on the chopping block is upb_string. --- src/upb_def.h | 371 ++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 228 insertions(+), 143 deletions(-) (limited to 'src/upb_def.h') diff --git a/src/upb_def.h b/src/upb_def.h index 776231a..ca969cb 100644 --- a/src/upb_def.h +++ b/src/upb_def.h @@ -4,25 +4,16 @@ * Copyright (c) 2009-2011 Google Inc. See LICENSE for details. * Author: Josh Haberman * - * Provides a mechanism for loading proto definitions from descriptors, and - * data structures to represent those definitions. These form the protobuf - * schema, and are used extensively throughout upb: + * Provides a mechanism for creating and linking proto definitions. + * These form the protobuf schema, and are used extensively throughout upb: * - upb_msgdef: describes a "message" construct. * - upb_fielddef: describes a message field. * - upb_enumdef: describes an enum. - * (TODO: definitions of extensions and services). + * (TODO: definitions of services). * - * Defs are obtained from a upb_symtab object. A upb_symtab is empty when - * constructed, and definitions can be added by supplying descriptors. - * - * Defs are immutable and reference-counted. Symbol tables reference any defs - * that are the "current" definitions. If an extension is loaded that adds a - * field to an existing message, a new msgdef is constructed that includes the - * new field and the old msgdef is unref'd. The old msgdef will still be ref'd - * by messages (if any) that were constructed with that msgdef. - * - * This file contains routines for creating and manipulating the definitions - * themselves. To create and manipulate actual messages, see upb_msg.h. + * These defs are mutable (and not thread-safe) when first created. + * Once they are added to a defbuilder (and later its symtab) they become + * immutable. */ #ifndef UPB_DEF_H_ @@ -35,51 +26,37 @@ extern "C" { #endif -/* upb_def: base class for defs **********************************************/ +struct _upb_symtab; +typedef struct _upb_symtab upb_symtab; // All the different kind of defs we support. These correspond 1:1 with // declarations in a .proto file. typedef enum { UPB_DEF_MSG = 0, UPB_DEF_ENUM, - UPB_DEF_SVC, - UPB_DEF_EXT, - // Internal-only, placeholder for a def that hasn't be resolved yet. - UPB_DEF_UNRESOLVED, + UPB_DEF_SERVICE, // Not yet implemented. - // For specifying that defs of any type are requsted from getdefs. - UPB_DEF_ANY = -1 -} upb_deftype; + UPB_DEF_ANY = -1, // Wildcard for upb_symtab_get*() + UPB_DEF_UNRESOLVED = 99, // Internal-only. +} upb_deftype_t; -// This typedef is more space-efficient than declaring an enum var directly. -typedef int8_t upb_deftype_t; + +/* upb_def: base class for defs **********************************************/ typedef struct { - upb_string *fqname; // Fully qualified. - upb_atomic_t refcount; + upb_string *fqname; // Fully qualified. + upb_symtab *symtab; // Def is mutable iff symtab == NULL. + upb_atomic_t refcount; // Owns a ref on symtab iff (symtab && refcount > 0). upb_deftype_t type; - - // The is_cyclic flag could go in upb_msgdef instead of here, because only - // messages can be involved in cycles. However, putting them here is free - // from a space perspective because structure alignment will otherwise leave - // three bytes empty after type. It is also makes ref and unref more - // efficient, because we don't have to downcast to msgdef before checking the - // is_cyclic flag. - bool is_cyclic; - uint16_t search_depth; // Used during initialization dfs. } upb_def; -// These must not be called directly! -void _upb_def_cyclic_ref(upb_def *def); -void _upb_def_reftozero(upb_def *def); - -// Call to ref/deref a def. -INLINE void upb_def_ref(upb_def *def) { - if(upb_atomic_ref(&def->refcount) && def->is_cyclic) _upb_def_cyclic_ref(def); -} -INLINE void upb_def_unref(upb_def *def) { - if(def && upb_atomic_unref(&def->refcount)) _upb_def_reftozero(def); -} +// Call to ref/unref a def. Can be used at any time, but is not thread-safe +// until the def is in a symtab. While a def is in a symtab, everything +// reachable from that def (the symtab and all defs in the symtab) are +// guaranteed to be alive. +void upb_def_ref(upb_def *def); +void upb_def_unref(upb_def *def); +upb_def *upb_def_dup(upb_def *def); #define UPB_UPCAST(ptr) (&(ptr)->base) @@ -88,30 +65,66 @@ INLINE void upb_def_unref(upb_def *def) { // A upb_fielddef describes a single field in a message. It isn't a full def // in the sense that it derives from upb_def. It cannot stand on its own; it -// is either a field of a upb_msgdef or contained inside a upb_extensiondef. -// It is also reference-counted. +// must be part of a upb_msgdef. It is also reference-counted. struct _upb_fielddef { - uint8_t type; - uint8_t label; - // True if we own a ref on "def" (above). This is true unless this edge is - // part of a cycle. - bool owned; - uint8_t set_bit_mask; + struct _upb_msgdef *msgdef; + upb_def *def; // if upb_hasdef(f) + upb_atomic_t refcount; + bool finalized; + // The following fields may be modified until the def is finalized. + uint8_t type; // Use UPB_TYPE() constants. + uint8_t label; // Use UPB_LABEL() constants. + int16_t hasbit; + uint16_t offset; int32_t number; - int16_t field_index; // Indicates set bit. + upb_string *name; + upb_value defaultval; // Only meaningful for non-repeated scalars and strings. + upb_value fval; + struct _upb_accessor_vtbl *accessor; +}; - uint16_t set_bit_offset; - uint32_t byte_offset; // Where in a upb_msg to find the data. +upb_fielddef *upb_fielddef_new(); +void upb_fielddef_ref(upb_fielddef *f); +void upb_fielddef_unref(upb_fielddef *f); +upb_fielddef *upb_fielddef_dup(upb_fielddef *f); + +// Read accessors. May be called any time. +INLINE uint8_t upb_fielddef_type(upb_fielddef *f) { return f->type; } +INLINE uint8_t upb_fielddef_label(upb_fielddef *f) { return f->label; } +INLINE int32_t upb_fielddef_number(upb_fielddef *f) { return f->number; } +INLINE upb_string *upb_fielddef_name(upb_fielddef *f) { return f->name; } +INLINE upb_value upb_fielddef_default(upb_fielddef *f) { return f->defaultval; } +INLINE upb_value upb_fielddef_fval(upb_fielddef *f) { return f->fval; } +INLINE bool upb_fielddef_finalized(upb_fielddef *f) { return f->finalized; } +INLINE struct _upb_msgdef *upb_fielddef_msgdef(upb_fielddef *f) { + return f->msgdef; +} +INLINE struct _upb_accessor_vtbl *upb_fielddef_accessor(upb_fielddef *f) { + return f->accessor; +} - upb_value default_value; - upb_string *name; - struct _upb_msgdef *msgdef; +// Only meaningful once the def is in a symtab (returns NULL otherwise, or for +// a fielddef where !upb_hassubdef(f)). +upb_def *upb_fielddef_subdef(upb_fielddef *f); - // For the case of an enum or a submessage, points to the def for that type. - upb_def *def; - upb_atomic_t refcount; -}; +// NULL until the fielddef has been added to a msgdef. + +// Write accessors. "Number" and "name" must be set before the fielddef is +// added to a msgdef. For the moment we do not allow these to be set once +// the fielddef is added to a msgdef -- this could be relaxed in the future. +void upb_fielddef_setnumber(upb_fielddef *f, int32_t number); +void upb_fielddef_setname(upb_fielddef *f, upb_string *name); + +// These writers may be called at any time prior to being put in a symtab. +void upb_fielddef_settype(upb_fielddef *f, uint8_t type); +void upb_fielddef_setlabel(upb_fielddef *f, uint8_t label); +void upb_fielddef_setdefault(upb_fielddef *f, upb_value value); +void upb_fielddef_setfval(upb_fielddef *f, upb_value fval); +void upb_fielddef_setaccessor(upb_fielddef *f, struct _upb_accessor_vtbl *vtbl); +// The name of the message or enum this field is referring to. Must be found +// at name resolution time (when the symtabtxn is committed to the symtab). +void upb_fielddef_settypename(upb_fielddef *f, upb_string *name); // A variety of tests about the type of a field. INLINE bool upb_issubmsgtype(upb_fieldtype_t type) { @@ -125,58 +138,35 @@ INLINE bool upb_isprimitivetype(upb_fieldtype_t type) { } INLINE bool upb_issubmsg(upb_fielddef *f) { return upb_issubmsgtype(f->type); } INLINE bool upb_isstring(upb_fielddef *f) { return upb_isstringtype(f->type); } -INLINE bool upb_isarray(upb_fielddef *f) { - return f->label == UPB_LABEL(REPEATED); -} +INLINE bool upb_isseq(upb_fielddef *f) { return f->label == UPB_LABEL(REPEATED); } + // Does the type of this field imply that it should contain an associated def? 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); -} - -INLINE bool upb_elem_ismm(upb_fielddef *f) { - return upb_isstring(f) || upb_issubmsg(f); -} /* upb_msgdef *****************************************************************/ // Structure that describes a single .proto message type. typedef struct _upb_msgdef { upb_def base; - upb_atomic_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 upb_strtable ntof; // name to field - // Immutable msg instance that has all default values set. - // TODO: need a way of making this immutable! - struct _upb_msg *default_message; + // The following fields may be modified until finalized. + uint16_t size; + uint8_t hasbit_bytes; + // The range of tag numbers used to store extensions. + uint32_t extension_start; + uint32_t extension_end; } upb_msgdef; // Hash table entries for looking up fields by name or number. typedef struct { bool junk; - uint8_t field_type; - uint8_t native_wire_type; upb_fielddef *f; } upb_itof_ent; typedef struct { @@ -184,23 +174,56 @@ typedef struct { upb_fielddef *f; } upb_ntof_ent; -INLINE void upb_msgdef_unref(upb_msgdef *md) { - upb_def_unref(UPB_UPCAST(md)); +upb_msgdef *upb_msgdef_new(); +INLINE void upb_msgdef_unref(upb_msgdef *md) { upb_def_unref(UPB_UPCAST(md)); } +INLINE void upb_msgdef_ref(upb_msgdef *md) { upb_def_ref(UPB_UPCAST(md)); } + +// Returns a new msgdef that is a copy of the given msgdef (and a copy of all +// the fields) but with any references to submessages broken and replaced with +// just the name of the submessage. This can be put back into another symtab +// and the names will be re-resolved in the new context. +upb_msgdef *upb_msgdef_dup(upb_msgdef *m); + +// Read accessors. May be called at any time. +INLINE uint16_t upb_msgdef_size(upb_msgdef *m) { return m->size; } +INLINE uint8_t upb_msgdef_hasbit_bytes(upb_msgdef *m) { + return m->hasbit_bytes; +} +INLINE uint32_t upb_msgdef_extension_start(upb_msgdef *m) { + return m->extension_start; } -INLINE void upb_msgdef_ref(upb_msgdef *md) { - upb_def_ref(UPB_UPCAST(md)); +INLINE uint32_t upb_msgdef_extension_end(upb_msgdef *m) { + return m->extension_end; } +// Write accessors. May only be called before the msgdef is in a symtab. +void upb_msgdef_setsize(upb_msgdef *m, uint16_t size); +void upb_msgdef_sethasbit_bytes(upb_msgdef *m, uint16_t bytes); +void upb_msgdef_setextension_start(upb_msgdef *m, uint32_t start); +void upb_msgdef_setextension_end(upb_msgdef *m, uint32_t end); + +// Adds a fielddef to a msgdef, and passes a ref on the field to the msgdef. +// May only be done before the msgdef is in a symtab. The fielddef's name and +// number must be set, and the message may not already contain any field with +// this name or number -- if it does, the fielddef is unref'd and false is +// returned. The fielddef may not already belong to another message. +bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f); + +// Sets the layout of all fields according to default rules: +// 1. Hasbits for required fields come first, then optional fields. +// 2. Values are laid out in a way that respects alignment rules. +// 3. The order is chosen to minimize memory usage. +// This should only be called once all fielddefs have been added. +// TODO: will likely want the ability to exclude strings/submessages/arrays. +// TODO: will likely want the ability to define a header size. +void upb_msgdef_layout(upb_msgdef *m); + // 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 // possible. These return NULL if no such field is found. -INLINE upb_itof_ent *upb_msgdef_itofent(upb_msgdef *m, uint32_t num) { - return (upb_itof_ent*)upb_inttable_fastlookup( - &m->itof, num, sizeof(upb_itof_ent)); -} - -INLINE upb_fielddef *upb_msgdef_itof(upb_msgdef *m, uint32_t num) { - upb_itof_ent *e = upb_msgdef_itofent(m, num); +INLINE upb_fielddef *upb_msgdef_itof(upb_msgdef *m, uint32_t i) { + upb_itof_ent *e = (upb_itof_ent*) + upb_inttable_fastlookup(&m->itof, i, sizeof(upb_itof_ent)); return e ? e->f : NULL; } @@ -214,6 +237,7 @@ INLINE int upb_msgdef_numfields(upb_msgdef *m) { } // Iteration over fields. The order is undefined. +// Iterators are invalidated when a field is added or removed. // upb_msg_iter 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); @@ -225,6 +249,7 @@ upb_msg_iter upb_msg_begin(upb_msgdef *m); upb_msg_iter upb_msg_next(upb_msgdef *m, upb_msg_iter iter); INLINE bool upb_msg_done(upb_msg_iter iter) { return upb_inttable_done(iter); } +// Iterator accessor. INLINE upb_fielddef *upb_msg_iter_field(upb_msg_iter iter) { upb_itof_ent *ent = (upb_itof_ent*)upb_inttable_iter_value(iter); return ent->f; @@ -233,13 +258,11 @@ INLINE upb_fielddef *upb_msg_iter_field(upb_msg_iter iter) { /* upb_enumdef ****************************************************************/ -typedef int32_t upb_enumval_t; - typedef struct _upb_enumdef { upb_def base; upb_strtable ntoi; upb_inttable iton; - upb_enumval_t default_value; // The first value listed in the enum. + int32_t defaultval; } upb_enumdef; typedef struct { @@ -252,12 +275,28 @@ typedef struct { upb_string *string; } upb_iton_ent; +upb_enumdef *upb_enumdef_new(); +INLINE void upb_enumdef_ref(upb_enumdef *e) { upb_def_ref(UPB_UPCAST(e)); } +INLINE void upb_enumdef_unref(upb_enumdef *e) { upb_def_unref(UPB_UPCAST(e)); } +upb_enumdef *upb_enumdef_dup(upb_enumdef *e); + +INLINE int32_t upb_enumdef_default(upb_enumdef *e) { return e->defaultval; } + +// May only be set before the enumdef is in a symtab. +void upb_enumdef_setdefault(upb_enumdef *e, int32_t val); + +// Adds a value to the enumdef. Requires that no existing val has this +// name or number (returns false and does not add if there is). May only +// be called before the enumdef is in a symtab. +bool upb_enumdef_addval(upb_enumdef *e, upb_string *name, int32_t num); + // Lookups from name to integer and vice-versa. -bool upb_enumdef_ntoi(upb_enumdef *e, upb_string *name, upb_enumval_t *num); +bool upb_enumdef_ntoi(upb_enumdef *e, upb_string *name, int32_t *num); // Caller does not own a ref on the returned string. -upb_string *upb_enumdef_iton(upb_enumdef *e, upb_enumval_t num); +upb_string *upb_enumdef_iton(upb_enumdef *e, int32_t num); // Iteration over name/value pairs. The order is undefined. +// Adding an enum val invalidates any iterators. // upb_enum_iter i; // for(i = upb_enum_begin(e); !upb_enum_done(i); i = upb_enum_next(e, i)) { // // ... @@ -268,6 +307,7 @@ upb_enum_iter upb_enum_begin(upb_enumdef *e); upb_enum_iter upb_enum_next(upb_enumdef *e, upb_enum_iter iter); INLINE bool upb_enum_done(upb_enum_iter iter) { return upb_inttable_done(iter); } +// Iterator accessors. INLINE upb_string *upb_enum_iter_name(upb_enum_iter iter) { upb_iton_ent *e = (upb_iton_ent*)upb_inttable_iter_value(iter); return e->string; @@ -277,28 +317,74 @@ INLINE int32_t upb_enum_iter_number(upb_enum_iter iter) { } +/* upb_symtabtxn **************************************************************/ + +// A symbol table transaction is a map of defs that can be added to a symtab +// in one single atomic operation that either succeeds or fails. Mutable defs +// can be added to this map (and perhaps removed, in the future). +// +// A symtabtxn is not thread-safe. + +typedef struct { + upb_strtable deftab; +} upb_symtabtxn; + +void upb_symtabtxn_init(upb_symtabtxn *t); +void upb_symtabtxn_uninit(upb_symtabtxn *t); + +// Adds a def to the symtab. Caller passes a ref on the def to the symtabtxn. +// The def's name must be set and there must not be any existing defs in the +// symtabtxn with this name, otherwise false will be returned and no operation +// will be performed (and the ref on the def will be released). +bool upb_symtabtxn_add(upb_symtabtxn *t, upb_def *def); + +// Gets the def (if any) that is associated with this name in the symtab. +// Caller does *not* inherit a ref on the def. +upb_def *upb_symtabtxn_get(upb_symtabtxn *t, upb_string *name); + +// Iterate over the defs that are part of the transaction. +// The order is undefined. +// The iterator is invalidated by upb_symtabtxn_add(). +// upb_symtabtxn_iter i; +// for(i = upb_symtabtxn_begin(t); !upb_symtabtxn_done(t); +// i = upb_symtabtxn_next(t, i)) { +// upb_def *def = upb_symtabtxn_iter_def(i); +// } +typedef void* upb_symtabtxn_iter; + +upb_symtabtxn_iter upb_symtabtxn_begin(upb_symtabtxn *t); +upb_symtabtxn_iter upb_symtabtxn_next(upb_symtabtxn *t, upb_symtabtxn_iter i); +bool upb_symtabtxn_done(upb_symtabtxn_iter i); +upb_def *upb_symtabtxn_iter_def(upb_symtabtxn_iter iter); + + /* upb_symtab *****************************************************************/ // A SymbolTable is where upb_defs live. It is empty when first constructed. -// Clients add definitions to the symtab by supplying descriptors (as defined -// in descriptor.proto) via the upb_stream interface. +// Clients add definitions to the symtab (or replace existing definitions) by +// using a upb_symtab_commit() or calling upb_symtab_add(). + +// upb_deflist: A little dynamic array for storing a growing list of upb_defs. +typedef struct { + upb_def **defs; + uint32_t len; + uint32_t size; +} upb_deflist; + +void upb_deflist_init(upb_deflist *l); +void upb_deflist_uninit(upb_deflist *l); +void upb_deflist_push(upb_deflist *l, upb_def *d); + struct _upb_symtab { upb_atomic_t refcount; upb_rwlock_t lock; // Protects all members except the refcount. upb_strtable symtab; // The symbol table. - upb_msgdef *fds_msgdef; // Msgdef for google.protobuf.FileDescriptorSet. + upb_deflist olddefs; }; -typedef struct _upb_symtab upb_symtab; -// Initializes a upb_symtab. Symtabs are not freed explicitly, but unref'd -// when the caller is done with them. upb_symtab *upb_symtab_new(void); -void _upb_symtab_free(upb_symtab *s); // Must not be called directly! - INLINE void upb_symtab_ref(upb_symtab *s) { upb_atomic_ref(&s->refcount); } -INLINE void upb_symtab_unref(upb_symtab *s) { - if(s && upb_atomic_unref(&s->refcount)) _upb_symtab_free(s); -} +void upb_symtab_unref(upb_symtab *s); // Resolves the given symbol using the rules described in descriptor.proto, // namely: @@ -310,35 +396,36 @@ INLINE void upb_symtab_unref(upb_symtab *s) { // // If a def is found, the caller owns one ref on the returned def. Otherwise // returns NULL. +// TODO: make return const upb_def *upb_symtab_resolve(upb_symtab *s, upb_string *base, upb_string *sym); // Find an entry in the symbol table with this exact name. If a def is found, // the caller owns one ref on the returned def. Otherwise returns NULL. +// TODO: make return const upb_def *upb_symtab_lookup(upb_symtab *s, upb_string *sym); // Gets an array of pointers to all currently active defs in this symtab. The // caller owns the returned array (which is of length *count) as well as a ref // to each symbol inside. If type is UPB_DEF_ANY then defs of all types are // returned, otherwise only defs of the required type are returned. -upb_def **upb_symtab_getdefs(upb_symtab *s, int *count, upb_deftype_t type); +// TODO: make return const +upb_def **upb_symtab_getdefs(upb_symtab *s, int *n, upb_deftype_t type); -// upb_defbuilder: For adding defs to the symtab. -// You allocate the defbuilder, which can handle a single descriptor. -// It will be freed automatically when the parse completes. -struct _upb_defbuilder; -typedef struct _upb_defbuilder upb_defbuilder; -struct _upb_handlers; -struct _upb_handlers; +// Adds a single upb_def into the symtab. A ref on the def is passed to the +// symtab. If any references cannot be resolved, false is returned and the +// symtab is unchanged. The error (if any) is saved to status if non-NULL. +bool upb_symtab_add(upb_symtab *s, upb_def *d, upb_status *status); -// Allocates a new defbuilder that will add defs to the given symtab. -upb_defbuilder *upb_defbuilder_new(upb_symtab *s); +// Adds the set of defs contained in the transaction to the symtab, clearing +// the txn. The entire operation either succeeds or fails. If the operation +// fails, the symtab is unchanged, false is returned, and status indicates +// the error. +bool upb_symtab_commit(upb_symtab *s, upb_symtabtxn *t, upb_status *status); -// Registers handlers that will operate on a defbuilder to add the defs -// to the defbuilder's symtab. Will free itself when the parse finishes. -// -// TODO: should this allow redefinition? Either is possible, but which is -// more useful? Maybe it should be an option. -struct _upb_mhandlers *upb_defbuilder_reghandlers(struct _upb_handlers *h); +// Frees defs that are no longer active in the symtab and are no longer +// reachable. Such defs are not freed when they are replaced in the symtab +// if they are still reachable from defs that are still referenced. +void upb_symtab_gc(upb_symtab *s); /* upb_def casts **************************************************************/ @@ -352,8 +439,7 @@ struct _upb_mhandlers *upb_defbuilder_reghandlers(struct _upb_handlers *h); } UPB_DYNAMIC_CAST_DEF(msgdef, MSG); UPB_DYNAMIC_CAST_DEF(enumdef, ENUM); -UPB_DYNAMIC_CAST_DEF(svcdef, SVC); -UPB_DYNAMIC_CAST_DEF(extdef, EXT); +UPB_DYNAMIC_CAST_DEF(svcdef, SERVICE); UPB_DYNAMIC_CAST_DEF(unresolveddef, UNRESOLVED); #undef UPB_DYNAMIC_CAST_DEF @@ -367,8 +453,7 @@ UPB_DYNAMIC_CAST_DEF(unresolveddef, UNRESOLVED); } UPB_DOWNCAST_DEF(msgdef, MSG); UPB_DOWNCAST_DEF(enumdef, ENUM); -UPB_DOWNCAST_DEF(svcdef, SVC); -UPB_DOWNCAST_DEF(extdef, EXT); +UPB_DOWNCAST_DEF(svcdef, SERVICE); UPB_DOWNCAST_DEF(unresolveddef, UNRESOLVED); #undef UPB_DOWNCAST_DEF -- cgit v1.2.3