|
|
|
/*
|
|
|
|
** upb::Handlers (upb_handlers)
|
|
|
|
**
|
|
|
|
** A upb_handlers is like a virtual table for a upb_msgdef. Each field of the
|
|
|
|
** message can have associated functions that will be called when we are
|
|
|
|
** parsing or visiting a stream of data. This is similar to how handlers work
|
|
|
|
** in SAX (the Simple API for XML).
|
|
|
|
**
|
|
|
|
** The handlers have no idea where the data is coming from, so a single set of
|
|
|
|
** handlers could be used with two completely different data sources (for
|
|
|
|
** example, a parser and a visitor over in-memory objects). This decoupling is
|
|
|
|
** the most important feature of upb, because it allows parsers and serializers
|
|
|
|
** to be highly reusable.
|
|
|
|
**
|
|
|
|
** This is a mixed C/C++ interface that offers a full API to both languages.
|
|
|
|
** See the top-level README for more information.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef UPB_HANDLERS_H
|
|
|
|
#define UPB_HANDLERS_H
|
|
|
|
|
|
|
|
#include "upb/def.h"
|
|
|
|
#include "upb/table.int.h"
|
|
|
|
|
|
|
|
#include "upb/port_def.inc"
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
namespace upb {
|
|
|
|
class HandlersPtr;
|
|
|
|
class HandlerCache;
|
|
|
|
template <class T> class Handler;
|
|
|
|
template <class T> struct CanonicalType;
|
|
|
|
} /* namespace upb */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/* The maximum depth that the handler graph can have. This is a resource limit
|
|
|
|
* for the C stack since we sometimes need to recursively traverse the graph.
|
|
|
|
* Cycles are ok; the traversal will stop when it detects a cycle, but we must
|
|
|
|
* hit the cycle before the maximum depth is reached.
|
|
|
|
*
|
|
|
|
* If having a single static limit is too inflexible, we can add another variant
|
|
|
|
* of Handlers::Freeze that allows specifying this as a parameter. */
|
|
|
|
#define UPB_MAX_HANDLER_DEPTH 64
|
|
|
|
|
|
|
|
/* All the different types of handlers that can be registered.
|
|
|
|
* Only needed for the advanced functions in upb::Handlers. */
|
|
|
|
typedef enum {
|
|
|
|
UPB_HANDLER_INT32,
|
|
|
|
UPB_HANDLER_INT64,
|
|
|
|
UPB_HANDLER_UINT32,
|
|
|
|
UPB_HANDLER_UINT64,
|
|
|
|
UPB_HANDLER_FLOAT,
|
|
|
|
UPB_HANDLER_DOUBLE,
|
|
|
|
UPB_HANDLER_BOOL,
|
|
|
|
UPB_HANDLER_STARTSTR,
|
|
|
|
UPB_HANDLER_STRING,
|
|
|
|
UPB_HANDLER_ENDSTR,
|
|
|
|
UPB_HANDLER_STARTSUBMSG,
|
|
|
|
UPB_HANDLER_ENDSUBMSG,
|
|
|
|
UPB_HANDLER_STARTSEQ,
|
|
|
|
UPB_HANDLER_ENDSEQ
|
|
|
|
} upb_handlertype_t;
|
|
|
|
|
|
|
|
#define UPB_HANDLER_MAX (UPB_HANDLER_ENDSEQ+1)
|
|
|
|
|
|
|
|
#define UPB_BREAK NULL
|
|
|
|
|
|
|
|
/* A convenient definition for when no closure is needed. */
|
|
|
|
extern char _upb_noclosure;
|
|
|
|
#define UPB_NO_CLOSURE &_upb_noclosure
|
|
|
|
|
|
|
|
/* A selector refers to a specific field handler in the Handlers object
|
|
|
|
* (for example: the STARTSUBMSG handler for field "field15"). */
|
|
|
|
typedef int32_t upb_selector_t;
|
|
|
|
|
|
|
|
/* Static selectors for upb::Handlers. */
|
|
|
|
#define UPB_STARTMSG_SELECTOR 0
|
|
|
|
#define UPB_ENDMSG_SELECTOR 1
|
|
|
|
#define UPB_UNKNOWN_SELECTOR 2
|
|
|
|
#define UPB_STATIC_SELECTOR_COUNT 3 /* Warning: also in upb/def.c. */
|
|
|
|
|
|
|
|
/* Static selectors for upb::BytesHandler. */
|
|
|
|
#define UPB_STARTSTR_SELECTOR 0
|
|
|
|
#define UPB_STRING_SELECTOR 1
|
|
|
|
#define UPB_ENDSTR_SELECTOR 2
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
template<class T> const void *UniquePtrForType() {
|
|
|
|
static const char ch = 0;
|
|
|
|
return &ch;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* upb_handlers ************************************************************/
|
|
|
|
|
|
|
|
/* Handler attributes, to be registered with the handler itself. */
|
|
|
|
typedef struct {
|
|
|
|
const void *handler_data;
|
|
|
|
const void *closure_type;
|
|
|
|
const void *return_closure_type;
|
|
|
|
bool alwaysok;
|
|
|
|
} upb_handlerattr;
|
|
|
|
|
|
|
|
#define UPB_HANDLERATTR_INIT {NULL, NULL, NULL, false}
|
|
|
|
|
|
|
|
/* Bufhandle, data passed along with a buffer to indicate its provenance. */
|
|
|
|
typedef struct {
|
|
|
|
/* The beginning of the buffer. This may be different than the pointer
|
|
|
|
* passed to a StringBuf handler because the handler may receive data
|
|
|
|
* that is from the middle or end of a larger buffer. */
|
|
|
|
const char *buf;
|
|
|
|
|
|
|
|
/* The offset within the attached object where this buffer begins. Only
|
|
|
|
* meaningful if there is an attached object. */
|
|
|
|
size_t objofs;
|
|
|
|
|
|
|
|
/* The attached object (if any) and a pointer representing its type. */
|
|
|
|
const void *obj;
|
|
|
|
const void *objtype;
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
template <class T>
|
|
|
|
void SetAttachedObject(const T* _obj) {
|
|
|
|
obj = _obj;
|
|
|
|
objtype = UniquePtrForType<T>();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
const T *GetAttachedObject() const {
|
|
|
|
return objtype == UniquePtrForType<T>() ? static_cast<const T *>(obj)
|
|
|
|
: NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
} upb_bufhandle;
|
|
|
|
|
|
|
|
#define UPB_BUFHANDLE_INIT {NULL, 0, NULL, NULL}
|
|
|
|
|
|
|
|
/* Handler function typedefs. */
|
|
|
|
typedef void upb_handlerfree(void *d);
|
|
|
|
typedef bool upb_unknown_handlerfunc(void *c, const void *hd, const char *buf,
|
|
|
|
size_t n);
|
|
|
|
typedef bool upb_startmsg_handlerfunc(void *c, const void*);
|
|
|
|
typedef bool upb_endmsg_handlerfunc(void *c, const void *, upb_status *status);
|
|
|
|
typedef void* upb_startfield_handlerfunc(void *c, const void *hd);
|
|
|
|
typedef bool upb_endfield_handlerfunc(void *c, const void *hd);
|
|
|
|
typedef bool upb_int32_handlerfunc(void *c, const void *hd, int32_t val);
|
|
|
|
typedef bool upb_int64_handlerfunc(void *c, const void *hd, int64_t val);
|
|
|
|
typedef bool upb_uint32_handlerfunc(void *c, const void *hd, uint32_t val);
|
|
|
|
typedef bool upb_uint64_handlerfunc(void *c, const void *hd, uint64_t val);
|
|
|
|
typedef bool upb_float_handlerfunc(void *c, const void *hd, float val);
|
|
|
|
typedef bool upb_double_handlerfunc(void *c, const void *hd, double val);
|
|
|
|
typedef bool upb_bool_handlerfunc(void *c, const void *hd, bool val);
|
|
|
|
typedef void *upb_startstr_handlerfunc(void *c, const void *hd,
|
|
|
|
size_t size_hint);
|
|
|
|
typedef size_t upb_string_handlerfunc(void *c, const void *hd, const char *buf,
|
|
|
|
size_t n, const upb_bufhandle* handle);
|
|
|
|
|
|
|
|
struct upb_handlers;
|
|
|
|
typedef struct upb_handlers upb_handlers;
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Mutating accessors. */
|
|
|
|
const upb_status *upb_handlers_status(upb_handlers *h);
|
|
|
|
void upb_handlers_clearerr(upb_handlers *h);
|
|
|
|
const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h);
|
|
|
|
bool upb_handlers_addcleanup(upb_handlers *h, void *p, upb_handlerfree *hfree);
|
|
|
|
bool upb_handlers_setunknown(upb_handlers *h, upb_unknown_handlerfunc *func,
|
|
|
|
const upb_handlerattr *attr);
|
|
|
|
bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func,
|
|
|
|
const upb_handlerattr *attr);
|
|
|
|
bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func,
|
|
|
|
const upb_handlerattr *attr);
|
|
|
|
bool upb_handlers_setint32(upb_handlers *h, const upb_fielddef *f,
|
|
|
|
upb_int32_handlerfunc *func,
|
|
|
|
const upb_handlerattr *attr);
|
|
|
|
bool upb_handlers_setint64(upb_handlers *h, const upb_fielddef *f,
|
|
|
|
upb_int64_handlerfunc *func,
|
|
|
|
const upb_handlerattr *attr);
|
|
|
|
bool upb_handlers_setuint32(upb_handlers *h, const upb_fielddef *f,
|
|
|
|
upb_uint32_handlerfunc *func,
|
|
|
|
const upb_handlerattr *attr);
|
|
|
|
bool upb_handlers_setuint64(upb_handlers *h, const upb_fielddef *f,
|
|
|
|
upb_uint64_handlerfunc *func,
|
|
|
|
const upb_handlerattr *attr);
|
|
|
|
bool upb_handlers_setfloat(upb_handlers *h, const upb_fielddef *f,
|
|
|
|
upb_float_handlerfunc *func,
|
|
|
|
const upb_handlerattr *attr);
|
|
|
|
bool upb_handlers_setdouble(upb_handlers *h, const upb_fielddef *f,
|
|
|
|
upb_double_handlerfunc *func,
|
|
|
|
const upb_handlerattr *attr);
|
|
|
|
bool upb_handlers_setbool(upb_handlers *h, const upb_fielddef *f,
|
|
|
|
upb_bool_handlerfunc *func,
|
|
|
|
const upb_handlerattr *attr);
|
|
|
|
bool upb_handlers_setstartstr(upb_handlers *h, const upb_fielddef *f,
|
|
|
|
upb_startstr_handlerfunc *func,
|
|
|
|
const upb_handlerattr *attr);
|
|
|
|
bool upb_handlers_setstring(upb_handlers *h, const upb_fielddef *f,
|
|
|
|
upb_string_handlerfunc *func,
|
|
|
|
const upb_handlerattr *attr);
|
|
|
|
bool upb_handlers_setendstr(upb_handlers *h, const upb_fielddef *f,
|
|
|
|
upb_endfield_handlerfunc *func,
|
|
|
|
const upb_handlerattr *attr);
|
|
|
|
bool upb_handlers_setstartseq(upb_handlers *h, const upb_fielddef *f,
|
|
|
|
upb_startfield_handlerfunc *func,
|
|
|
|
const upb_handlerattr *attr);
|
|
|
|
bool upb_handlers_setstartsubmsg(upb_handlers *h, const upb_fielddef *f,
|
|
|
|
upb_startfield_handlerfunc *func,
|
|
|
|
const upb_handlerattr *attr);
|
|
|
|
bool upb_handlers_setendsubmsg(upb_handlers *h, const upb_fielddef *f,
|
|
|
|
upb_endfield_handlerfunc *func,
|
|
|
|
const upb_handlerattr *attr);
|
|
|
|
bool upb_handlers_setendseq(upb_handlers *h, const upb_fielddef *f,
|
|
|
|
upb_endfield_handlerfunc *func,
|
|
|
|
const upb_handlerattr *attr);
|
|
|
|
|
|
|
|
/* Read-only accessors. */
|
|
|
|
const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h,
|
|
|
|
const upb_fielddef *f);
|
|
|
|
const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h,
|
|
|
|
upb_selector_t sel);
|
|
|
|
upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s,
|
|
|
|
const void **handler_data);
|
|
|
|
bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t s,
|
|
|
|
upb_handlerattr *attr);
|
|
|
|
|
|
|
|
/* "Static" methods */
|
|
|
|
upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f);
|
|
|
|
bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type,
|
|
|
|
upb_selector_t *s);
|
|
|
|
UPB_INLINE upb_selector_t upb_handlers_getendselector(upb_selector_t start) {
|
|
|
|
return start + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
} /* extern "C" */
|
|
|
|
|
|
|
|
namespace upb {
|
|
|
|
typedef upb_handlers Handlers;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Convenience macros for creating a Handler object that is wrapped with a
|
|
|
|
* type-safe wrapper function that converts the "void*" parameters/returns
|
|
|
|
* of the underlying C API into nice C++ function.
|
|
|
|
*
|
|
|
|
* Sample usage:
|
|
|
|
* void OnValue1(MyClosure* c, const MyHandlerData* d, int32_t val) {
|
|
|
|
* // do stuff ...
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* // Handler that doesn't need any data bound to it.
|
|
|
|
* void OnValue2(MyClosure* c, int32_t val) {
|
|
|
|
* // do stuff ...
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* // Handler that returns bool so it can return failure if necessary.
|
|
|
|
* bool OnValue3(MyClosure* c, int32_t val) {
|
|
|
|
* // do stuff ...
|
|
|
|
* return ok;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* // Member function handler.
|
|
|
|
* class MyClosure {
|
|
|
|
* public:
|
|
|
|
* void OnValue(int32_t val) {
|
|
|
|
* // do stuff ...
|
|
|
|
* }
|
|
|
|
* };
|
|
|
|
*
|
|
|
|
* // Takes ownership of the MyHandlerData.
|
|
|
|
* handlers->SetInt32Handler(f1, UpbBind(OnValue1, new MyHandlerData(...)));
|
|
|
|
* handlers->SetInt32Handler(f2, UpbMakeHandler(OnValue2));
|
|
|
|
* handlers->SetInt32Handler(f1, UpbMakeHandler(OnValue3));
|
|
|
|
* handlers->SetInt32Handler(f2, UpbMakeHandler(&MyClosure::OnValue));
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* In C++11, the "template" disambiguator can appear even outside templates,
|
|
|
|
* so all calls can safely use this pair of macros. */
|
|
|
|
|
|
|
|
#define UpbMakeHandler(f) upb::MatchFunc(f).template GetFunc<f>()
|
|
|
|
|
|
|
|
/* We have to be careful to only evaluate "d" once. */
|
|
|
|
#define UpbBind(f, d) upb::MatchFunc(f).template GetFunc<f>((d))
|
|
|
|
|
|
|
|
/* Handler: a struct that contains the (handler, data, deleter) tuple that is
|
|
|
|
* used to register all handlers. Users can Make() these directly but it's
|
|
|
|
* more convenient to use the UpbMakeHandler/UpbBind macros above. */
|
|
|
|
template <class T> class upb::Handler {
|
|
|
|
public:
|
|
|
|
/* The underlying, handler function signature that upb uses internally. */
|
|
|
|
typedef T FuncPtr;
|
|
|
|
|
|
|
|
/* Intentionally implicit. */
|
|
|
|
template <class F> Handler(F func);
|
|
|
|
~Handler() { UPB_ASSERT(registered_); }
|
|
|
|
|
|
|
|
void AddCleanup(upb_handlers* h) const;
|
|
|
|
FuncPtr handler() const { return handler_; }
|
|
|
|
const upb_handlerattr& attr() const { return attr_; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
Handler(const Handler&) = delete;
|
|
|
|
Handler& operator=(const Handler&) = delete;
|
|
|
|
|
|
|
|
FuncPtr handler_;
|
|
|
|
mutable upb_handlerattr attr_;
|
|
|
|
mutable bool registered_;
|
|
|
|
void *cleanup_data_;
|
|
|
|
upb_handlerfree *cleanup_func_;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* A upb::Handlers object represents the set of handlers associated with a
|
|
|
|
* message in the graph of messages. You can think of it as a big virtual
|
|
|
|
* table with functions corresponding to all the events that can fire while
|
|
|
|
* parsing or visiting a message of a specific type.
|
|
|
|
*
|
|
|
|
* Any handlers that are not set behave as if they had successfully consumed
|
|
|
|
* the value. Any unset Start* handlers will propagate their closure to the
|
|
|
|
* inner frame.
|
|
|
|
*
|
|
|
|
* The easiest way to create the *Handler objects needed by the Set* methods is
|
|
|
|
* with the UpbBind() and UpbMakeHandler() macros; see below. */
|
|
|
|
class upb::HandlersPtr {
|
|
|
|
public:
|
|
|
|
HandlersPtr(upb_handlers* ptr) : ptr_(ptr) {}
|
|
|
|
|
|
|
|
upb_handlers* ptr() const { return ptr_; }
|
|
|
|
|
|
|
|
typedef upb_selector_t Selector;
|
|
|
|
typedef upb_handlertype_t Type;
|
|
|
|
|
|
|
|
typedef Handler<void *(*)(void *, const void *)> StartFieldHandler;
|
|
|
|
typedef Handler<bool (*)(void *, const void *)> EndFieldHandler;
|
|
|
|
typedef Handler<bool (*)(void *, const void *)> StartMessageHandler;
|
|
|
|
typedef Handler<bool (*)(void *, const void *, upb_status *)>
|
|
|
|
EndMessageHandler;
|
|
|
|
typedef Handler<void *(*)(void *, const void *, size_t)> StartStringHandler;
|
|
|
|
typedef Handler<size_t (*)(void *, const void *, const char *, size_t,
|
|
|
|
const upb_bufhandle *)>
|
|
|
|
StringHandler;
|
|
|
|
|
|
|
|
template <class T> struct ValueHandler {
|
|
|
|
typedef Handler<bool(*)(void *, const void *, T)> H;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef ValueHandler<int32_t>::H Int32Handler;
|
|
|
|
typedef ValueHandler<int64_t>::H Int64Handler;
|
|
|
|
typedef ValueHandler<uint32_t>::H UInt32Handler;
|
|
|
|
typedef ValueHandler<uint64_t>::H UInt64Handler;
|
|
|
|
typedef ValueHandler<float>::H FloatHandler;
|
|
|
|
typedef ValueHandler<double>::H DoubleHandler;
|
|
|
|
typedef ValueHandler<bool>::H BoolHandler;
|
|
|
|
|
|
|
|
/* Any function pointer can be converted to this and converted back to its
|
|
|
|
* correct type. */
|
|
|
|
typedef void GenericFunction();
|
|
|
|
|
|
|
|
typedef void HandlersCallback(const void *closure, upb_handlers *h);
|
|
|
|
|
|
|
|
/* Returns the msgdef associated with this handlers object. */
|
|
|
|
MessageDefPtr message_def() const {
|
|
|
|
return MessageDefPtr(upb_handlers_msgdef(ptr()));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Adds the given pointer and function to the list of cleanup functions that
|
|
|
|
* will be run when these handlers are freed. If this pointer has previously
|
|
|
|
* been registered, the function returns false and does nothing. */
|
|
|
|
bool AddCleanup(void *ptr, upb_handlerfree *cleanup) {
|
|
|
|
return upb_handlers_addcleanup(ptr_, ptr, cleanup);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sets the startmsg handler for the message, which is defined as follows:
|
|
|
|
*
|
|
|
|
* bool startmsg(MyType* closure) {
|
|
|
|
* // Called when the message begins. Returns true if processing should
|
|
|
|
* // continue.
|
|
|
|
* return true;
|
|
|
|
* }
|
|
|
|
*/
|
|
|
|
bool SetStartMessageHandler(const StartMessageHandler &h) {
|
|
|
|
h.AddCleanup(ptr());
|
|
|
|
return upb_handlers_setstartmsg(ptr(), h.handler(), &h.attr());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sets the endmsg handler for the message, which is defined as follows:
|
|
|
|
*
|
|
|
|
* bool endmsg(MyType* closure, upb_status *status) {
|
|
|
|
* // Called when processing of this message ends, whether in success or
|
|
|
|
* // failure. "status" indicates the final status of processing, and
|
|
|
|
* // can also be modified in-place to update the final status.
|
|
|
|
* }
|
|
|
|
*/
|
|
|
|
bool SetEndMessageHandler(const EndMessageHandler& h) {
|
|
|
|
h.AddCleanup(ptr());
|
|
|
|
return upb_handlers_setendmsg(ptr(), h.handler(), &h.attr());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sets the value handler for the given field, which is defined as follows
|
|
|
|
* (this is for an int32 field; other field types will pass their native
|
|
|
|
* C/C++ type for "val"):
|
|
|
|
*
|
|
|
|
* bool OnValue(MyClosure* c, const MyHandlerData* d, int32_t val) {
|
|
|
|
* // Called when the field's value is encountered. "d" contains
|
|
|
|
* // whatever data was bound to this field when it was registered.
|
|
|
|
* // Returns true if processing should continue.
|
|
|
|
* return true;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* handers->SetInt32Handler(f, UpbBind(OnValue, new MyHandlerData(...)));
|
|
|
|
*
|
|
|
|
* The value type must exactly match f->type().
|
|
|
|
* For example, a handler that takes an int32_t parameter may only be used for
|
|
|
|
* fields of type UPB_TYPE_INT32 and UPB_TYPE_ENUM.
|
|
|
|
*
|
|
|
|
* Returns false if the handler failed to register; in this case the cleanup
|
|
|
|
* handler (if any) will be called immediately.
|
|
|
|
*/
|
|
|
|
bool SetInt32Handler(FieldDefPtr f, const Int32Handler &h) {
|
|
|
|
h.AddCleanup(ptr());
|
|
|
|
return upb_handlers_setint32(ptr(), f.ptr(), h.handler(), &h.attr());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SetInt64Handler (FieldDefPtr f, const Int64Handler& h) {
|
|
|
|
h.AddCleanup(ptr());
|
|
|
|
return upb_handlers_setint64(ptr(), f.ptr(), h.handler(), &h.attr());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SetUInt32Handler(FieldDefPtr f, const UInt32Handler& h) {
|
|
|
|
h.AddCleanup(ptr());
|
|
|
|
return upb_handlers_setuint32(ptr(), f.ptr(), h.handler(), &h.attr());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SetUInt64Handler(FieldDefPtr f, const UInt64Handler& h) {
|
|
|
|
h.AddCleanup(ptr());
|
|
|
|
return upb_handlers_setuint64(ptr(), f.ptr(), h.handler(), &h.attr());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SetFloatHandler (FieldDefPtr f, const FloatHandler& h) {
|
|
|
|
h.AddCleanup(ptr());
|
|
|
|
return upb_handlers_setfloat(ptr(), f.ptr(), h.handler(), &h.attr());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SetDoubleHandler(FieldDefPtr f, const DoubleHandler& h) {
|
|
|
|
h.AddCleanup(ptr());
|
|
|
|
return upb_handlers_setdouble(ptr(), f.ptr(), h.handler(), &h.attr());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SetBoolHandler(FieldDefPtr f, const BoolHandler &h) {
|
|
|
|
h.AddCleanup(ptr());
|
|
|
|
return upb_handlers_setbool(ptr(), f.ptr(), h.handler(), &h.attr());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Like the previous, but templated on the type on the value (ie. int32).
|
|
|
|
* This is mostly useful to call from other templates. To call this you must
|
|
|
|
* specify the template parameter explicitly, ie:
|
|
|
|
* h->SetValueHandler<T>(f, UpbBind(MyHandler<T>, MyData)); */
|
|
|
|
template <class T>
|
|
|
|
bool SetValueHandler(
|
|
|
|
FieldDefPtr f,
|
|
|
|
const typename ValueHandler<typename CanonicalType<T>::Type>::H &handler);
|
|
|
|
|
|
|
|
/* Sets handlers for a string field, which are defined as follows:
|
|
|
|
*
|
|
|
|
* MySubClosure* startstr(MyClosure* c, const MyHandlerData* d,
|
|
|
|
* size_t size_hint) {
|
|
|
|
* // Called when a string value begins. The return value indicates the
|
|
|
|
* // closure for the string. "size_hint" indicates the size of the
|
|
|
|
* // string if it is known, however if the string is length-delimited
|
|
|
|
* // and the end-of-string is not available size_hint will be zero.
|
|
|
|
* // This case is indistinguishable from the case where the size is
|
|
|
|
* // known to be zero.
|
|
|
|
* //
|
|
|
|
* // TODO(haberman): is it important to distinguish these cases?
|
|
|
|
* // If we had ssize_t as a type we could make -1 "unknown", but
|
|
|
|
* // ssize_t is POSIX (not ANSI) and therefore less portable.
|
|
|
|
* // In practice I suspect it won't be important to distinguish.
|
|
|
|
* return closure;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* size_t str(MyClosure* closure, const MyHandlerData* d,
|
|
|
|
* const char *str, size_t len) {
|
|
|
|
* // Called for each buffer of string data; the multiple physical buffers
|
|
|
|
* // are all part of the same logical string. The return value indicates
|
|
|
|
* // how many bytes were consumed. If this number is less than "len",
|
|
|
|
* // this will also indicate that processing should be halted for now,
|
|
|
|
* // like returning false or UPB_BREAK from any other callback. If
|
|
|
|
* // number is greater than "len", the excess bytes will be skipped over
|
|
|
|
* // and not passed to the callback.
|
|
|
|
* return len;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* bool endstr(MyClosure* c, const MyHandlerData* d) {
|
|
|
|
* // Called when a string value ends. Return value indicates whether
|
|
|
|
* // processing should continue.
|
|
|
|
* return true;
|
|
|
|
* }
|
|
|
|
*/
|
|
|
|
bool SetStartStringHandler(FieldDefPtr f, const StartStringHandler &h) {
|
|
|
|
h.AddCleanup(ptr());
|
|
|
|
return upb_handlers_setstartstr(ptr(), f.ptr(), h.handler(), &h.attr());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SetStringHandler(FieldDefPtr f, const StringHandler& h) {
|
|
|
|
h.AddCleanup(ptr());
|
|
|
|
return upb_handlers_setstring(ptr(), f.ptr(), h.handler(), &h.attr());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SetEndStringHandler(FieldDefPtr f, const EndFieldHandler& h) {
|
|
|
|
h.AddCleanup(ptr());
|
|
|
|
return upb_handlers_setendstr(ptr(), f.ptr(), h.handler(), &h.attr());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sets the startseq handler, which is defined as follows:
|
|
|
|
*
|
|
|
|
* MySubClosure *startseq(MyClosure* c, const MyHandlerData* d) {
|
|
|
|
* // Called when a sequence (repeated field) begins. The returned
|
|
|
|
* // pointer indicates the closure for the sequence (or UPB_BREAK
|
|
|
|
* // to interrupt processing).
|
|
|
|
* return closure;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* h->SetStartSequenceHandler(f, UpbBind(startseq, new MyHandlerData(...)));
|
|
|
|
*
|
|
|
|
* Returns "false" if "f" does not belong to this message or is not a
|
|
|
|
* repeated field.
|
|
|
|
*/
|
|
|
|
bool SetStartSequenceHandler(FieldDefPtr f, const StartFieldHandler &h) {
|
|
|
|
h.AddCleanup(ptr());
|
|
|
|
return upb_handlers_setstartseq(ptr(), f.ptr(), h.handler(), &h.attr());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sets the startsubmsg handler for the given field, which is defined as
|
|
|
|
* follows:
|
|
|
|
*
|
|
|
|
* MySubClosure* startsubmsg(MyClosure* c, const MyHandlerData* d) {
|
|
|
|
* // Called when a submessage begins. The returned pointer indicates the
|
|
|
|
* // closure for the sequence (or UPB_BREAK to interrupt processing).
|
|
|
|
* return closure;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* h->SetStartSubMessageHandler(f, UpbBind(startsubmsg,
|
|
|
|
* new MyHandlerData(...)));
|
|
|
|
*
|
|
|
|
* Returns "false" if "f" does not belong to this message or is not a
|
|
|
|
* submessage/group field.
|
|
|
|
*/
|
|
|
|
bool SetStartSubMessageHandler(FieldDefPtr f, const StartFieldHandler& h) {
|
|
|
|
h.AddCleanup(ptr());
|
|
|
|
return upb_handlers_setstartsubmsg(ptr(), f.ptr(), h.handler(), &h.attr());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sets the endsubmsg handler for the given field, which is defined as
|
|
|
|
* follows:
|
|
|
|
*
|
|
|
|
* bool endsubmsg(MyClosure* c, const MyHandlerData* d) {
|
|
|
|
* // Called when a submessage ends. Returns true to continue processing.
|
|
|
|
* return true;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* Returns "false" if "f" does not belong to this message or is not a
|
|
|
|
* submessage/group field.
|
|
|
|
*/
|
|
|
|
bool SetEndSubMessageHandler(FieldDefPtr f, const EndFieldHandler &h) {
|
|
|
|
h.AddCleanup(ptr());
|
|
|
|
return upb_handlers_setendsubmsg(ptr(), f.ptr(), h.handler(), &h.attr());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Starts the endsubseq handler for the given field, which is defined as
|
|
|
|
* follows:
|
|
|
|
*
|
|
|
|
* bool endseq(MyClosure* c, const MyHandlerData* d) {
|
|
|
|
* // Called when a sequence ends. Returns true continue processing.
|
|
|
|
* return true;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* Returns "false" if "f" does not belong to this message or is not a
|
|
|
|
* repeated field.
|
|
|
|
*/
|
|
|
|
bool SetEndSequenceHandler(FieldDefPtr f, const EndFieldHandler &h) {
|
|
|
|
h.AddCleanup(ptr());
|
|
|
|
return upb_handlers_setendseq(ptr(), f.ptr(), h.handler(), &h.attr());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
upb_handlers* ptr_;
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* __cplusplus */
|
|
|
|
|
|
|
|
/* upb_handlercache ***********************************************************/
|
|
|
|
|
|
|
|
/* A upb_handlercache lazily builds and caches upb_handlers. You pass it a
|
|
|
|
* function (with optional closure) that can build handlers for a given
|
|
|
|
* message on-demand, and the cache maintains a map of msgdef->handlers. */
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
|
|
|
struct upb_handlercache;
|
|
|
|
typedef struct upb_handlercache upb_handlercache;
|
|
|
|
|
|
|
|
typedef void upb_handlers_callback(const void *closure, upb_handlers *h);
|
|
|
|
|
|
|
|
upb_handlercache *upb_handlercache_new(upb_handlers_callback *callback,
|
|
|
|
const void *closure);
|
|
|
|
void upb_handlercache_free(upb_handlercache *cache);
|
|
|
|
const upb_handlers *upb_handlercache_get(upb_handlercache *cache,
|
|
|
|
const upb_msgdef *md);
|
|
|
|
bool upb_handlercache_addcleanup(upb_handlercache *h, void *p,
|
|
|
|
upb_handlerfree *hfree);
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
} /* extern "C" */
|
|
|
|
|
|
|
|
class upb::HandlerCache {
|
|
|
|
public:
|
|
|
|
HandlerCache(upb_handlers_callback *callback, const void *closure)
|
|
|
|
: ptr_(upb_handlercache_new(callback, closure), upb_handlercache_free) {}
|
|
|
|
HandlerCache(HandlerCache&&) = default;
|
|
|
|
HandlerCache& operator=(HandlerCache&&) = default;
|
|
|
|
HandlerCache(upb_handlercache* c) : ptr_(c, upb_handlercache_free) {}
|
|
|
|
|
|
|
|
upb_handlercache* ptr() { return ptr_.get(); }
|
|
|
|
|
|
|
|
const upb_handlers *Get(MessageDefPtr md) {
|
|
|
|
return upb_handlercache_get(ptr_.get(), md.ptr());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::unique_ptr<upb_handlercache, decltype(&upb_handlercache_free)> ptr_;
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* __cplusplus */
|
|
|
|
|
|
|
|
/* upb_byteshandler ***********************************************************/
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
upb_func *func;
|
|
|
|
|
|
|
|
/* It is wasteful to include the entire attributes here:
|
|
|
|
*
|
|
|
|
* * Some of the information is redundant (like storing the closure type
|
|
|
|
* separately for each handler that must match).
|
|
|
|
* * Some of the info is only needed prior to freeze() (like closure types).
|
|
|
|
* * alignment padding wastes a lot of space for alwaysok_.
|
|
|
|
*
|
|
|
|
* If/when the size and locality of handlers is an issue, we can optimize this
|
|
|
|
* not to store the entire attr like this. We do not expose the table's
|
|
|
|
* layout to allow this optimization in the future. */
|
|
|
|
upb_handlerattr attr;
|
|
|
|
} upb_handlers_tabent;
|
|
|
|
|
|
|
|
#define UPB_TABENT_INIT {NULL, UPB_HANDLERATTR_INIT}
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
upb_handlers_tabent table[3];
|
|
|
|
} upb_byteshandler;
|
|
|
|
|
|
|
|
#define UPB_BYTESHANDLER_INIT \
|
|
|
|
{ \
|
|
|
|
{ UPB_TABENT_INIT, UPB_TABENT_INIT, UPB_TABENT_INIT } \
|
|
|
|
}
|
|
|
|
|
|
|
|
UPB_INLINE void upb_byteshandler_init(upb_byteshandler *handler) {
|
|
|
|
upb_byteshandler init = UPB_BYTESHANDLER_INIT;
|
|
|
|
*handler = init;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Caller must ensure that "d" outlives the handlers. */
|
|
|
|
bool upb_byteshandler_setstartstr(upb_byteshandler *h,
|
|
|
|
upb_startstr_handlerfunc *func, void *d);
|
|
|
|
bool upb_byteshandler_setstring(upb_byteshandler *h,
|
|
|
|
upb_string_handlerfunc *func, void *d);
|
|
|
|
bool upb_byteshandler_setendstr(upb_byteshandler *h,
|
|
|
|
upb_endfield_handlerfunc *func, void *d);
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
} /* extern "C" */
|
|
|
|
|
|
|
|
namespace upb {
|
|
|
|
typedef upb_byteshandler BytesHandler;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/** Message handlers ******************************************************************/
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* These are the handlers used internally by upb_msgfactory_getmergehandlers().
|
|
|
|
* They write scalar data to a known offset from the message pointer.
|
|
|
|
*
|
|
|
|
* These would be trivial for anyone to implement themselves, but it's better
|
|
|
|
* to use these because some JITs will recognize and specialize these instead
|
|
|
|
* of actually calling the function. */
|
|
|
|
|
|
|
|
/* Sets a handler for the given primitive field that will write the data at the
|
|
|
|
* given offset. If hasbit > 0, also sets a hasbit at the given bit offset
|
|
|
|
* (addressing each byte low to high). */
|
|
|
|
bool upb_msg_setscalarhandler(upb_handlers *h,
|
|
|
|
const upb_fielddef *f,
|
|
|
|
size_t offset,
|
|
|
|
int32_t hasbit);
|
|
|
|
|
|
|
|
/* If the given handler is a msghandlers_primitive field, returns true and sets
|
|
|
|
* *type, *offset and *hasbit. Otherwise returns false. */
|
|
|
|
bool upb_msg_getscalarhandlerdata(const upb_handlers *h,
|
|
|
|
upb_selector_t s,
|
|
|
|
upb_fieldtype_t *type,
|
|
|
|
size_t *offset,
|
|
|
|
int32_t *hasbit);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
} /* extern "C" */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "upb/handlers-inl.h"
|
|
|
|
|
|
|
|
#include "upb/port_undef.inc"
|
|
|
|
|
|
|
|
#endif /* UPB_HANDLERS_H */
|