diff --git a/config.toml b/.cargo/config.toml similarity index 100% rename from config.toml rename to .cargo/config.toml diff --git a/lib/src/replica.rs b/lib/src/replica.rs index e6956f431..6dde71008 100644 --- a/lib/src/replica.rs +++ b/lib/src/replica.rs @@ -501,6 +501,30 @@ pub unsafe extern "C" fn tc_replica_import_task_with_uuid( ) } +#[ffizz_header::item] +#[ffizz(order = 902)] +/// Delete a task. The task must exist. Note that this is different from setting status to +/// Deleted; this is the final purge of the task. +/// +/// ```c +/// EXTERN_C struct TCTask *tc_replica_delete_task(struct TCReplica *rep, struct TCUuid tcuuid); +/// ``` +#[no_mangle] +pub unsafe extern "C" fn tc_replica_delete_task(rep: *mut TCReplica, tcuuid: TCUuid) -> TCResult { + wrap( + rep, + |rep| { + // SAFETY: + // - tcuuid is a valid TCUuid (all bytes are valid) + // - tcuuid is Copy so ownership doesn't matter + let uuid = unsafe { TCUuid::val_from_arg(tcuuid) }; + rep.delete_task(uuid)?; + Ok(TCResult::Ok) + }, + TCResult::Error, + ) +} + #[ffizz_header::item] #[ffizz(order = 902)] /// Synchronize this replica with a server. diff --git a/lib/taskchampion.h b/lib/taskchampion.h index 2f3237ab2..06586456c 100644 --- a/lib/taskchampion.h +++ b/lib/taskchampion.h @@ -547,6 +547,10 @@ EXTERN_C struct TCTaskList tc_replica_all_tasks(struct TCReplica *rep); // there are no operations that can be done. EXTERN_C TCResult tc_replica_commit_undo_ops(struct TCReplica *rep, TCReplicaOpList tc_undo_ops, int32_t *undone_out); +// Delete a task. The task must exist. Note that this is different from setting status to +// Deleted; this is the final purge of the task. +EXTERN_C struct TCTask *tc_replica_delete_task(struct TCReplica *rep, struct TCUuid tcuuid); + // Get the latest error for a replica, or a string with NULL ptr if no error exists. Subsequent // calls to this function will return NULL. The rep pointer must not be NULL. The caller must // free the returned string. diff --git a/taskchampion/src/replica.rs b/taskchampion/src/replica.rs index 632133225..df27d02c0 100644 --- a/taskchampion/src/replica.rs +++ b/taskchampion/src/replica.rs @@ -208,9 +208,13 @@ impl Replica { } /// Delete a task. The task must exist. Note that this is different from setting status to - /// Deleted; this is the final purge of the task. This is not a public method as deletion - /// should only occur through expiration. - fn delete_task(&mut self, uuid: Uuid) -> Result<()> { + /// Deleted; this is the final purge of the task. + /// + /// Deletion may interact poorly with modifications to the same task on other replicas. For + /// example, if a task is deleted on replica 1 and its description modified on replica 1, then + /// after both replicas have fully synced, the resulting task will only have a `description` + /// property. + pub fn delete_task(&mut self, uuid: Uuid) -> Result<()> { self.add_undo_point(false)?; self.taskdb.apply(SyncOp::Delete { uuid })?; trace!("task {} deleted", uuid);