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.
 
 
 
 
 
 

262 lines
8.4 KiB

/*
* upb - a minimalist implementation of protocol buffers.
*
* Copyright (c) 2009 Google Inc. See LICENSE for details.
* Author: Josh Haberman <jhaberman@gmail.com>
*
* This file contains shared definitions that are widely used across upb.
*/
#ifndef UPB_H_
#define UPB_H_
#include <assert.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
// inline if possible, emit standalone code if required.
#ifndef INLINE
#define INLINE static inline
#endif
#ifdef __GNUC__
#define UPB_NORETURN __attribute__((__noreturn__))
#else
#define UPB_NORETURN
#endif
#ifndef UINT16_MAX
#define UINT16_MAX 65535
#endif
#define UPB_MAX(x, y) ((x) > (y) ? (x) : (y))
#define UPB_MIN(x, y) ((x) < (y) ? (x) : (y))
// The maximum that any submessages can be nested. Matches proto2's limit.
// At the moment this specifies the size of several statically-sized arrays
// and therefore setting it high will cause more memory to be used. Will
// be replaced by a runtime-configurable limit and dynamically-resizing arrays.
// TODO: make this a runtime-settable property of upb_handlers.
#define UPB_MAX_NESTING 64
// The maximum number of fields that any one .proto type can have. Note that
// this is very different than the max field number. It is hard to imagine a
// scenario where more than 2k fields (each with its own name and field number)
// makes sense. The .proto file to describe it would be 2000 lines long and
// contain 2000 unique names.
//
// With this limit we can store a has-bit offset in 8 bits (2**8 * 8 = 2048)
// and we can store a value offset in 16 bits, since the maximum message
// size is 16,640 bytes (2**8 has-bits + 2048 * 8-byte value). Note that
// strings and arrays are not counted in this, only the *pointer* to them is.
// An individual string or array is unaffected by this 16k byte limit.
#define UPB_MAX_FIELDS (2048)
#define UPB_MAX_FIELDNUMBER ((1 << 29) - 1)
// Nested type names are separated by periods.
#define UPB_SYMBOL_SEPARATOR '.'
// The longest chain that mutually-recursive types are allowed to form. For
// example, this is a type cycle of length 2:
// message A {
// B b = 1;
// }
// message B {
// A a = 1;
// }
#define UPB_MAX_TYPE_CYCLE_LEN 16
// The maximum depth that the type graph can have. Note that this setting does
// not automatically constrain UPB_MAX_NESTING, because type cycles allow for
// unlimited nesting if we do not limit it. Many algorithms in upb call
// recursive functions that traverse the type graph, so we must limit this to
// avoid blowing the C stack.
#define UPB_MAX_TYPE_DEPTH 64
/* upb_value ******************************************************************/
// Clients should not need to access these enum values; they are used internally
// to do typechecks of upb_value accesses.
typedef enum {
UPB_CTYPE_INT32 = 1,
UPB_CTYPE_INT64 = 2,
UPB_CTYPE_UINT32 = 3,
UPB_CTYPE_UINT64 = 4,
UPB_CTYPE_DOUBLE = 5,
UPB_CTYPE_FLOAT = 6,
UPB_CTYPE_BOOL = 7,
UPB_CTYPE_PTR = 8,
UPB_CTYPE_BYTEREGION = 9,
UPB_CTYPE_FIELDDEF = 10,
} upb_ctype_t;
struct _upb_byteregion;
struct _upb_fielddef;
// A single .proto value. The owner must have an out-of-band way of knowing
// the type, so that it knows which union member to use.
typedef struct {
union {
uint64_t uint64;
int32_t int32;
int64_t int64;
uint32_t uint32;
double _double;
float _float;
bool _bool;
void *_void;
struct _upb_byteregion *byteregion;
const struct _upb_fielddef *fielddef;
} val;
#ifndef NDEBUG
// In debug mode we carry the value type around also so we can check accesses
// to be sure the right member is being read.
upb_ctype_t type;
#endif
} upb_value;
#ifdef NDEBUG
#define SET_TYPE(dest, val)
#else
#define SET_TYPE(dest, val) dest = val
#endif
// For each value type, define the following set of functions:
//
// // Get/set an int32 from a upb_value.
// int32_t upb_value_getint32(upb_value val);
// void upb_value_setint32(upb_value *val, int32_t cval);
//
// // Construct a new upb_value from an int32.
// upb_value upb_value_int32(int32_t val);
#define WRITERS(name, membername, ctype, proto_type) \
INLINE void upb_value_set ## name(upb_value *val, ctype cval) { \
val->val.uint64 = 0; \
SET_TYPE(val->type, proto_type); \
val->val.membername = cval; \
} \
INLINE upb_value upb_value_ ## name(ctype val) { \
upb_value ret; \
upb_value_set ## name(&ret, val); \
return ret; \
}
#define ALL(name, membername, ctype, proto_type) \
/* Can't reuse WRITERS() here unfortunately because "bool" is a macro \
* that expands to _Bool, so it ends up defining eg. upb_value_set_Bool */ \
INLINE void upb_value_set ## name(upb_value *val, ctype cval) { \
val->val.uint64 = 0; \
SET_TYPE(val->type, proto_type); \
val->val.membername = cval; \
} \
INLINE upb_value upb_value_ ## name(ctype val) { \
upb_value ret; \
upb_value_set ## name(&ret, val); \
return ret; \
} \
INLINE ctype upb_value_get ## name(upb_value val) { \
assert(val.type == proto_type); \
return val.val.membername; \
}
ALL(int32, int32, int32_t, UPB_CTYPE_INT32);
ALL(int64, int64, int64_t, UPB_CTYPE_INT64);
ALL(uint32, uint32, uint32_t, UPB_CTYPE_UINT32);
ALL(uint64, uint64, uint64_t, UPB_CTYPE_UINT64);
ALL(bool, _bool, bool, UPB_CTYPE_BOOL);
ALL(ptr, _void, void*, UPB_CTYPE_PTR);
ALL(byteregion, byteregion, struct _upb_byteregion*, UPB_CTYPE_BYTEREGION);
// upb_fielddef should never be modified from a callback
// (ie. when they're getting passed through a upb_value).
ALL(fielddef, fielddef, const struct _upb_fielddef*, UPB_CTYPE_FIELDDEF);
#ifdef __KERNEL__
// Linux kernel modules are compiled without SSE and therefore are incapable
// of compiling functions that return floating-point values, so we define as
// macros instead and lose the type check.
WRITERS(double, _double, double, UPB_CTYPE_DOUBLE);
WRITERS(float, _float, float, UPB_CTYPE_FLOAT);
#define upb_value_getdouble(v) (v.val._double)
#define upb_value_getfloat(v) (v.val._float)
#else
ALL(double, _double, double, UPB_CTYPE_DOUBLE);
ALL(float, _float, float, UPB_CTYPE_FLOAT);
#endif /* __KERNEL__ */
#undef WRITERS
#undef ALL
extern upb_value UPB_NO_VALUE;
/* upb_status *****************************************************************/
typedef enum {
UPB_OK, // The operation completed successfully.
UPB_SUSPENDED, // The operation was suspended and may be resumed later.
UPB_ERROR, // An error occurred.
} upb_success_t;
typedef struct {
const char *name;
// Writes a NULL-terminated string to "buf" containing an error message for
// the given error code, returning false if the message was too large to fit.
bool (*code_to_string)(int code, char *buf, size_t len);
} upb_errorspace;
typedef struct {
bool error;
bool eof;
// Specific status code defined by some error space (optional).
int code;
upb_errorspace *space;
// Error message (optional).
const char *str; // NULL when no message is present. NULL-terminated.
char *buf; // Owned by the status.
size_t bufsize;
} upb_status;
#define UPB_STATUS_INIT {UPB_OK, false, 0, NULL, NULL, NULL, 0}
void upb_status_init(upb_status *status);
void upb_status_uninit(upb_status *status);
INLINE bool upb_ok(const upb_status *status) { return !status->error; }
INLINE bool upb_eof(const upb_status *status) { return status->eof; }
void upb_status_clear(upb_status *status);
void upb_status_seterrliteral(upb_status *status, const char *msg);
void upb_status_seterrf(upb_status *s, const char *msg, ...);
void upb_status_setcode(upb_status *s, upb_errorspace *space, int code);
INLINE void upb_status_seteof(upb_status *s) { s->eof = true; }
// The returned string is invalidated by any other call into the status.
const char *upb_status_getstr(const upb_status *s);
void upb_status_copy(upb_status *to, const upb_status *from);
// Like vasprintf (which allocates a string large enough for the result), but
// uses *buf (which can be NULL) as a starting point and reallocates it only if
// the new value will not fit. "size" is updated to reflect the allocated size
// of the buffer. Starts writing at the given offset into the string; bytes
// preceding this offset are unaffected. Returns the new length of the string,
// or -1 on memory allocation failure.
int upb_vrprintf(char **buf, size_t *size, size_t ofs,
const char *fmt, va_list args);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* UPB_H_ */