blob: 8c4d8bf5d5c2312df223a1f6710a8a0be3a88614 [file] [log] [blame]
/*
** upb::pb::Decoder
**
** A high performance, streaming, resumable decoder for the binary protobuf
** format.
**
** This interface works the same regardless of what decoder backend is being
** used. A client of this class does not need to know whether decoding is using
** a JITted decoder (DynASM, LLVM, etc) or an interpreted decoder. By default,
** it will always use the fastest available decoder. However, you can call
** set_allow_jit(false) to disable any JIT decoder that might be available.
** This is primarily useful for testing purposes.
*/
#ifndef UPB_DECODER_H_
#define UPB_DECODER_H_
#include "upb/sink.h"
#ifdef __cplusplus
namespace upb {
namespace pb {
class CodeCache;
class DecoderPtr;
class DecoderMethodPtr;
class DecoderMethodOptions;
} /* namespace pb */
} /* namespace upb */
#endif
/* The maximum number of bytes we are required to buffer internally between
* calls to the decoder. The value is 14: a 5 byte unknown tag plus ten-byte
* varint, less one because we are buffering an incomplete value.
*
* Should only be used by unit tests. */
#define UPB_DECODER_MAX_RESIDUAL_BYTES 14
/* upb_pbdecodermethod ********************************************************/
struct upb_pbdecodermethod;
typedef struct upb_pbdecodermethod upb_pbdecodermethod;
#ifdef __cplusplus
extern "C" {
#endif
const upb_handlers *upb_pbdecodermethod_desthandlers(
const upb_pbdecodermethod *m);
const upb_byteshandler *upb_pbdecodermethod_inputhandler(
const upb_pbdecodermethod *m);
bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m);
#ifdef __cplusplus
} /* extern "C" */
/* Represents the code to parse a protobuf according to a destination
* Handlers. */
class upb::pb::DecoderMethodPtr {
public:
DecoderMethodPtr() : ptr_(nullptr) {}
DecoderMethodPtr(const upb_pbdecodermethod* ptr) : ptr_(ptr) {}
const upb_pbdecodermethod* ptr() { return ptr_; }
/* The destination handlers that are statically bound to this method.
* This method is only capable of outputting to a sink that uses these
* handlers. */
const Handlers *dest_handlers() const {
return upb_pbdecodermethod_desthandlers(ptr_);
}
/* The input handlers for this decoder method. */
const BytesHandler* input_handler() const {
return upb_pbdecodermethod_inputhandler(ptr_);
}
/* Whether this method is native. */
bool is_native() const {
return upb_pbdecodermethod_isnative(ptr_);
}
private:
const upb_pbdecodermethod* ptr_;
};
#endif
/* upb_pbdecoder **************************************************************/
/* Preallocation hint: decoder won't allocate more bytes than this when first
* constructed. This hint may be an overestimate for some build configurations.
* But if the decoder library is upgraded without recompiling the application,
* it may be an underestimate. */
#define UPB_PB_DECODER_SIZE 4416
struct upb_pbdecoder;
typedef struct upb_pbdecoder upb_pbdecoder;
#ifdef __cplusplus
extern "C" {
#endif
upb_pbdecoder *upb_pbdecoder_create(upb_arena *arena,
const upb_pbdecodermethod *method,
upb_sink output, upb_status *status);
const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d);
upb_bytessink upb_pbdecoder_input(upb_pbdecoder *d);
uint64_t upb_pbdecoder_bytesparsed(const upb_pbdecoder *d);
size_t upb_pbdecoder_maxnesting(const upb_pbdecoder *d);
bool upb_pbdecoder_setmaxnesting(upb_pbdecoder *d, size_t max);
void upb_pbdecoder_reset(upb_pbdecoder *d);
#ifdef __cplusplus
} /* extern "C" */
/* A Decoder receives binary protobuf data on its input sink and pushes the
* decoded data to its output sink. */
class upb::pb::DecoderPtr {
public:
DecoderPtr() : ptr_(nullptr) {}
DecoderPtr(upb_pbdecoder* ptr) : ptr_(ptr) {}
upb_pbdecoder* ptr() { return ptr_; }
/* Constructs a decoder instance for the given method, which must outlive this
* decoder. Any errors during parsing will be set on the given status, which
* must also outlive this decoder.
*
* The sink must match the given method. */
static DecoderPtr Create(Arena *arena, DecoderMethodPtr method,
upb::Sink output, Status *status) {
return DecoderPtr(upb_pbdecoder_create(arena->ptr(), method.ptr(),
output.sink(), status->ptr()));
}
/* Returns the DecoderMethod this decoder is parsing from. */
const DecoderMethodPtr method() const {
return DecoderMethodPtr(upb_pbdecoder_method(ptr_));
}
/* The sink on which this decoder receives input. */
BytesSink input() { return BytesSink(upb_pbdecoder_input(ptr())); }
/* Returns number of bytes successfully parsed.
*
* This can be useful for determining the stream position where an error
* occurred.
*
* This value may not be up-to-date when called from inside a parsing
* callback. */
uint64_t BytesParsed() { return upb_pbdecoder_bytesparsed(ptr()); }
/* Gets/sets the parsing nexting limit. If the total number of nested
* submessages and repeated fields hits this limit, parsing will fail. This
* is a resource limit that controls the amount of memory used by the parsing
* stack.
*
* Setting the limit will fail if the parser is currently suspended at a depth
* greater than this, or if memory allocation of the stack fails. */
size_t max_nesting() { return upb_pbdecoder_maxnesting(ptr()); }
bool set_max_nesting(size_t max) {
return upb_pbdecoder_setmaxnesting(ptr(), max);
}
void Reset() { upb_pbdecoder_reset(ptr()); }
static const size_t kSize = UPB_PB_DECODER_SIZE;
private:
upb_pbdecoder *ptr_;
};
#endif /* __cplusplus */
/* upb_pbcodecache ************************************************************/
/* Lazily builds and caches decoder methods that will push data to the given
* handlers. The destination handlercache must outlive this object. */
struct upb_pbcodecache;
typedef struct upb_pbcodecache upb_pbcodecache;
#ifdef __cplusplus
extern "C" {
#endif
upb_pbcodecache *upb_pbcodecache_new(upb_handlercache *dest);
void upb_pbcodecache_free(upb_pbcodecache *c);
bool upb_pbcodecache_allowjit(const upb_pbcodecache *c);
void upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow);
void upb_pbcodecache_setlazy(upb_pbcodecache *c, bool lazy);
const upb_pbdecodermethod *upb_pbcodecache_get(upb_pbcodecache *c,
const upb_msgdef *md);
#ifdef __cplusplus
} /* extern "C" */
/* A class for caching protobuf processing code, whether bytecode for the
* interpreted decoder or machine code for the JIT.
*
* This class is not thread-safe. */
class upb::pb::CodeCache {
public:
CodeCache(upb::HandlerCache *dest)
: ptr_(upb_pbcodecache_new(dest->ptr()), upb_pbcodecache_free) {}
CodeCache(CodeCache&&) = default;
CodeCache& operator=(CodeCache&&) = default;
upb_pbcodecache* ptr() { return ptr_.get(); }
const upb_pbcodecache* ptr() const { return ptr_.get(); }
/* Whether the cache is allowed to generate machine code. Defaults to true.
* There is no real reason to turn it off except for testing or if you are
* having a specific problem with the JIT.
*
* Note that allow_jit = true does not *guarantee* that the code will be JIT
* compiled. If this platform is not supported or the JIT was not compiled
* in, the code may still be interpreted. */
bool allow_jit() const { return upb_pbcodecache_allowjit(ptr()); }
/* This may only be called when the object is first constructed, and prior to
* any code generation. */
void set_allow_jit(bool allow) { upb_pbcodecache_setallowjit(ptr(), allow); }
/* Should the decoder push submessages to lazy handlers for fields that have
* them? The caller should set this iff the lazy handlers expect data that is
* in protobuf binary format and the caller wishes to lazy parse it. */
void set_lazy(bool lazy) { upb_pbcodecache_setlazy(ptr(), lazy); }
/* Returns a DecoderMethod that can push data to the given handlers.
* If a suitable method already exists, it will be returned from the cache. */
const DecoderMethodPtr Get(MessageDefPtr md) {
return DecoderMethodPtr(upb_pbcodecache_get(ptr(), md.ptr()));
}
private:
std::unique_ptr<upb_pbcodecache, decltype(&upb_pbcodecache_free)> ptr_;
};
#endif /* __cplusplus */
#endif /* UPB_DECODER_H_ */