ffi for tc_task_get/set_value

This commit is contained in:
Dustin J. Mitchell 2022-08-08 00:42:07 +00:00
parent 7cecac3328
commit 4fdb46fd47
3 changed files with 117 additions and 4 deletions

View file

@ -111,6 +111,54 @@ static void test_task_get_set_description(void) {
tc_replica_free(rep);
}
// updating arbitrary attributes on a task works
static void test_task_get_set_attribute(void) {
TCReplica *rep = tc_replica_new_in_memory();
TEST_ASSERT_NULL(tc_replica_error(rep).ptr);
TCTask *task = tc_replica_new_task(
rep,
TC_STATUS_PENDING,
tc_string_borrow("my task"));
TEST_ASSERT_NOT_NULL(task);
TCString foo;
foo = tc_task_get_value(task, tc_string_borrow("foo"));
TEST_ASSERT_NULL(foo.ptr);
tc_task_to_mut(task, rep);
TEST_ASSERT_EQUAL(TC_RESULT_OK, tc_task_set_value(task,
tc_string_borrow("foo"),
tc_string_borrow("updated")));
foo = tc_task_get_value(task, tc_string_borrow("foo"));
TEST_ASSERT_NOT_NULL(foo.ptr);
TEST_ASSERT_EQUAL_STRING("updated", tc_string_content(&foo));
tc_string_free(&foo);
tc_task_to_immut(task);
foo = tc_task_get_value(task, tc_string_borrow("foo"));
TEST_ASSERT_NOT_NULL(foo.ptr);
TEST_ASSERT_EQUAL_STRING("updated", tc_string_content(&foo));
tc_string_free(&foo);
TCString null = { .ptr = NULL };
tc_task_to_mut(task, rep);
TEST_ASSERT_EQUAL(TC_RESULT_OK, tc_task_set_value(task,
tc_string_borrow("foo"),
null));
foo = tc_task_get_value(task, tc_string_borrow("foo"));
TEST_ASSERT_NULL(foo.ptr);
tc_task_free(task);
tc_replica_free(rep);
}
// updating entry on a task works
static void test_task_get_set_entry(void) {
TCReplica *rep = tc_replica_new_in_memory();
@ -652,6 +700,7 @@ int task_tests(void) {
RUN_TEST(test_task_free_mutable_task);
RUN_TEST(test_task_get_set_status);
RUN_TEST(test_task_get_set_description);
RUN_TEST(test_task_get_set_attribute);
RUN_TEST(test_task_get_set_entry);
RUN_TEST(test_task_get_set_modified);
RUN_TEST(test_task_get_set_wait_and_is_waiting);

View file

@ -294,8 +294,7 @@ pub unsafe extern "C" fn tc_task_get_taskmap(task: *mut TCTask) -> TCKVList {
})
}
/// Get a task's description, or NULL if the task cannot be represented as a C string (e.g., if it
/// contains embedded NUL characters).
/// Get a task's description.
#[no_mangle]
pub unsafe extern "C" fn tc_task_get_description(task: *mut TCTask) -> TCString {
wrap(task, |task| {
@ -306,6 +305,27 @@ pub unsafe extern "C" fn tc_task_get_description(task: *mut TCTask) -> TCString
})
}
/// Get a task property's value, or NULL if the task has no such property, (including if the
/// property name is not valid utf-8).
#[no_mangle]
pub unsafe extern "C" fn tc_task_get_value(task: *mut TCTask, property: TCString) -> TCString {
// SAFETY:
// - property is valid (promised by caller)
// - caller will not use property after this call (convention)
let mut property = unsafe { TCString::val_from_arg(property) };
wrap(task, |task| {
if let Ok(property) = property.as_str() {
let value = task.get_value(property);
if let Some(value) = value {
// SAFETY:
// - caller promises to free this string
return unsafe { TCString::return_val(value.into()) };
}
}
TCString::default() // null value
})
}
/// Get the entry timestamp for a task (when it was created), or 0 if not set.
#[no_mangle]
pub unsafe extern "C" fn tc_task_get_entry(task: *mut TCTask) -> libc::time_t {
@ -507,6 +527,40 @@ pub unsafe extern "C" fn tc_task_set_status(task: *mut TCTask, status: TCStatus)
)
}
/// Set a mutable task's property value by name. If value.ptr is NULL, the property is removed.
#[no_mangle]
pub unsafe extern "C" fn tc_task_set_value(
task: *mut TCTask,
property: TCString,
value: TCString,
) -> TCResult {
// SAFETY:
// - property is valid (promised by caller)
// - caller will not use property after this call (convention)
let mut property = unsafe { TCString::val_from_arg(property) };
let value = if value.is_null() {
None
} else {
// SAFETY:
// - value is valid (promised by caller, after NULL check)
// - caller will not use value after this call (convention)
Some(unsafe { TCString::val_from_arg(value) })
};
wrap_mut(
task,
|task| {
let value_str = if let Some(mut v) = value {
Some(v.as_str()?.to_string())
} else {
None
};
task.set_value(property.as_str()?.to_string(), value_str)?;
Ok(TCResult::Ok)
},
TCResult::Error,
)
}
/// Set a mutable task's description.
#[no_mangle]
pub unsafe extern "C" fn tc_task_set_description(

View file

@ -751,11 +751,16 @@ enum TCStatus tc_task_get_status(struct TCTask *task);
struct TCKVList tc_task_get_taskmap(struct TCTask *task);
/**
* Get a task's description, or NULL if the task cannot be represented as a C string (e.g., if it
* contains embedded NUL characters).
* Get a task's description.
*/
struct TCString tc_task_get_description(struct TCTask *task);
/**
* Get a task property's value, or NULL if the task has no such property, (including if the
* property name is not valid utf-8).
*/
struct TCString tc_task_get_value(struct TCTask *task, struct TCString property);
/**
* Get the entry timestamp for a task (when it was created), or 0 if not set.
*/
@ -837,6 +842,11 @@ struct TCUdaList tc_task_get_legacy_udas(struct TCTask *task);
*/
TCResult tc_task_set_status(struct TCTask *task, enum TCStatus status);
/**
* Set a mutable task's property value by name. If value.ptr is NULL, the property is removed.
*/
TCResult tc_task_set_value(struct TCTask *task, struct TCString property, struct TCString value);
/**
* Set a mutable task's description.
*/