diff options
Diffstat (limited to 'src/upb_bytestream.h')
-rw-r--r-- | src/upb_bytestream.h | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/src/upb_bytestream.h b/src/upb_bytestream.h new file mode 100644 index 0000000..e4b51fd --- /dev/null +++ b/src/upb_bytestream.h @@ -0,0 +1,123 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2010-2011 Google Inc. See LICENSE for details. + * Author: Josh Haberman <jhaberman@gmail.com> + * + * Defines the interfaces upb_bytesrc and upb_bytesink, which are abstractions + * of read()/write() with useful buffering/sharing semantics. + */ + +#ifndef UPB_BYTESTREAM_H +#define UPB_BYTESTREAM_H + +#include <stdarg.h> +#include "upb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* upb_bytesrc ****************************************************************/ + +// upb_bytesrc is a pull interface for streams of bytes, basically an +// abstraction of read()/fread(), but it avoids copies where possible. + +typedef upb_strlen_t (*upb_bytesrc_read_fptr)( + upb_bytesrc *src, void *buf, upb_strlen_t count, upb_status *status); +typedef bool (*upb_bytesrc_getstr_fptr)( + upb_bytesrc *src, upb_string *str, upb_status *status); + +typedef struct { + upb_bytesrc_read_fptr read; + upb_bytesrc_getstr_fptr getstr; +} upb_bytesrc_vtbl; + +struct _upb_bytesrc { + upb_bytesrc_vtbl *vtbl; +}; + +INLINE void upb_bytesrc_init(upb_bytesrc *s, upb_bytesrc_vtbl *vtbl) { + s->vtbl = vtbl; +} + +// Reads up to "count" bytes into "buf", returning the total number of bytes +// read. If 0, indicates error and puts details in "status". +INLINE upb_strlen_t upb_bytesrc_read(upb_bytesrc *src, void *buf, + upb_strlen_t count, upb_status *status) { + return src->vtbl->read(src, buf, count, status); +} + +// Like upb_bytesrc_read(), but modifies "str" in-place. Caller must ensure +// that "str" is created or just recycled. Returns "false" if no data was +// returned, either due to error or EOF (check status for details). +// +// In comparison to upb_bytesrc_read(), this call can possibly alias existing +// string data (which avoids a copy). On the other hand, if the data was *not* +// already in an existing string, this copies it into a upb_string, and if the +// data needs to be put in a specific range of memory (because eg. you need to +// put it into a different kind of string object) then upb_bytesrc_get() could +// save you a copy. +INLINE bool upb_bytesrc_getstr(upb_bytesrc *src, upb_string *str, + upb_status *status) { + return src->vtbl->getstr(src, str, status); +} + + +/* upb_bytesink ***************************************************************/ + +struct _upb_bytesink; +typedef struct _upb_bytesink upb_bytesink; +typedef upb_strlen_t (*upb_bytesink_putstr_fptr)( + upb_bytesink *bytesink, upb_string *str, upb_status *status); +typedef upb_strlen_t (*upb_bytesink_vprintf_fptr)( + upb_bytesink *bytesink, upb_status *status, const char *fmt, va_list args); + +typedef struct { + upb_bytesink_putstr_fptr putstr; + upb_bytesink_vprintf_fptr vprintf; +} upb_bytesink_vtbl; + +struct _upb_bytesink { + upb_bytesink_vtbl *vtbl; +}; + +INLINE void upb_bytesink_init(upb_bytesink *s, upb_bytesink_vtbl *vtbl) { + s->vtbl = vtbl; +} + + +// TODO: Figure out how buffering should be handled. Should the caller buffer +// data and only call these functions when a buffer is full? Seems most +// efficient, but then buffering has to be configured in the caller, which +// could be anything, which makes it hard to have a standard interface for +// controlling buffering. +// +// The downside of having the bytesink buffer is efficiency: the caller is +// making more (virtual) function calls, and the caller can't arrange to have +// a big contiguous buffer. The bytesink can do this, but will have to copy +// to make the data contiguous. + +// Returns the number of bytes written. +INLINE upb_strlen_t upb_bytesink_printf(upb_bytesink *sink, upb_status *status, + const char *fmt, ...) { + va_list args; + va_start(args, fmt); + upb_strlen_t ret = sink->vtbl->vprintf(sink, status, fmt, args); + va_end(args); + return ret; +} + +// Puts the given string, returning true if the operation was successful, otherwise +// check "status" for details. Ownership of the string is *not* passed; if +// the callee wants a reference he must call upb_string_getref() on it. +INLINE upb_strlen_t upb_bytesink_putstr(upb_bytesink *sink, upb_string *str, + upb_status *status) { + return sink->vtbl->putstr(sink, str, status); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif |