proto.h (130 lines of code) (raw):
#ifndef LIBWATCHMAN_PROTO_H_
#define LIBWATCHMAN_PROTO_H_
#include <jansson.h>
#include "bser.h"
#include "bser_parse.h"
/* A wrapper around json (jansson) or bser */
enum { PROTO_BSER, PROTO_JSON };
typedef struct proto_ptr {
union {
json_t* json;
bser_t* bser;
} u;
int type;
} proto_t;
proto_t
proto_from_json(json_t* json)
{
proto_t proto;
proto.u.json = json;
proto.type = PROTO_JSON;
return proto;
}
proto_t
proto_from_bser(bser_t* bser)
{
proto_t proto;
proto.u.bser = bser;
proto.type = PROTO_BSER;
return proto;
}
proto_t
proto_null()
{
proto_t proto;
proto.u.json = NULL;
return proto;
}
int
proto_is_null(proto_t p)
{
return p.u.json == NULL;
}
#define PROTO_DISPATCH(ret, name) \
ret \
proto_##name(proto_t p) \
{ \
return p.type == PROTO_JSON ? \
json_##name(p.u.json) : \
bser_##name(p.u.bser); \
}
PROTO_DISPATCH(int, is_boolean)
PROTO_DISPATCH(int, is_integer)
PROTO_DISPATCH(int, is_real)
PROTO_DISPATCH(int, is_string)
PROTO_DISPATCH(int, is_array)
PROTO_DISPATCH(int, is_object)
PROTO_DISPATCH(int, is_true)
PROTO_DISPATCH(int64_t, integer_value)
PROTO_DISPATCH(double, real_value)
PROTO_DISPATCH(int, array_size)
#undef PROTO_DISPATCH
/* Returns a potentially non-null-terminated read-only string, with a length */
const char*
proto_string_value(proto_t p, size_t* length)
{
if (p.type == PROTO_JSON) {
const char* v = json_string_value(p.u.json);
*length = strlen(v);
return v;
} else {
return bser_string_value(p.u.bser, length);
}
}
/* Returns a dynamically-allocated null-terminated c-string (caller-owned) */
char*
proto_strdup(proto_t p)
{
size_t length;
const char* v = proto_string_value(p, &length);
if (v[length] == '\0') {
return strdup(v);
} else {
char* res = malloc(length + 1);
memcpy(res, v, length);
res[length] = '\0';
return res;
}
}
proto_t
proto_array_get(proto_t p, int index)
{
return p.type == PROTO_JSON ?
proto_from_json(json_array_get(p.u.json, index)) :
proto_from_bser(bser_array_get(p.u.bser, index));
}
proto_t
proto_object_get(proto_t p, const char* key)
{
return p.type == PROTO_JSON ?
proto_from_json(json_object_get(p.u.json, key)) :
proto_from_bser(bser_object_get(p.u.bser, key));
}
char*
proto_dumps(proto_t p, int flags)
{
json_t* json = p.u.json;
char* result;
if (p.type == PROTO_BSER) {
json_error_t err;
json = bser2json(p.u.bser, &err);
if (json == NULL) {
json = json_string(err.text);
flags |= JSON_ENCODE_ANY;
}
}
result = json_dumps(json, flags);
if (p.type == PROTO_BSER) {
json_decref(json);
}
return result;
}
/* The proto_free command only decrefs the json object in json mode, so
* it's only a true free if the json only has one reference. */
void
proto_free(proto_t p)
{
if (p.type == PROTO_JSON) {
json_decref(p.u.json);
p.u.json = NULL;
} else {
bser_free(p.u.bser);
p.u.bser = NULL;
}
}
#endif /* ndef LIBWATCHMAN_PROTO_H_ */