Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Module type #365

Merged
merged 7 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# v1.5.2

* Restrict future arguments for `then()` or `else()` to objects without an Id.
* Module as type, no longer the workaround of exposing modules as futures.
* Added the `is_module()` function.
* Support ThingsDB code in exposed module functions.

# v1.5.1

* Added support for building on MacOS.
Expand Down
1 change: 1 addition & 0 deletions inc/doc.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#define DOC_IS_INF DOC_SEE("collection-api/is/is_inf")
#define DOC_IS_INT DOC_SEE("collection-api/is/is_int")
#define DOC_IS_LIST DOC_SEE("collection-api/is/is_list")
#define DOC_IS_MODULE DOC_SEE("collection-api/is/is_module")
#define DOC_IS_MPDATA DOC_SEE("collection-api/is/is_mpdata")
#define DOC_IS_NAN DOC_SEE("collection-api/is/is_nan")
#define DOC_IS_NIL DOC_SEE("collection-api/is/is_nil")
Expand Down
9 changes: 5 additions & 4 deletions inc/ti/fn/fn.h
Original file line number Diff line number Diff line change
Expand Up @@ -649,12 +649,13 @@ static int fn_call_f_try_n(
cleri_node_t * nd,
ex_t * e)
{
ti_future_t * future = (ti_future_t *) query->rval;
ti_module_t * module = future->module;
ti_module_t * module = (ti_module_t *) query->rval;
ti_mod_expose_t * expose = ti_mod_expose_by_strn(module, name, n);

if (expose)
return ti_mod_expose_call(expose, query, nd, e);
return expose->closure
? ti_mod_closure_call(expose, query, nd, e)
: ti_mod_expose_call(expose, query, nd, e);

ex_set(e, EX_LOOKUP_ERROR,
"module `%s` has no function `%.*s`",
Expand Down Expand Up @@ -708,7 +709,7 @@ static int fn_call_try_n(
if (ti_val_is_wrap(query->rval))
return fn_call_w_try_n(name, n, query, nd, e);

if (ti_val_is_future(query->rval))
if (ti_val_is_module(query->rval))
return fn_call_f_try_n(name, n, query, nd, e);

if (ti_val_is_member(query->rval))
Expand Down
1 change: 1 addition & 0 deletions inc/ti/fn/fnclosure.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ static int do__f_closure_new(ti_query_t * query, cleri_node_t * nd, ex_t * e)
case TI_VAL_MEMBER:
case TI_VAL_MPDATA:
case TI_VAL_FUTURE:
case TI_VAL_MODULE:
ex_set(e, EX_TYPE_ERROR,
"cannot convert type `%s` to `"TI_VAL_CLOSURE_S"`",
ti_val_str(query->rval));
Expand Down
18 changes: 18 additions & 0 deletions inc/ti/fn/fnismodule.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include <ti/fn/fn.h>

static int do__f_is_module(ti_query_t * query, cleri_node_t * nd, ex_t * e)
{
const int nargs = fn_get_nargs(nd);
_Bool is_module;

if (fn_nargs("is_module", DOC_IS_MODULE, 1, nargs, e) ||
ti_do_statement(query, nd->children, e))
return e->nr;

is_module = ti_val_is_module(query->rval);

ti_val_unsafe_drop(query->rval);
query->rval = (ti_val_t *) ti_vbool_get(is_module);

return 0;
}
1 change: 1 addition & 0 deletions inc/ti/fn/fnsearch.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ static int do__search_thing(
}
case TI_VAL_TEMPLATE:
case TI_VAL_FUTURE:
case TI_VAL_MODULE:
return 0;
}
assert(0);
Expand Down
3 changes: 2 additions & 1 deletion inc/ti/forloop.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ typedef int (*ti_forloop_t) (
cleri_node_t *,
ex_t *);

static const ti_forloop_t ti_forloop_callbacks[21] = {
static const ti_forloop_t ti_forloop_callbacks[22] = {
ti_forloop_no_iter, /* TI_VAL_NIL */
ti_forloop_no_iter, /* TI_VAL_INT */
ti_forloop_no_iter, /* TI_VAL_FLOAT */
Expand All @@ -60,6 +60,7 @@ static const ti_forloop_t ti_forloop_callbacks[21] = {
ti_forloop_no_iter, /* TI_VAL_MPDATA */
ti_forloop_no_iter, /* TI_VAL_CLOSURE */
ti_forloop_no_iter, /* TI_VAL_FUTURE */
ti_forloop_no_iter, /* TI_VAL_MODULE */
ti_forloop_no_iter, /* TI_VAL_TEMPLATE */
};

Expand Down
5 changes: 5 additions & 0 deletions inc/ti/mod/expose.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@

ti_mod_expose_t * ti_mod_expose_create(void);
void ti_mod_expose_destroy(ti_mod_expose_t * expose);
int ti_mod_closure_call(
ti_mod_expose_t * expose,
ti_query_t * query,
cleri_node_t * nd,
ex_t * e);
int ti_mod_expose_call(
ti_mod_expose_t * expose,
ti_query_t * query,
Expand Down
11 changes: 7 additions & 4 deletions inc/ti/mod/expose.t.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@
typedef struct ti_mod_expose_s ti_mod_expose_t;

#include <util/vec.h>
#include <ti/closure.t.h>

struct ti_mod_expose_s
{
uint8_t * deep; /* NULL or 0..127 */
uint8_t * deep; /* NULL or 0..127 */
_Bool * load; /* NULL or true/false */
char * doc; /* NULL or string */
vec_t * argmap; /* ti_item_t */
vec_t * defaults; /* ti_item_t */
char * doc; /* NULL or string */
vec_t * argmap; /* ti_item_t */
vec_t * defaults; /* ti_item_t */
ti_closure_t * closure; /* closure */
ti_raw_t * def; /* closure definition */
};

#endif /* TI_MOD_EXPOSE_T_H_ */
4 changes: 4 additions & 0 deletions inc/ti/module.t.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ typedef union
struct ti_module_s
{
uint32_t ref;
uint8_t tp;
uint8_t _pad0;
uint16_t _pad1;

int status; /* 0 = success, >0 = enum, <0 = uv error */
int flags;
uint16_t restarts; /* keep the number of times this module has been
Expand Down
1 change: 1 addition & 0 deletions inc/ti/thing.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ int ti_thing_get_by_raw_e(
ti_raw_t * r,
ex_t * e);
int ti_thing_gen_id(ti_thing_t * thing);
_Bool ti_thing_has_id(ti_thing_t * thing);
int ti_thing__to_client_pk(
ti_thing_t * thing,
ti_vp_t * vp,
Expand Down
1 change: 1 addition & 0 deletions inc/ti/val.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ int ti_val_convert_to_set(ti_val_t ** val, ex_t * e);
_Bool ti_val_as_bool(ti_val_t * val);
size_t ti_val_get_len(ti_val_t * val);
int ti_val_gen_ids(ti_val_t * val);
_Bool ti_val_has_ids(ti_val_t * val);
size_t ti_val_alloc_size(ti_val_t * val);
ti_val_t * ti_val_strv(ti_val_t * val);
int ti_val_copy(ti_val_t ** val, ti_thing_t * parent, void * key, uint8_t deep);
Expand Down
38 changes: 36 additions & 2 deletions inc/ti/val.inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <ti/future.h>
#include <ti/member.h>
#include <ti/member.inline.h>
#include <ti/module.t.h>
#include <ti/name.h>
#include <ti/nil.h>
#include <ti/nil.h>
Expand Down Expand Up @@ -117,7 +118,10 @@ static inline const char * val__future_type_str(ti_val_t * UNUSED(val))
{
return TI_VAL_FUTURE_S;
}

static inline const char * val__module_type_str(ti_val_t * UNUSED(val))
{
return TI_VAL_MODULE_S;
}
static inline int val__nil_to_client_pk(ti_val_t * UNUSED(v), ti_vp_t * vp, int UNUSED(d), int UNUSED(f))
{
return msgpack_pack_nil(&vp->pk);
Expand Down Expand Up @@ -183,6 +187,7 @@ static inline int val__closure_to_client_pk(ti_val_t * val, ti_vp_t * vp, int UN
return ti_closure_to_client_pk((ti_closure_t *) val, &vp->pk);
}
static inline int val__future_to_client_pk(ti_future_t * future, ti_vp_t * vp, int deep, int flags);
static inline int val__module_to_client_pk(ti_module_t * UNUSED(module), ti_vp_t * vp, int UNUSED(deep), int UNUSED(flags));
static inline int val__member_to_client_pk(ti_member_t * member, ti_vp_t * vp, int deep, int flags);
static inline int val__member_to_store_pk(ti_member_t * member, msgpack_packer * pk);
static inline int val__varr_to_client_pk(ti_varr_t * varr, ti_vp_t * vp, int deep, int flags);
Expand Down Expand Up @@ -229,6 +234,7 @@ static inline int val__set_to_arr(ti_val_t ** v, ti_varr_t * varr, ex_t * e)

static inline int val__member_to_arr(ti_val_t ** v, ti_varr_t * varr, ex_t * e);
static inline int val__future_to_arr(ti_val_t ** v, ti_varr_t * UNUSED(varr), ex_t * UNUSED(e));
static inline int val__module_to_arr(ti_val_t ** v, ti_varr_t * UNUSED(varr), ex_t * UNUSED(e));

static inline int val__closure_to_arr(ti_val_t ** v, ti_varr_t * UNUSED(varr), ex_t * e)
{
Expand All @@ -254,7 +260,7 @@ typedef struct
} ti_val_type_t;


static ti_val_type_t ti_val_type_props[21] = {
static ti_val_type_t ti_val_type_props[22] = {
/* TI_VAL_NIL */
{
.destroy = (ti_val_destroy_cb) free,
Expand Down Expand Up @@ -454,6 +460,15 @@ static ti_val_type_t ti_val_type_props[21] = {
.get_type_str = val__future_type_str,
.allowed_as_vtask_arg = false,
},
/* TI_VAL_MODULE */
{
.destroy = (ti_val_destroy_cb) ti_module_destroy,
.to_str = val__no_to_str,
.to_arr_cb = val__module_to_arr,
.to_client_pk = (ti_val_to_client_pk_cb) val__module_to_client_pk,
.get_type_str = val__module_type_str,
.allowed_as_vtask_arg = false,
},
/* TI_VAL_TEMPLATE */
{
.destroy = (ti_val_destroy_cb) ti_template_destroy,
Expand Down Expand Up @@ -751,6 +766,11 @@ static inline _Bool ti_val_is_future(ti_val_t * val)
return val->tp == TI_VAL_FUTURE;
}

static inline _Bool ti_val_is_module(ti_val_t * val)
{
return val->tp == TI_VAL_MODULE;
}

static inline _Bool ti_val_overflow_cast(double d)
{
return !(d >= -VAL__CAST_MAX && d < VAL__CAST_MAX);
Expand Down Expand Up @@ -1017,6 +1037,7 @@ static inline void ti_val_attach(
case TI_VAL_MEMBER:
case TI_VAL_CLOSURE:
case TI_VAL_FUTURE:
case TI_VAL_MODULE:
return;
case TI_VAL_ARR:
((ti_varr_t *) val)->parent = parent;
Expand Down Expand Up @@ -1088,6 +1109,7 @@ static inline int ti_val_make_assignable(
case TI_VAL_CLOSURE:
return ti_closure_unbound((ti_closure_t *) *val, e);
case TI_VAL_FUTURE:
case TI_VAL_MODULE:
ti_val_unsafe_drop(*val);
*val = (ti_val_t *) ti_nil_get();
return 0;
Expand Down Expand Up @@ -1119,6 +1141,11 @@ static inline int val__future_to_client_pk(ti_future_t * future, ti_vp_t * vp, i
: msgpack_pack_nil(&vp->pk);
}

static inline int val__module_to_client_pk(ti_module_t * UNUSED(module), ti_vp_t * vp, int UNUSED(deep), int UNUSED(flags))
{
return msgpack_pack_nil(&vp->pk);
}

static inline int val__member_to_client_pk(ti_member_t * member, ti_vp_t * vp, int deep, int flags)
{
return ti_val(member->val)->to_client_pk(member->val, vp, deep, flags);
Expand Down Expand Up @@ -1289,6 +1316,13 @@ static inline int val__future_to_arr(ti_val_t ** v, ti_varr_t * UNUSED(varr), ex
return 0;
}

static inline int val__module_to_arr(ti_val_t ** v, ti_varr_t * UNUSED(varr), ex_t * UNUSED(e))
{
ti_val_unsafe_drop(*v);
*v = (ti_val_t *) ti_nil_get();
return 0;
}

/*
* does not increment `*v` reference counter but the value might change to
* a (new) tuple pointer.
Expand Down
2 changes: 2 additions & 0 deletions inc/ti/val.t.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#define TI_VAL_DATETIME_S "datetime"
#define TI_VAL_TIMEVAL_S "timeval"
#define TI_VAL_FUTURE_S "future"
#define TI_VAL_MODULE_S "module"
#define TI_VAL_TASK_S "task"

#define TI_KIND_S_INSTANCE "." /* Internally, New typed thing */
Expand Down Expand Up @@ -66,6 +67,7 @@ typedef enum
TI_VAL_MPDATA, /* msgpack data */
TI_VAL_CLOSURE,
TI_VAL_FUTURE, /* future */
TI_VAL_MODULE, /* module */
TI_VAL_TEMPLATE, /* template to generate TI_VAL_STR
note that a template is never stored like a value,
rather it may build from either a query or a stored
Expand Down
4 changes: 2 additions & 2 deletions inc/ti/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

#define TI_VERSION_MAJOR 1
#define TI_VERSION_MINOR 5
#define TI_VERSION_PATCH 1
#define TI_VERSION_PATCH 2

/* The syntax version is used to test compatibility with functions
* using the `ti_nodes_check_syntax()` function */
Expand All @@ -25,7 +25,7 @@
* "-rc0"
* ""
*/
#define TI_VERSION_PRE_RELEASE ""
#define TI_VERSION_PRE_RELEASE "-alpha1"

#define TI_MAINTAINER \
"Jeroen van der Heijden <[email protected]>"
Expand Down
4 changes: 2 additions & 2 deletions itest/test_advanced.py
Original file line number Diff line number Diff line change
Expand Up @@ -1822,7 +1822,7 @@ async def test_future_to_type(self, client):
with self.assertRaisesRegex(
TypeError,
r'mismatch in type `A`; property `x` allows `any` type '
r"with the exception of the `future` type"):
r"with the exception of the `future` and `module` type"):
await client.query("""//ti
A{
x: future(||nil)
Expand Down Expand Up @@ -2504,7 +2504,7 @@ async def test_future_name(self, client):

with self.assertRaisesRegex(
LookupError,
r'module `async` has no function `id`'):
r'type `future` has no function `id`'):
await client.query(r"""//ti
user = add_user(); user.id();
""")
Expand Down
8 changes: 8 additions & 0 deletions itest/test_collection_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2137,6 +2137,14 @@ async def test_is_future(self, client):
self.assertFalse(await client.query('is_future( 42 );'))
self.assertFalse(await client.query('is_future( nil );'))

async def test_is_module(self, client):
with self.assertRaisesRegex(
NumArgumentsError,
'function `is_module` takes 1 argument but 0 were given'):
await client.query('is_module();')

self.assertFalse(await client.query('is_module(future(nil));'))

async def test_is_inf(self, client):
with self.assertRaisesRegex(
NumArgumentsError,
Expand Down
11 changes: 11 additions & 0 deletions itest/test_future.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,5 +245,16 @@ async def test_future_arguments(self, client):
future(|a, b| a + b);
""")

async def test_no_ids(self, client):
with self.assertRaisesRegex(
OperationError,
'context does not allow arguments which are stored by Id'):
await client.query("""//ti
.t = t = {name: 'iris'};
future(|t| {
t.name = 'Iris';
});
""")

if __name__ == '__main__':
run_test(TestFuture())
Loading