/* * upb - a minimalist implementation of protocol buffers. * * Copyright (c) 2010-2012 Google Inc. See LICENSE for details. * Author: Josh Haberman * * 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); // Internal-only struct for the sink. struct upb_sinkframe { UPB_PRIVATE_FOR_CPP const upb_handlers *h; void *closure; // For any frames besides the top, this is the END* callback that will run // when the subframe is popped (for example, for a "sequence" frame the frame // above it will be a UPB_HANDLER_ENDSEQ handler). But this is only // necessary for assertion checking inside upb_sink and can be omitted if the // sink has only one caller. // // TODO(haberman): have a mechanism for ensuring that a sink only has one // caller. upb_selector_t selector; }; // The maximum nesting depth that upb::Sink will allow. Matches proto2's limit. // TODO: make this a runtime-settable property of Sink. #define UPB_SINK_MAX_NESTING 64 // 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? UPB_DEFINE_CLASS0(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 Sink(const Handlers* handlers, T* closure); // Resets the value of the sink. template 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 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. , UPB_DEFINE_STRUCT0(upb_sink, const upb_handlers *handlers; void *closure; )); UPB_DEFINE_CLASS0(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 BytesSink(const BytesHandler* handler, T* closure); // Resets the value of the sink. template 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(); , UPB_DEFINE_STRUCT0(upb_bytessink, const upb_byteshandler *handler; void *closure; )); // 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. UPB_DEFINE_CLASS0(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 static bool PutBuffer(const T& str, BytesSink* sink) { return PutBuffer(str.c_str(), str.size(), sink); } , UPB_DEFINE_STRUCT0(upb_bufsrc, )); 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) { *subc = NULL; if (!s->handler) return true; upb_startstr_handlerfunc *start = (upb_startstr_handlerfunc *)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) { if (!s->handler) return true; upb_string_handlerfunc *putbuf = (upb_string_handlerfunc *)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) { if (!s->handler) return true; upb_endfield_handlerfunc *end = (upb_endfield_handlerfunc *)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; upb_bufhandle handle; upb_bufhandle_init(&handle); upb_bufhandle_setbuf(&handle, buf, 0); bool 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) { \ if (!s->handlers) return true; \ upb_##type##_handlerfunc *func = \ (upb_##type##_handlerfunc *)upb_handlers_gethandler(s->handlers, sel); \ if (!func) return true; \ const void *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) { if (!s->handlers) return n; upb_string_handlerfunc *handler = (upb_string_handlerfunc *)upb_handlers_gethandler(s->handlers, sel); if (!handler) return n; const void *hd = upb_handlers_gethandlerdata(s->handlers, sel); return handler(s->closure, hd, buf, n, handle); } UPB_INLINE bool upb_sink_startmsg(upb_sink *s) { if (!s->handlers) return true; upb_startmsg_handlerfunc *startmsg = (upb_startmsg_handlerfunc *)upb_handlers_gethandler(s->handlers, UPB_STARTMSG_SELECTOR); if (!startmsg) return true; const void *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) { if (!s->handlers) return true; upb_endmsg_handlerfunc *endmsg = (upb_endmsg_handlerfunc *)upb_handlers_gethandler(s->handlers, UPB_ENDMSG_SELECTOR); if (!endmsg) return true; const void *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) { sub->closure = s->closure; sub->handlers = s->handlers; if (!s->handlers) return true; upb_startfield_handlerfunc *startseq = (upb_startfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel); if (!startseq) return true; const void *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) { if (!s->handlers) return true; upb_endfield_handlerfunc *endseq = (upb_endfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel); if (!endseq) return true; const void *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) { sub->closure = s->closure; sub->handlers = s->handlers; if (!s->handlers) return true; upb_startstr_handlerfunc *startstr = (upb_startstr_handlerfunc*)upb_handlers_gethandler(s->handlers, sel); if (!startstr) return true; const void *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) { if (!s->handlers) return true; upb_endfield_handlerfunc *endstr = (upb_endfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel); if (!endstr) return true; const void *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) { sub->closure = s->closure; if (!s->handlers) { sub->handlers = NULL; return true; } sub->handlers = upb_handlers_getsubhandlers_sel(s->handlers, sel); upb_startfield_handlerfunc *startsubmsg = (upb_startfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel); if (!startsubmsg) return true; const void *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) { if (!s->handlers) return true; upb_endfield_handlerfunc *endsubmsg = (upb_endfield_handlerfunc*)upb_handlers_gethandler(s->handlers, sel); if (!endsubmsg) return s->closure; const void *hd = upb_handlers_gethandlerdata(s->handlers, sel); return endsubmsg(s->closure, hd); } UPB_END_EXTERN_C // } #ifdef __cplusplus namespace upb { template Sink::Sink(const Handlers* handlers, T* closure) { upb_sink_reset(this, handlers, closure); } template 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 BytesSink::BytesSink(const BytesHandler* handler, T* closure) { Reset(handler, closure); } template 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