A tool in jerry-ext: arg transformer for binding (#1740)

It provides some APIs for binding developers, so that
they can validate the type of the js argument and convert/assign them
to the native argument.

Related Issue: #1716

JerryScript-DCO-1.0-Signed-off-by: Martijn The martijn.the@intel.com
JerryScript-DCO-1.0-Signed-off-by: Zidong Jiang zidong.jiang@intel.com
This commit is contained in:
Zidong Jiang
2017-05-04 18:00:35 +08:00
committed by GitHub
parent ede13835b2
commit 90efdf9c8b
17 changed files with 1709 additions and 3 deletions
+413
View File
@@ -0,0 +1,413 @@
# jerryx_arg types
## jerryx_arg_t
**Summary**
The structure defining a single validation/transformation step.
*Note*: For commonly used validators, `arg.h` provides helpers to create the `jerryx_arg_t`s.
For example, `jerryx_arg_number ()`, `jerryx_arg_boolean ()`, etc.
**Prototype**
```c
typedef struct
{
/** the transform function */
jerryx_arg_transform_func_t func;
/** pointer to destination where func should store the result */
void *dest;
/** extra information, specific to func */
uintptr_t extra_info;
} jerryx_arg_t;
```
**See also**
- [jerryx_arg_number](#jerryx_arg_number)
- [jerryx_arg_boolean](#jerryx_arg_boolean)
- [jerryx_arg_string](#jerryx_arg_string)
- [jerryx_arg_function](#jerryx_arg_function)
- [jerryx_arg_native_pointer](#jerryx_arg_native_pointer)
- [jerryx_arg_ignore](#jerryx_arg_ignore)
## jerryx_arg_transform_func_t
**Summary**
Signature of the transform function.
Users can create custom transformations by implementing a transform function
and using `jerryx_arg_custom ()`.
The function is expected to return `undefined` if it ran successfully or
return an `Error` in case it failed. The function can use the iterator and the
helpers `jerryx_arg_js_iterator_pop ()` and `jerryx_arg_js_iterator_peek ()` to
get the next input value.
*Note*: A transform function is allowed to consume any number of input values!
This enables complex validation like handling different JS function signatures,
mapping multiple input arguments to a C struct, etc.
The function is expected to store the result of
a successful transformation into `c_arg_p->dest`. In case the validation did
not pass, the transform should not modify `c_arg_p->dest`.
Additional parameters can be provided to the function through `c_arg_p->extra_info`.
**Prototype**
```c
typedef jerry_value_t (*jerryx_arg_transform_func_t) (jerryx_arg_js_iterator_t *js_arg_iter_p,
const jerryx_arg_t *c_arg_p);
```
**See also**
- [jerryx_arg_custom](#jerryx_arg_custom)
- [jerryx_arg_js_iterator_pop](#jerryx_arg_js_iterator_pop)
- [jerryx_arg_js_iterator_peek](#jerryx_arg_js_iterator_peek)
## jerryx_arg_coerce_t
Enum that indicates whether an argument is allowed to be coerced into the expected JS type.
- JERRYX_ARG_COERCE - the transform will invoke toNumber, toBoolean, toString, etc.
- JERRYX_ARG_NO_COERCE - the type coercion is not allowed. The transform will fail if the type does not match the expectation.
**See also**
- [jerryx_arg_number](#jerryx_arg_number)
- [jerryx_arg_boolean](#jerryx_arg_boolean)
- [jerryx_arg_string](#jerryx_arg_string)
## jerryx_arg_optional_t
Enum that indicates whether an argument is optional or required.
- JERRYX_ARG_OPTIONAL - The argument is optional. If the argument is `undefined` the transform is successful and `c_arg_p->dest` remains untouched.
- JERRYX_ARG_REQUIRED - The argument is required. If the argument is `undefined` the transform will fail and `c_arg_p->dest` remains untouched.
**See also**
- [jerryx_arg_number](#jerryx_arg_number)
- [jerryx_arg_boolean](#jerryx_arg_boolean)
- [jerryx_arg_string](#jerryx_arg_string)
- [jerryx_arg_function](#jerryx_arg_function)
- [jerryx_arg_native_pointer](#jerryx_arg_native_pointer)
# Main functions
## jerryx_arg_transform_this_and_args
**Summary**
Validate the this value and the JS arguments, and assign them to the native arguments.
This function is useful to perform input validation inside external function handlers (see `jerry_external_handler_t`).
**Prototype**
```c
jerry_value_t
jerryx_arg_transform_this_and_args (const jerry_value_t this_val,
const jerry_value_t *js_arg_p,
const jerry_length_t js_arg_cnt,
const jerryx_arg_t *c_arg_p,
jerry_length_t c_arg_cnt)
```
- `this_val` - `this` value. Note this is processed as the first value, before the array of arguments.
- `js_arg_p` - points to the array with JS arguments.
- `js_arg_cnt` - the count of the `js_arg_p` array.
- `c_arg_p` - points to the array of validation/transformation steps
- `c_arg_cnt` - the count of the `c_arg_p` array.
- return value - a `jerry_value_t` representing `undefined` if all validators passed or an `Error` if a validator failed.
**Example**
```c
// JS signature: function (requiredBool, requiredString, optionalNumber)
static jerry_value_t my_external_handler (const jerry_value_t function_obj,
const jerry_value_t this_val,
const jerry_value_t args_p[],
const jerry_length_t args_count)
{
bool required_bool;
char required_str[16];
double optional_num = 1234.567; // default value
// "mapping" defines the steps to transform input arguments to C variables:
const jerryx_arg_t mapping[] =
{
// `this` is the first value. No checking needed on `this` for this function.
jerryx_arg_ignore (),
jerryx_arg_boolean (&required_bool, JERRYX_ARG_NO_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_string (&required_str, sizeof (required_str), JERRYX_ARG_NO_COERCE, JERRYX_ARG_REQUIRED),
jerryx_arg_number (&optional_num, JERRYX_ARG_NO_COERCE, JERRYX_ARG_OPTIONAL),
};
// Validate and transform:
const jerry_value_t rv = jerryx_arg_transform_this_and_args (this_val,
args_p,
args_count,
mapping,
ARRAY_LENGTH (mapping));
if (jerry_value_has_error_flag (rv))
{
// Handle error
return rv;
}
// Validated and tranformed successfully!
// required_bool, required_str and optional_num can now be used.
// ...
}
```
**See also**
- [jerryx_arg_ignore](#jerryx_arg_ignore)
- [jerryx_arg_number](#jerryx_arg_number)
- [jerryx_arg_boolean](#jerryx_arg_boolean)
- [jerryx_arg_string](#jerryx_arg_string)
- [jerryx_arg_function](#jerryx_arg_function)
- [jerryx_arg_native_pointer](#jerryx_arg_native_pointer)
- [jerryx_arg_custom](#jerryx_arg_custom)
## jerryx_arg_transform_args
**Summary**
Validate an array of `jerry_value_t` and assign them to the native arguments.
**Prototype**
```c
jerry_value_t
jerryx_arg_transform_args (const jerry_value_t *js_arg_p,
const jerry_length_t js_arg_cnt,
const jerryx_arg_t *c_arg_p,
jerry_length_t c_arg_cnt)
```
- `js_arg_p` - points to the array with JS arguments.
- `js_arg_cnt` - the count of the `js_arg_p` array.
- `c_arg_p` - points to the array of validation/transformation steps
- `c_arg_cnt` - the count of the `c_arg_p` array.
- return value - a `jerry_value_t` representing `undefined` if all validators passed or an `Error` if a validator failed.
**See also**
- [jerryx_arg_transform_this_and_args](#jerryx_arg_transform_this_and_args)
# Helpers for commonly used validations
## jerryx_arg_number
**Summary**
Create a validation/transformation step (`jerryx_arg_t`) that expects to consume
one `number` JS argument and stores it into a C `double`.
**Prototype**
```c
static inline jerryx_arg_t
jerryx_arg_number (double *dest,
jerryx_arg_coerce_t coerce_flag,
jerryx_arg_optional_t opt_flag)
```
- return value - the created `jerryx_arg_t` instance.
- `dest` - pointer to the `double` where the result should be stored.
- `coerce_flag` - whether type coercion is allowed.
- `opt_flag` - whether the argument is optional.
**See also**
- [jerryx_arg_transform_this_and_args](#jerryx_arg_transform_this_and_args)
## jerryx_arg_boolean
**Summary**
Create a validation/transformation step (`jerryx_arg_t`) that expects to
consume one `boolean` JS argument and stores it into a C `bool`.
**Prototype**
```c
static inline jerryx_arg_t
jerryx_arg_boolean (bool *dest,
jerryx_arg_coerce_t coerce_flag,
jerryx_arg_optional_t opt_flag)
```
- return value - the created `jerryx_arg_t` instance.
- `dest` - pointer to the `bool` where the result should be stored.
- `coerce_flag` - whether type coercion is allowed.
- `opt_flag` - whether the argument is optional.
**See also**
- [jerryx_arg_transform_this_and_args](#jerryx_arg_transform_this_and_args)
## jerryx_arg_string
**Summary**
Create a validation/transformation step (`jerryx_arg_t`) that expects to
consume one `string` JS argument and stores it into a C `char` array.
**Prototype**
```c
static inline jerryx_arg_t
jerryx_arg_string (char *dest,
uint32_t size,
jerryx_arg_coerce_t coerce_flag,
jerryx_arg_optional_t opt_flag)
```
- return value - the created `jerryx_arg_t` instance.
- `dest` - pointer to the native char array where the result should be stored.
- `size` - the size of native char array.
- `coerce_flag` - whether type coercion is allowed.
- `opt_flag` - whether the argument is optional.
**See also**
- [jerryx_arg_transform_this_and_args](#jerryx_arg_transform_this_and_args)
## jerryx_arg_function
**Summary**
Create a validation/transformation step (`jerryx_arg_t`) that expects to
consume one `function` JS argument and stores it into a C `jerry_value_t`.
**Prototype**
```c
static inline jerryx_arg_t
jerryx_arg_function (jerry_value_t *dest,
jerryx_arg_optional_t opt_flag)
```
- return value - the created `jerryx_arg_t` instance.
- `dest` - pointer to the `jerry_value_t` where the result should be stored.
- `opt_flag` - whether the argument is optional.
**See also**
- [jerryx_arg_transform_this_and_args](#jerryx_arg_transform_this_and_args)
## jerryx_arg_native_pointer
**Summary**
Create a validation/transformation step (`jerryx_arg_t`) that expects to
consume one `Object` JS argument that is 'backed' with a native pointer with
a given type info. In case the native pointer info matches, the transform
will succeed and the object's native pointer will be assigned to `*dest`.
**Prototype**
```c
static inline jerryx_arg_t
jerryx_arg_native_pointer (void **dest,
const jerry_object_native_info_t *info_p,
jerryx_arg_optional_t opt_flag)
```
- return value - the created `jerryx_arg_t` instance.
- `dest` - pointer to where the resulting native pointer should be stored.
- `info_p` - expected the type info.
- `opt_flag` - whether the argument is optional.
**See also**
- [jerryx_arg_transform_this_and_args](#jerryx_arg_transform_this_and_args)
# Functions to create custom validations
## jerryx_arg_custom
**Summary**
Create a jerryx_arg_t instance with custom transform.
**Prototype**
```c
static inline jerryx_arg_t
jerryx_arg_custom (void *dest,
uintptr_t extra_info,
jerryx_arg_transform_func_t func)
```
- return value - the created `jerryx_arg_t` instance.
- `dest` - pointer to the native argument where the result should be stored.
- `extra_info` - the extra parameter data, specific to the transform function.
- `func` - the custom transform function.
**See also**
- [jerryx_arg_transform_this_and_args](#jerryx_arg_transform_this_and_args)
## jerryx_arg_js_iterator_pop
**Summary**
Pop the current `jerry_value_t` argument from the iterator.
It will change the `js_arg_idx` and `js_arg_p` value in the iterator.
**Prototype**
```c
jerry_value_t
jerryx_arg_js_iterator_pop (jerryx_arg_js_iterator_t *js_arg_iter_p)
```
- return value - the `jerry_value_t` argument that was popped.
- `js_arg_iter_p` - the JS arg iterator from which to pop.
## jerryx_arg_js_iterator_peek
**Summary**
Get the current JS argument from the iterator, without moving the iterator forward.
*Note:* Unlike `jerryx_arg_js_iterator_pop ()`, it will not change `js_arg_idx` and
`js_arg_p` value in the iterator.
**Prototype**
```c
jerry_value_t
jerryx_arg_js_iterator_peek (jerryx_arg_js_iterator_t *js_arg_iter_p)
```
- return value - the current `jerry_value_t` argument.
- `js_arg_iter_p` - the JS arg iterator from which to peek.
## jerryx_arg_js_iterator_index
**Summary**
Get the index of the current JS argument from the iterator.
**Prototype**
```c
jerry_length_t
jerryx_arg_js_iterator_index (jerryx_arg_js_iterator_t *js_arg_iter_p)
```
- return value - the index of current JS argument.
- `js_arg_iter_p` - the JS arg iterator from which to peek.