Protocol Buffers - Google's data interchange format (grpc依赖) https://developers.google.com/protocol-buffers/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

529 lines
18 KiB

/*
** upb::Sink (upb_sink)
** upb::BytesSink (upb_bytessink)
**
** A upb_sink is an object that binds a upb_handlers object to some runtime
** state. It is the object that can actually receive data via the upb_handlers
** interface.
**
** Unlike upb_def and upb_handlers, upb_sink is never frozen, immutable, or
** thread-safe. You can create as many of them as you want, but each one may
** only be used in a single thread at a time.
**
** If we compare with class-based OOP, a you can think of a upb_def as an
** abstract base class, a upb_handlers as a concrete derived class, and a
** upb_sink as an object (class instance).
*/
#ifndef UPB_SINK_H
#define UPB_SINK_H
#include "upb/handlers.h"
#ifdef __cplusplus
namespace upb {
class BufferSource;
class BytesSink;
class Sink;
}
#endif
UPB_DECLARE_TYPE(upb::BufferSource, upb_bufsrc)
UPB_DECLARE_TYPE(upb::BytesSink, upb_bytessink)
UPB_DECLARE_TYPE(upb::Sink, upb_sink)
#ifdef __cplusplus
/* A upb::Sink is an object that binds a upb::Handlers object to some runtime
* state. It represents an endpoint to which data can be sent.
*
* TODO(haberman): right now all of these functions take selectors. Should they
* take selectorbase instead?
*
* ie. instead of calling:
* sink->StartString(FOO_FIELD_START_STRING, ...)
* a selector base would let you say:
* sink->StartString(FOO_FIELD, ...)
*
* This would make call sites a little nicer and require emitting fewer selector
* definitions in .h files.
*
* But the current scheme has the benefit that you can retrieve a function
* pointer for any handler with handlers->GetHandler(selector), without having
* to have a separate GetHandler() function for each handler type. The JIT
* compiler uses this. To accommodate we'd have to expose a separate
* GetHandler() for every handler type.
*
* Also to ponder: selectors right now are independent of a specific Handlers
* instance. In other words, they allocate a number to every possible handler
* that *could* be registered, without knowing anything about what handlers
* *are* registered. That means that using selectors as table offsets prohibits
* us from compacting the handler table at Freeze() time. If the table is very
* sparse, this could be wasteful.
*
* Having another selector-like thing that is specific to a Handlers instance
* would allow this compacting, but then it would be impossible to write code
* ahead-of-time that can be bound to any Handlers instance at runtime. For
* example, a .proto file parser written as straight C will not know what
* Handlers it will be bound to, so when it calls sink->StartString() what
* selector will it pass? It needs a selector like we have today, that is
* independent of any particular upb::Handlers.
*
* Is there a way then to allow Handlers table compaction? */
class upb::Sink {
public:
/* Constructor with no initialization; must be Reset() before use. */
Sink() {}
/* Constructs a new sink for the given frozen handlers and closure.
*
* TODO: once the Handlers know the expected closure type, verify that T
* matches it. */
template <class T> Sink(const Handlers* handlers, T* closure);
/* Resets the value of the sink. */
template <class T> void Reset(const Handlers* handlers, T* closure);
/* Returns the top-level object that is bound to this sink.
*
* TODO: once the Handlers know the expected closure type, verify that T
* matches it. */
template <class T> T* GetObject() const;
/* Functions for pushing data into the sink.
*
* These return false if processing should stop (either due to error or just
* to suspend).
*
* These may not be called from within one of the same sink's handlers (in
* other words, handlers are not re-entrant). */
/* Should be called at the start and end of every message; both the top-level
* message and submessages. This means that submessages should use the
* following sequence:
* sink->StartSubMessage(startsubmsg_selector);
* sink->StartMessage();
* // ...
* sink->EndMessage(&status);
* sink->EndSubMessage(endsubmsg_selector); */
bool StartMessage();
bool EndMessage(Status* status);
/* Putting of individual values. These work for both repeated and
* non-repeated fields, but for repeated fields you must wrap them in
* calls to StartSequence()/EndSequence(). */
bool PutInt32(Handlers::Selector s, int32_t val);
bool PutInt64(Handlers::Selector s, int64_t val);
bool PutUInt32(Handlers::Selector s, uint32_t val);
bool PutUInt64(Handlers::Selector s, uint64_t val);
bool PutFloat(Handlers::Selector s, float val);
bool PutDouble(Handlers::Selector s, double val);
bool PutBool(Handlers::Selector s, bool val);
/* Putting of string/bytes values. Each string can consist of zero or more
* non-contiguous buffers of data.
*
* For StartString(), the function will write a sink for the string to "sub."
* The sub-sink must be used for any/all PutStringBuffer() calls. */
bool StartString(Handlers::Selector s, size_t size_hint, Sink* sub);
size_t PutStringBuffer(Handlers::Selector s, const char *buf, size_t len,
const BufferHandle *handle);
bool EndString(Handlers::Selector s);
/* For submessage fields.
*
* For StartSubMessage(), the function will write a sink for the string to
* "sub." The sub-sink must be used for any/all handlers called within the
* submessage. */
bool StartSubMessage(Handlers::Selector s, Sink* sub);
bool EndSubMessage(Handlers::Selector s);
/* For repeated fields of any type, the sequence of values must be wrapped in
* these calls.
*
* For StartSequence(), the function will write a sink for the string to
* "sub." The sub-sink must be used for any/all handlers called within the
* sequence. */
bool StartSequence(Handlers::Selector s, Sink* sub);
bool EndSequence(Handlers::Selector s);
/* Copy and assign specifically allowed.
* We don't even bother making these members private because so many
* functions need them and this is mainly just a dumb data container anyway.
*/
#else
struct upb_sink {
#endif
const upb_handlers *handlers;
void *closure;
};
#ifdef __cplusplus
class upb::BytesSink {
public:
BytesSink() {}
/* Constructs a new sink for the given frozen handlers and closure.
*
* TODO(haberman): once the Handlers know the expected closure type, verify
* that T matches it. */
template <class T> BytesSink(const BytesHandler* handler, T* closure);
/* Resets the value of the sink. */
template <class T> void Reset(const BytesHandler* handler, T* closure);
bool Start(size_t size_hint, void **subc);
size_t PutBuffer(void *subc, const char *buf, size_t len,
const BufferHandle *handle);
bool End();
#else
struct upb_bytessink {
#endif
const upb_byteshandler *handler;
void *closure;
};
#ifdef __cplusplus
/* A class for pushing a flat buffer of data to a BytesSink.
* You can construct an instance of this to get a resumable source,
* or just call the static PutBuffer() to do a non-resumable push all in one
* go. */
class upb::BufferSource {
public:
BufferSource();
BufferSource(const char* buf, size_t len, BytesSink* sink);
/* Returns true if the entire buffer was pushed successfully. Otherwise the
* next call to PutNext() will resume where the previous one left off.
* TODO(haberman): implement this. */
bool PutNext();
/* A static version; with this version is it not possible to resume in the
* case of failure or a partially-consumed buffer. */
static bool PutBuffer(const char* buf, size_t len, BytesSink* sink);
template <class T> static bool PutBuffer(const T& str, BytesSink* sink) {
return PutBuffer(str.c_str(), str.size(), sink);
}
#else
struct upb_bufsrc {
char dummy;
#endif
};
UPB_BEGIN_EXTERN_C
/* Inline definitions. */
UPB_INLINE void upb_bytessink_reset(upb_bytessink *s, const upb_byteshandler *h,
void *closure) {
s->handler = h;
s->closure = closure;
}
UPB_INLINE bool upb_bytessink_start(upb_bytessink *s, size_t size_hint,
void **subc) {
typedef upb_startstr_handlerfunc func;
func *start;
*subc = s->closure;
if (!s->handler) return true;
start = (func *)s->handler->table[UPB_STARTSTR_SELECTOR].func;
if (!start) return true;
*subc = start(s->closure, upb_handlerattr_handlerdata(
&s->handler->table[UPB_STARTSTR_SELECTOR].attr),
size_hint);
return *subc != NULL;
}
UPB_INLINE size_t upb_bytessink_putbuf(upb_bytessink *s, void *subc,
const char *buf, size_t size,
const upb_bufhandle* handle) {
typedef upb_string_handlerfunc func;
func *putbuf;
if (!s->handler) return true;
putbuf = (func *)s->handler->table[UPB_STRING_SELECTOR].func;
if (!putbuf) return true;
return putbuf(subc, upb_handlerattr_handlerdata(
&s->handler->table[UPB_STRING_SELECTOR].attr),
buf, size, handle);
}
UPB_INLINE bool upb_bytessink_end(upb_bytessink *s) {
typedef upb_endfield_handlerfunc func;
func *end;
if (!s->handler) return true;
end = (func *)s->handler->table[UPB_ENDSTR_SELECTOR].func;
if (!end) return true;
return end(s->closure,
upb_handlerattr_handlerdata(
&s->handler->table[UPB_ENDSTR_SELECTOR].attr));
}
UPB_INLINE bool upb_bufsrc_putbuf(const char *buf, size_t len,
upb_bytessink *sink) {
void *subc;
bool ret;
upb_bufhandle handle;
upb_bufhandle_init(&handle);
upb_bufhandle_setbuf(&handle, buf, 0);
ret = upb_bytessink_start(sink, len, &subc);
if (ret && len != 0) {
ret = (upb_bytessink_putbuf(sink, subc, buf, len, &handle) >= len);
}
if (ret) {
ret = upb_bytessink_end(sink);
}
upb_bufhandle_uninit(&handle);
return ret;
}
#define PUTVAL(type, ctype) \
UPB_INLINE bool upb_sink_put##type(upb_sink *s, upb_selector_t sel, \
ctype val) { \
typedef upb_##type##_handlerfunc functype; \
functype *func; \
const void *hd; \
if (!s->handlers) return true; \
func = (functype *)upb_handlers_gethandler(s->handlers, sel); \
if (!func) return true; \
hd = upb_handlers_gethandlerdata(s->handlers, sel); \
return func(s->closure, hd, val); \
}
PUTVAL(int32, int32_t)
PUTVAL(int64, int64_t)
PUTVAL(uint32, uint32_t)
PUTVAL(uint64, uint64_t)
PUTVAL(float, float)
PUTVAL(double, double)
PUTVAL(bool, bool)
#undef PUTVAL
UPB_INLINE void upb_sink_reset(upb_sink *s, const upb_handlers *h, void *c) {
s->handlers = h;
s->closure = c;
}
UPB_INLINE size_t upb_sink_putstring(upb_sink *s, upb_selector_t sel,
const char *buf, size_t n,
const upb_bufhandle *handle) {
typedef upb_string_handlerfunc func;
func *handler;
const void *hd;
if (!s->handlers) return n;
handler = (func *)upb_handlers_gethandler(s->handlers, sel);
if (!handler) return n;
hd = upb_handlers_gethandlerdata(s->handlers, sel);
return handler(s->closure, hd, buf, n, handle);
}
UPB_INLINE bool upb_sink_startmsg(upb_sink *s) {
typedef upb_startmsg_handlerfunc func;
func *startmsg;
const void *hd;
if (!s->handlers) return true;
startmsg = (func*)upb_handlers_gethandler(s->handlers, UPB_STARTMSG_SELECTOR);
if (!startmsg) return true;
hd = upb_handlers_gethandlerdata(s->handlers, UPB_STARTMSG_SELECTOR);
return startmsg(s->closure, hd);
}
UPB_INLINE bool upb_sink_endmsg(upb_sink *s, upb_status *status) {
typedef upb_endmsg_handlerfunc func;
func *endmsg;
const void *hd;
if (!s->handlers) return true;
endmsg = (func *)upb_handlers_gethandler(s->handlers, UPB_ENDMSG_SELECTOR);
if (!endmsg) return true;
hd = upb_handlers_gethandlerdata(s->handlers, UPB_ENDMSG_SELECTOR);
return endmsg(s->closure, hd, status);
}
UPB_INLINE bool upb_sink_startseq(upb_sink *s, upb_selector_t sel,
upb_sink *sub) {
typedef upb_startfield_handlerfunc func;
func *startseq;
const void *hd;
sub->closure = s->closure;
sub->handlers = s->handlers;
if (!s->handlers) return true;
startseq = (func*)upb_handlers_gethandler(s->handlers, sel);
if (!startseq) return true;
hd = upb_handlers_gethandlerdata(s->handlers, sel);
sub->closure = startseq(s->closure, hd);
return sub->closure ? true : false;
}
UPB_INLINE bool upb_sink_endseq(upb_sink *s, upb_selector_t sel) {
typedef upb_endfield_handlerfunc func;
func *endseq;
const void *hd;
if (!s->handlers) return true;
endseq = (func*)upb_handlers_gethandler(s->handlers, sel);
if (!endseq) return true;
hd = upb_handlers_gethandlerdata(s->handlers, sel);
return endseq(s->closure, hd);
}
UPB_INLINE bool upb_sink_startstr(upb_sink *s, upb_selector_t sel,
size_t size_hint, upb_sink *sub) {
typedef upb_startstr_handlerfunc func;
func *startstr;
const void *hd;
sub->closure = s->closure;
sub->handlers = s->handlers;
if (!s->handlers) return true;
startstr = (func*)upb_handlers_gethandler(s->handlers, sel);
if (!startstr) return true;
hd = upb_handlers_gethandlerdata(s->handlers, sel);
sub->closure = startstr(s->closure, hd, size_hint);
return sub->closure ? true : false;
}
UPB_INLINE bool upb_sink_endstr(upb_sink *s, upb_selector_t sel) {
typedef upb_endfield_handlerfunc func;
func *endstr;
const void *hd;
if (!s->handlers) return true;
endstr = (func*)upb_handlers_gethandler(s->handlers, sel);
if (!endstr) return true;
hd = upb_handlers_gethandlerdata(s->handlers, sel);
return endstr(s->closure, hd);
}
UPB_INLINE bool upb_sink_startsubmsg(upb_sink *s, upb_selector_t sel,
upb_sink *sub) {
typedef upb_startfield_handlerfunc func;
func *startsubmsg;
const void *hd;
sub->closure = s->closure;
if (!s->handlers) {
sub->handlers = NULL;
return true;
}
sub->handlers = upb_handlers_getsubhandlers_sel(s->handlers, sel);
startsubmsg = (func*)upb_handlers_gethandler(s->handlers, sel);
if (!startsubmsg) return true;
hd = upb_handlers_gethandlerdata(s->handlers, sel);
sub->closure = startsubmsg(s->closure, hd);
return sub->closure ? true : false;
}
UPB_INLINE bool upb_sink_endsubmsg(upb_sink *s, upb_selector_t sel) {
typedef upb_endfield_handlerfunc func;
func *endsubmsg;
const void *hd;
if (!s->handlers) return true;
endsubmsg = (func*)upb_handlers_gethandler(s->handlers, sel);
if (!endsubmsg) return s->closure;
hd = upb_handlers_gethandlerdata(s->handlers, sel);
return endsubmsg(s->closure, hd);
}
UPB_END_EXTERN_C
#ifdef __cplusplus
namespace upb {
template <class T> Sink::Sink(const Handlers* handlers, T* closure) {
upb_sink_reset(this, handlers, closure);
}
template <class T>
inline void Sink::Reset(const Handlers* handlers, T* closure) {
upb_sink_reset(this, handlers, closure);
}
inline bool Sink::StartMessage() {
return upb_sink_startmsg(this);
}
inline bool Sink::EndMessage(Status* status) {
return upb_sink_endmsg(this, status);
}
inline bool Sink::PutInt32(Handlers::Selector sel, int32_t val) {
return upb_sink_putint32(this, sel, val);
}
inline bool Sink::PutInt64(Handlers::Selector sel, int64_t val) {
return upb_sink_putint64(this, sel, val);
}
inline bool Sink::PutUInt32(Handlers::Selector sel, uint32_t val) {
return upb_sink_putuint32(this, sel, val);
}
inline bool Sink::PutUInt64(Handlers::Selector sel, uint64_t val) {
return upb_sink_putuint64(this, sel, val);
}
inline bool Sink::PutFloat(Handlers::Selector sel, float val) {
return upb_sink_putfloat(this, sel, val);
}
inline bool Sink::PutDouble(Handlers::Selector sel, double val) {
return upb_sink_putdouble(this, sel, val);
}
inline bool Sink::PutBool(Handlers::Selector sel, bool val) {
return upb_sink_putbool(this, sel, val);
}
inline bool Sink::StartString(Handlers::Selector sel, size_t size_hint,
Sink *sub) {
return upb_sink_startstr(this, sel, size_hint, sub);
}
inline size_t Sink::PutStringBuffer(Handlers::Selector sel, const char *buf,
size_t len, const BufferHandle* handle) {
return upb_sink_putstring(this, sel, buf, len, handle);
}
inline bool Sink::EndString(Handlers::Selector sel) {
return upb_sink_endstr(this, sel);
}
inline bool Sink::StartSubMessage(Handlers::Selector sel, Sink* sub) {
return upb_sink_startsubmsg(this, sel, sub);
}
inline bool Sink::EndSubMessage(Handlers::Selector sel) {
return upb_sink_endsubmsg(this, sel);
}
inline bool Sink::StartSequence(Handlers::Selector sel, Sink* sub) {
return upb_sink_startseq(this, sel, sub);
}
inline bool Sink::EndSequence(Handlers::Selector sel) {
return upb_sink_endseq(this, sel);
}
template <class T>
BytesSink::BytesSink(const BytesHandler* handler, T* closure) {
Reset(handler, closure);
}
template <class T>
void BytesSink::Reset(const BytesHandler *handler, T *closure) {
upb_bytessink_reset(this, handler, closure);
}
inline bool BytesSink::Start(size_t size_hint, void **subc) {
return upb_bytessink_start(this, size_hint, subc);
}
inline size_t BytesSink::PutBuffer(void *subc, const char *buf, size_t len,
const BufferHandle *handle) {
return upb_bytessink_putbuf(this, subc, buf, len, handle);
}
inline bool BytesSink::End() {
return upb_bytessink_end(this);
}
inline bool BufferSource::PutBuffer(const char *buf, size_t len,
BytesSink *sink) {
return upb_bufsrc_putbuf(buf, len, sink);
}
} /* namespace upb */
#endif
#endif