diff --git a/integration-tests/src/bindings_tests/task.c b/integration-tests/src/bindings_tests/task.c index b75320df3..0a80bfaaf 100644 --- a/integration-tests/src/bindings_tests/task.c +++ b/integration-tests/src/bindings_tests/task.c @@ -41,7 +41,7 @@ static void test_task_free_mutable_task(void) { TCUuid uuid = tc_task_get_uuid(task); tc_task_to_mut(task, rep); - TEST_ASSERT_TRUE(tc_task_set_status(task, TC_STATUS_DELETED)); + TEST_ASSERT_EQUAL(TC_RESULT_TRUE, tc_task_set_status(task, TC_STATUS_DELETED)); TEST_ASSERT_EQUAL(TC_STATUS_DELETED, tc_task_get_status(task)); tc_task_free(task); // implicitly converts to immut @@ -68,7 +68,7 @@ static void test_task_get_set_status(void) { TEST_ASSERT_EQUAL(TC_STATUS_PENDING, tc_task_get_status(task)); tc_task_to_mut(task, rep); - TEST_ASSERT_TRUE(tc_task_set_status(task, TC_STATUS_DELETED)); + TEST_ASSERT_EQUAL(TC_RESULT_TRUE, tc_task_set_status(task, TC_STATUS_DELETED)); TEST_ASSERT_EQUAL(TC_STATUS_DELETED, tc_task_get_status(task)); // while mut tc_task_to_immut(task); TEST_ASSERT_EQUAL(TC_STATUS_DELETED, tc_task_get_status(task)); // while immut @@ -92,7 +92,7 @@ static void test_task_get_set_description(void) { TCString *desc; tc_task_to_mut(task, rep); - tc_task_set_description(task, tc_string_borrow("updated")); + TEST_ASSERT_EQUAL(TC_RESULT_TRUE, tc_task_set_description(task, tc_string_borrow("updated"))); TEST_ASSERT_TRUE(desc = tc_task_get_description(task)); TEST_ASSERT_NOT_NULL(desc); @@ -127,9 +127,9 @@ static void test_task_start_stop_is_active(void) { tc_task_to_mut(task, rep); TEST_ASSERT_FALSE(tc_task_is_active(task)); - tc_task_start(task); + TEST_ASSERT_EQUAL(TC_RESULT_TRUE, tc_task_start(task)); TEST_ASSERT_TRUE(tc_task_is_active(task)); - tc_task_stop(task); + TEST_ASSERT_EQUAL(TC_RESULT_TRUE, tc_task_stop(task)); TEST_ASSERT_FALSE(tc_task_is_active(task)); tc_task_free(task); diff --git a/lib/src/result.rs b/lib/src/result.rs index e807e4690..12f5e3e6a 100644 --- a/lib/src/result.rs +++ b/lib/src/result.rs @@ -1,10 +1,11 @@ +// TODO: make true = 1, false = 0, error = -1 /// A result combines a boolean success value with /// an error response. It is equivalent to `Result`. /// cbindgen:prefix-with-name /// cbindgen:rename-all=ScreamingSnakeCase #[repr(C)] pub enum TCResult { - True, - False, - Error, + Error = -1, + False = 0, + True = 1, } diff --git a/lib/src/task.rs b/lib/src/task.rs index 14aa82746..531f33173 100644 --- a/lib/src/task.rs +++ b/lib/src/task.rs @@ -1,4 +1,6 @@ -use crate::{replica::TCReplica, status::TCStatus, string::TCString, uuid::TCUuid}; +use crate::{ + replica::TCReplica, result::TCResult, status::TCStatus, string::TCString, uuid::TCUuid, +}; use std::ops::Deref; use taskchampion::{Task, TaskMut}; @@ -113,7 +115,8 @@ impl From for TCTask { } } -/// Utility function to get a shared reference to the underlying Task. +/// Utility function to get a shared reference to the underlying Task. All Task getters +/// are error-free, so this does not handle errors. fn wrap<'a, T, F>(task: *const TCTask, f: F) -> T where F: FnOnce(&Task) -> T, @@ -131,8 +134,9 @@ where } /// Utility function to get a mutable reference to the underlying Task. The -/// TCTask must be mutable. -fn wrap_mut<'a, T, F>(task: *mut TCTask, f: F) -> T +/// TCTask must be mutable. The inner function may use `?` syntax to return an +/// error, which will be represented with the `err_value` returned to C. +fn wrap_mut<'a, T, F>(task: *mut TCTask, f: F, err_value: T) -> T where F: FnOnce(&mut TaskMut) -> anyhow::Result, { @@ -145,8 +149,13 @@ where TCTask::Mutable(ref mut t, _) => t, TCTask::Invalid => unreachable!(), }; - // TODO: add TCTask error handling, like replica - f(task).unwrap() + match f(task) { + Ok(rv) => rv, + Err(e) => { + // TODO: add TCTask error handling, like replica + err_value + } + } } /// Convert an immutable task into a mutable task. @@ -238,31 +247,39 @@ pub extern "C" fn tc_task_is_active<'a>(task: *const TCTask) -> bool { /// Set a mutable task's status. /// -/// Returns false on error. +/// Returns TC_RESULT_TRUE on success and TC_RESULT_ERROR on failure. #[no_mangle] -pub extern "C" fn tc_task_set_status<'a>(task: *mut TCTask, status: TCStatus) -> bool { - wrap_mut(task, |task| { - task.set_status(status.into())?; - Ok(true) - }) +pub extern "C" fn tc_task_set_status<'a>(task: *mut TCTask, status: TCStatus) -> TCResult { + wrap_mut( + task, + |task| { + task.set_status(status.into())?; + Ok(TCResult::True) + }, + TCResult::Error, + ) } /// Set a mutable task's description. /// -/// Returns false on error. +/// Returns TC_RESULT_TRUE on success and TC_RESULT_ERROR on failure. #[no_mangle] pub extern "C" fn tc_task_set_description<'a>( task: *mut TCTask, description: *mut TCString, -) -> bool { +) -> TCResult { // SAFETY: // - tcstring is not NULL (promised by caller) // - caller is exclusive owner of tcstring (implicitly promised by caller) let description = unsafe { TCString::from_arg(description) }; - wrap_mut(task, |task| { - task.set_description(description.as_str()?.to_string())?; - Ok(true) - }) + wrap_mut( + task, + |task| { + task.set_description(description.as_str()?.to_string())?; + Ok(TCResult::True) + }, + TCResult::Error, + ) } // TODO: tc_task_set_description @@ -272,24 +289,32 @@ pub extern "C" fn tc_task_set_description<'a>( /// Start a task. /// -/// TODO: error +/// Returns TC_RESULT_TRUE on success and TC_RESULT_ERROR on failure. #[no_mangle] -pub extern "C" fn tc_task_start<'a>(task: *mut TCTask) { - wrap_mut(task, |task| { - task.start()?; - Ok(()) - }) +pub extern "C" fn tc_task_start<'a>(task: *mut TCTask) -> TCResult { + wrap_mut( + task, + |task| { + task.start()?; + Ok(TCResult::True) + }, + TCResult::Error, + ) } /// Stop a task. /// -/// TODO: error +/// Returns TC_RESULT_TRUE on success and TC_RESULT_ERROR on failure. #[no_mangle] -pub extern "C" fn tc_task_stop<'a>(task: *mut TCTask) { - wrap_mut(task, |task| { - task.stop()?; - Ok(()) - }) +pub extern "C" fn tc_task_stop<'a>(task: *mut TCTask) -> TCResult { + wrap_mut( + task, + |task| { + task.stop()?; + Ok(TCResult::True) + }, + TCResult::Error, + ) } // TODO: tc_task_done diff --git a/lib/taskchampion.h b/lib/taskchampion.h index 65de06667..8330a1dbe 100644 --- a/lib/taskchampion.h +++ b/lib/taskchampion.h @@ -11,9 +11,9 @@ * an error response. It is equivalent to `Result`. */ typedef enum TCResult { - TC_RESULT_TRUE, - TC_RESULT_FALSE, - TC_RESULT_ERROR, + TC_RESULT_ERROR = -1, + TC_RESULT_FALSE = 0, + TC_RESULT_TRUE = 1, } TCResult; /** @@ -258,30 +258,30 @@ bool tc_task_is_active(const struct TCTask *task); /** * Set a mutable task's status. * - * Returns false on error. + * Returns TC_RESULT_TRUE on success and TC_RESULT_ERROR on failure. */ -bool tc_task_set_status(struct TCTask *task, enum TCStatus status); +enum TCResult tc_task_set_status(struct TCTask *task, enum TCStatus status); /** * Set a mutable task's description. * - * Returns false on error. + * Returns TC_RESULT_TRUE on success and TC_RESULT_ERROR on failure. */ -bool tc_task_set_description(struct TCTask *task, struct TCString *description); +enum TCResult tc_task_set_description(struct TCTask *task, struct TCString *description); /** * Start a task. * - * TODO: error + * Returns TC_RESULT_TRUE on success and TC_RESULT_ERROR on failure. */ -void tc_task_start(struct TCTask *task); +enum TCResult tc_task_start(struct TCTask *task); /** * Stop a task. * - * TODO: error + * Returns TC_RESULT_TRUE on success and TC_RESULT_ERROR on failure. */ -void tc_task_stop(struct TCTask *task); +enum TCResult tc_task_stop(struct TCTask *task); /** * Free a task. The given task must not be NULL. The task must not be used after this function