mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-19 05:44:12 +01:00
params: simplify lifetimes of params.
@wythe points out we don't need to keep the around now param_is_set() is removed. We can in fact go further and avoid marshalling them into temporary objects at the caller altogether. This means internally we have an array of struct param, rather than an array of 'struct param *', which causes most of the noise in this patch. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
3f6f9e6fe0
commit
6ff901d7b0
@ -16,16 +16,20 @@ struct param {
|
|||||||
size_t argsize;
|
size_t argsize;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct param *param_add_(const tal_t *ctx,
|
static void param_add(struct param **params,
|
||||||
const char *name, param_cb cb, void *arg,
|
const char *name, param_cb cb, void *arg,
|
||||||
size_t argsize)
|
const tal_t *ctx, size_t argsize)
|
||||||
{
|
{
|
||||||
#if DEVELOPER
|
#if DEVELOPER
|
||||||
assert(name);
|
assert(name);
|
||||||
assert(cb);
|
assert(cb);
|
||||||
assert(arg);
|
assert(arg);
|
||||||
#endif
|
#endif
|
||||||
struct param *last = tal(tmpctx, struct param);
|
struct param *last;
|
||||||
|
|
||||||
|
tal_resize(params, tal_count(*params) + 1);
|
||||||
|
last = &(*params)[tal_count(*params) - 1];
|
||||||
|
|
||||||
last->ctx = ctx;
|
last->ctx = ctx;
|
||||||
last->is_set = false;
|
last->is_set = false;
|
||||||
last->name = name;
|
last->name = name;
|
||||||
@ -35,22 +39,6 @@ struct param *param_add_(const tal_t *ctx,
|
|||||||
/* Non-NULL means we are supposed to allocate iff found */
|
/* Non-NULL means we are supposed to allocate iff found */
|
||||||
if (last->ctx)
|
if (last->ctx)
|
||||||
*(void **)last->arg = NULL;
|
*(void **)last->arg = NULL;
|
||||||
return last;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct param *param_opt_add_(const tal_t *ctx, const char *name,
|
|
||||||
const jsmntok_t **tok)
|
|
||||||
{
|
|
||||||
struct param *last = tal(tmpctx, struct param);
|
|
||||||
assert(ctx);
|
|
||||||
last->ctx = ctx;
|
|
||||||
last->is_set = false;
|
|
||||||
last->name = name;
|
|
||||||
last->cb = (param_cb)json_tok_tok;
|
|
||||||
last->arg = tok;
|
|
||||||
last->argsize = sizeof(*tok);
|
|
||||||
*tok = NULL;
|
|
||||||
return last;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fail_format {
|
struct fail_format {
|
||||||
@ -109,17 +97,17 @@ static bool make_callback(struct command *cmd,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct param **post_check(struct command *cmd, struct param **params)
|
static struct param *post_check(struct command *cmd, struct param *params)
|
||||||
{
|
{
|
||||||
struct param **first = params;
|
struct param *first = params;
|
||||||
struct param **last = first + tal_count(params);
|
struct param *last = first + tal_count(params);
|
||||||
|
|
||||||
/* Make sure required params were provided. */
|
/* Make sure required params were provided. */
|
||||||
while (first != last && (*first)->argsize == 0) {
|
while (first != last && first->argsize == 0) {
|
||||||
if (!(*first)->is_set) {
|
if (!first->is_set) {
|
||||||
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||||
"missing required parameter: '%s'",
|
"missing required parameter: '%s'",
|
||||||
(*first)->name);
|
first->name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
first++;
|
first++;
|
||||||
@ -127,19 +115,19 @@ static struct param **post_check(struct command *cmd, struct param **params)
|
|||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct param **parse_by_position(struct command *cmd,
|
static bool parse_by_position(struct command *cmd,
|
||||||
struct param **params,
|
struct param *params,
|
||||||
const char *buffer,
|
const char *buffer,
|
||||||
const jsmntok_t tokens[])
|
const jsmntok_t tokens[])
|
||||||
{
|
{
|
||||||
const jsmntok_t *tok = tokens + 1;
|
const jsmntok_t *tok = tokens + 1;
|
||||||
const jsmntok_t *end = json_next(tokens);
|
const jsmntok_t *end = json_next(tokens);
|
||||||
struct param **first = params;
|
struct param *first = params;
|
||||||
struct param **last = first + tal_count(params);
|
struct param *last = first + tal_count(params);
|
||||||
|
|
||||||
while (first != last && tok != end) {
|
while (first != last && tok != end) {
|
||||||
if (!json_tok_is_null(buffer, tok))
|
if (!json_tok_is_null(buffer, tok))
|
||||||
if (!make_callback(cmd, *first, buffer, tok))
|
if (!make_callback(cmd, first, buffer, tok))
|
||||||
return NULL;
|
return NULL;
|
||||||
tok = json_next(tok);
|
tok = json_next(tok);
|
||||||
first++;
|
first++;
|
||||||
@ -151,29 +139,29 @@ static struct param **parse_by_position(struct command *cmd,
|
|||||||
"too many parameters:"
|
"too many parameters:"
|
||||||
" got %u, expected %zu",
|
" got %u, expected %zu",
|
||||||
tokens->size, tal_count(params));
|
tokens->size, tal_count(params));
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return post_check(cmd, params);
|
return post_check(cmd, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct param *find_param(struct param **params, const char *start,
|
static struct param *find_param(struct param *params, const char *start,
|
||||||
size_t n)
|
size_t n)
|
||||||
{
|
{
|
||||||
struct param **first = params;
|
struct param *first = params;
|
||||||
struct param **last = first + tal_count(params);
|
struct param *last = first + tal_count(params);
|
||||||
|
|
||||||
while (first != last) {
|
while (first != last) {
|
||||||
if (strncmp((*first)->name, start, n) == 0)
|
if (strncmp(first->name, start, n) == 0)
|
||||||
if (strlen((*first)->name) == n)
|
if (strlen(first->name) == n)
|
||||||
return *first;
|
return first;
|
||||||
first++;
|
first++;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct param **parse_by_name(struct command *cmd,
|
static bool parse_by_name(struct command *cmd,
|
||||||
struct param **params,
|
struct param *params,
|
||||||
const char *buffer,
|
const char *buffer,
|
||||||
const jsmntok_t tokens[])
|
const jsmntok_t tokens[])
|
||||||
{
|
{
|
||||||
@ -188,36 +176,36 @@ static struct param **parse_by_name(struct command *cmd,
|
|||||||
"unknown parameter: '%.*s'",
|
"unknown parameter: '%.*s'",
|
||||||
first->end - first->start,
|
first->end - first->start,
|
||||||
buffer + first->start);
|
buffer + first->start);
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p->is_set) {
|
if (p->is_set) {
|
||||||
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||||
"duplicate json names: '%s'", p->name);
|
"duplicate json names: '%s'", p->name);
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!make_callback(cmd, p, buffer, first + 1))
|
if (!make_callback(cmd, p, buffer, first + 1))
|
||||||
return NULL;
|
return false;
|
||||||
first = json_next(first + 1);
|
first = json_next(first + 1);
|
||||||
}
|
}
|
||||||
return post_check(cmd, params);
|
return post_check(cmd, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEVELOPER
|
#if DEVELOPER
|
||||||
static int comp_by_name(struct param *const *a, struct param *const *b,
|
static int comp_by_name(const struct param *a, const struct param *b,
|
||||||
void *unused)
|
void *unused)
|
||||||
{
|
{
|
||||||
return strcmp((*a)->name, (*b)->name);
|
return strcmp(a->name, b->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int comp_by_arg(struct param *const *a, struct param *const *b,
|
static int comp_by_arg(const struct param *a, const struct param *b,
|
||||||
void *unused)
|
void *unused)
|
||||||
{
|
{
|
||||||
/* size_t could be larger than int: don't turn a 4bn difference into 0 */
|
/* size_t could be larger than int: don't turn a 4bn difference into 0 */
|
||||||
if ((*a)->arg > (*b)->arg)
|
if (a->arg > b->arg)
|
||||||
return 1;
|
return 1;
|
||||||
else if ((*a)->arg < (*b)->arg)
|
else if (a->arg < b->arg)
|
||||||
return -1;
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -225,10 +213,10 @@ static int comp_by_arg(struct param *const *a, struct param *const *b,
|
|||||||
/* This comparator is a bit different, but works well.
|
/* This comparator is a bit different, but works well.
|
||||||
* Return 0 if @a is optional and @b is required. Otherwise return 1.
|
* Return 0 if @a is optional and @b is required. Otherwise return 1.
|
||||||
*/
|
*/
|
||||||
static int comp_req_order(struct param *const *a, struct param *const *b,
|
static int comp_req_order(const struct param *a, const struct param *b,
|
||||||
void *unused)
|
void *unused)
|
||||||
{
|
{
|
||||||
if ((*a)->argsize != 0 && (*b)->argsize == 0)
|
if (a->argsize != 0 && b->argsize == 0)
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -237,12 +225,12 @@ static int comp_req_order(struct param *const *a, struct param *const *b,
|
|||||||
* Make sure 2 sequential items in @params are not equal (based on
|
* Make sure 2 sequential items in @params are not equal (based on
|
||||||
* provided comparator).
|
* provided comparator).
|
||||||
*/
|
*/
|
||||||
static void check_distinct(struct param **params,
|
static void check_distinct(struct param *params,
|
||||||
int (*compar) (struct param *const *a,
|
int (*compar) (const struct param *a,
|
||||||
struct param *const *b, void *unused))
|
const struct param *b, void *unused))
|
||||||
{
|
{
|
||||||
struct param **first = params;
|
struct param *first = params;
|
||||||
struct param **last = first + tal_count(params);
|
struct param *last = first + tal_count(params);
|
||||||
first++;
|
first++;
|
||||||
while (first != last) {
|
while (first != last) {
|
||||||
assert(compar(first - 1, first, NULL) != 0);
|
assert(compar(first - 1, first, NULL) != 0);
|
||||||
@ -250,9 +238,9 @@ static void check_distinct(struct param **params,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void check_unique(struct param **copy,
|
static void check_unique(struct param *copy,
|
||||||
int (*compar) (struct param *const *a,
|
int (*compar) (const struct param *a,
|
||||||
struct param *const *b, void *unused))
|
const struct param *b, void *unused))
|
||||||
{
|
{
|
||||||
asort(copy, tal_count(copy), compar, NULL);
|
asort(copy, tal_count(copy), compar, NULL);
|
||||||
check_distinct(copy, compar);
|
check_distinct(copy, compar);
|
||||||
@ -261,7 +249,7 @@ static void check_unique(struct param **copy,
|
|||||||
/*
|
/*
|
||||||
* Verify consistent internal state.
|
* Verify consistent internal state.
|
||||||
*/
|
*/
|
||||||
static void check_params(struct param **params)
|
static void check_params(struct param *params)
|
||||||
{
|
{
|
||||||
if (tal_count(params) < 2)
|
if (tal_count(params) < 2)
|
||||||
return;
|
return;
|
||||||
@ -270,7 +258,7 @@ static void check_params(struct param **params)
|
|||||||
check_distinct(params, comp_req_order);
|
check_distinct(params, comp_req_order);
|
||||||
|
|
||||||
/* duplicate so we can sort */
|
/* duplicate so we can sort */
|
||||||
struct param **copy = tal_dup_arr(params, struct param *,
|
struct param *copy = tal_dup_arr(params, struct param,
|
||||||
params, tal_count(params), 0);
|
params, tal_count(params), 0);
|
||||||
|
|
||||||
/* check for repeated names and args */
|
/* check for repeated names and args */
|
||||||
@ -281,10 +269,10 @@ static void check_params(struct param **params)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static struct param **param_parse_arr(struct command *cmd,
|
static bool param_parse_arr(struct command *cmd,
|
||||||
const char *buffer,
|
const char *buffer,
|
||||||
const jsmntok_t tokens[],
|
const jsmntok_t tokens[],
|
||||||
struct param **params)
|
struct param *params)
|
||||||
{
|
{
|
||||||
#if DEVELOPER
|
#if DEVELOPER
|
||||||
check_params(params);
|
check_params(params);
|
||||||
@ -296,20 +284,23 @@ static struct param **param_parse_arr(struct command *cmd,
|
|||||||
|
|
||||||
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||||
"Expected array or object for params");
|
"Expected array or object for params");
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct param **param_parse(struct command *cmd, const char *buffer,
|
bool param_parse(struct command *cmd, const char *buffer,
|
||||||
const jsmntok_t tokens[], ...)
|
const jsmntok_t tokens[], ...)
|
||||||
{
|
{
|
||||||
struct param *def;
|
struct param *params = tal_arr(tmpctx, struct param, 0);
|
||||||
struct param **params = tal_arr(cmd, struct param *, 0);
|
const char *name;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
va_start(ap, tokens);
|
va_start(ap, tokens);
|
||||||
while ((def = va_arg(ap, struct param *)) != NULL) {
|
while ((name = va_arg(ap, const char *)) != NULL) {
|
||||||
tal_steal(params, def);
|
param_cb cb = va_arg(ap, param_cb);
|
||||||
tal_resize(¶ms, tal_count(params) + 1);
|
void *arg = va_arg(ap, void *);
|
||||||
params[tal_count(params) - 1] = def;
|
const tal_t *ctx = va_arg(ap, const tal_t *);
|
||||||
|
size_t argsize = va_arg(ap, size_t);
|
||||||
|
param_add(¶ms, name, cb, arg, ctx, argsize);
|
||||||
}
|
}
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ struct param;
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
At this point in the code you can be assured the json tokens were successfully
|
At this point in the code you can be assured the json tokens were successfully
|
||||||
parsed. If not, param_parse() returned NULL, having already called
|
parsed. If not, param_parse() returns false, having already called
|
||||||
command_fail() with a descriptive error message. The data section of the json
|
command_fail() with a descriptive error message. The data section of the json
|
||||||
result contains the offending parameter and its value.
|
result contains the offending parameter and its value.
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ struct param;
|
|||||||
|
|
||||||
Otherwise a generic message is provided.
|
Otherwise a generic message is provided.
|
||||||
*/
|
*/
|
||||||
struct param **param_parse(struct command *cmd, const char *buffer,
|
bool param_parse(struct command *cmd, const char *buffer,
|
||||||
const jsmntok_t params[], ...);
|
const jsmntok_t params[], ...);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -60,27 +60,32 @@ typedef bool(*param_cb)(const char *buffer, const jsmntok_t *tok, void *arg);
|
|||||||
* Returns an opaque pointer that can be later used in param_is_set().
|
* Returns an opaque pointer that can be later used in param_is_set().
|
||||||
*/
|
*/
|
||||||
#define param_req(name, cb, arg) \
|
#define param_req(name, cb, arg) \
|
||||||
param_add_(NULL, name"", \
|
name"", \
|
||||||
typesafe_cb_preargs(bool, void *, \
|
typesafe_cb_preargs(bool, void *, \
|
||||||
(cb), (arg), \
|
(cb), (arg), \
|
||||||
const char *, \
|
const char *, \
|
||||||
const jsmntok_t *), \
|
const jsmntok_t *), \
|
||||||
(arg), 0)
|
(arg), NULL, 0
|
||||||
/*
|
/*
|
||||||
* Same as above but for optional parameters.
|
* Same as above but for optional parameters.
|
||||||
*/
|
*/
|
||||||
#define param_opt(ctx, name, cb, arg) \
|
#define param_opt(ctx, name, cb, arg) \
|
||||||
param_add_(ctx, name"", \
|
name"", \
|
||||||
typesafe_cb_preargs(bool, void *, \
|
typesafe_cb_preargs(bool, void *, \
|
||||||
(cb), *(arg), \
|
(cb), *(arg), \
|
||||||
const char *, \
|
const char *, \
|
||||||
const jsmntok_t *), \
|
const jsmntok_t *), \
|
||||||
(arg), sizeof(**arg))
|
(arg), (ctx), sizeof(**arg)
|
||||||
struct param * param_add_(const tal_t *ctx, const char *name, param_cb cb, void *arg, size_t argsize);
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For when you want an optional raw token.
|
||||||
|
*
|
||||||
|
* Note: weird sizeof() does type check that arg really is a (const) jsmntok_t **.
|
||||||
|
*/
|
||||||
#define param_opt_tok(ctx, name, arg) \
|
#define param_opt_tok(ctx, name, arg) \
|
||||||
param_opt_add_(ctx, name"", arg)
|
name"", \
|
||||||
|
json_tok_tok, \
|
||||||
struct param *param_opt_add_(const tal_t *ctx, const char *name, const jsmntok_t **tok);
|
(arg) + 0*sizeof(*(arg) == (jsmntok_t *)NULL), \
|
||||||
|
(ctx), sizeof(const jsmntok_t *)
|
||||||
|
|
||||||
#endif /* LIGHTNING_LIGHTNINGD_PARAMS_H */
|
#endif /* LIGHTNING_LIGHTNINGD_PARAMS_H */
|
||||||
|
@ -353,15 +353,13 @@ static void add_members(struct param **params,
|
|||||||
char *name = tal_fmt(tmpctx, "%i", i);
|
char *name = tal_fmt(tmpctx, "%i", i);
|
||||||
json_add_num(obj, name, i);
|
json_add_num(obj, name, i);
|
||||||
json_add_num(arr, NULL, i);
|
json_add_num(arr, NULL, i);
|
||||||
/* Since name is not a literal, we do this manually. */
|
param_add(params, name,
|
||||||
params[i] = param_add_(NULL, name,
|
|
||||||
typesafe_cb_preargs(bool, void *,
|
typesafe_cb_preargs(bool, void *,
|
||||||
json_tok_number,
|
json_tok_number,
|
||||||
&ints[i],
|
&ints[i],
|
||||||
const char *,
|
const char *,
|
||||||
const jsmntok_t *),
|
const jsmntok_t *),
|
||||||
&ints[i], 0);
|
&ints[i], NULL, 0);
|
||||||
tal_steal(params, params[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,14 +369,14 @@ static void add_members(struct param **params,
|
|||||||
*/
|
*/
|
||||||
static void five_hundred_params(void)
|
static void five_hundred_params(void)
|
||||||
{
|
{
|
||||||
struct param **params = tal_arr(NULL, struct param *, 500);
|
struct param *params = tal_arr(NULL, struct param, 0);
|
||||||
|
|
||||||
unsigned int *ints = tal_arr(params, unsigned int, 500);
|
unsigned int *ints = tal_arr(params, unsigned int, 500);
|
||||||
struct json_result *obj = new_json_result(params);
|
struct json_result *obj = new_json_result(params);
|
||||||
struct json_result *arr = new_json_result(params);
|
struct json_result *arr = new_json_result(params);
|
||||||
json_object_start(obj, NULL);
|
json_object_start(obj, NULL);
|
||||||
json_array_start(arr, NULL);
|
json_array_start(arr, NULL);
|
||||||
add_members(params, obj, arr, ints);
|
add_members(¶ms, obj, arr, ints);
|
||||||
json_object_end(obj);
|
json_object_end(obj);
|
||||||
json_array_end(arr);
|
json_array_end(arr);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user