Skip to content

Commit

Permalink
WIP WIP WIP
Browse files Browse the repository at this point in the history
This will probably conflict with the clangd change. It doesn't compile
yet, but is on the way to doing so.
  • Loading branch information
djmitche committed Aug 1, 2024
1 parent 2bb05d3 commit 6ce0134
Show file tree
Hide file tree
Showing 23 changed files with 115 additions and 1,327 deletions.
2 changes: 2 additions & 0 deletions doc/devel/contrib/rust-and-c++.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Taskwarrior has historically been a C++ project, but as of taskwarrior-3.0.0, th
TaskChampion implements storage and access to "replicas" containing a user's tasks.
It defines an abstract model for this data, and also provides a simple Rust API for manipulating replicas.
It also defines a method of synchronizing replicas and provides an implementation of that method in the form of a sync server.
TODO: update this
TaskChampion provides a C interface via the `taskchampion-lib` crate, at `src/tc/lib`.

Other applications, besides Taskwarrior, can use TaskChampion to manage tasks.
Expand All @@ -17,5 +18,6 @@ Taskwarrior is just one application using the TaskChampion interface.
Taskwarrior's interface to TaskChampion has a few layers:

* A Rust library, `takschampion-lib`, that presents `extern "C"` functions for use from C++, essentially defining a C interface to TaskChampion.
TODO: update this
* C++ wrappers for the types from `taskchampion-lib`, defined in [`src/tc`](../../src/tc), ensuring memory safety (with `unique_ptr`) and adding methods corresponding to the Rust API's methods.
The wrapper types are in the C++ namespace, `tc`.
15 changes: 9 additions & 6 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
cmake_minimum_required (VERSION 3.22)
# TODO: explicit path shouldn't be required
include_directories (${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_SOURCE_DIR}/src/tc
${CMAKE_SOURCE_DIR}/src/tc/lib
${CMAKE_SOURCE_DIR}/src/commands
${CMAKE_SOURCE_DIR}/src/columns
${CMAKE_SOURCE_DIR}/src/libshared/src
${CMAKE_SOURCE_DIR}/build/src/tc/corrosion_generated/cxxbridge/taskchampion-cpp/include
${TASK_INCLUDE_DIRS})

# TODO: temporary
add_definitions(-w)

add_library (task STATIC CLI2.cpp CLI2.h
Context.cpp Context.h
DOM.cpp DOM.h
Expand Down Expand Up @@ -53,11 +56,11 @@ add_executable (calc_executable calc.cpp)
add_executable (lex_executable lex.cpp)

# Yes, 'task' (and hence libshared) is included twice, otherwise linking fails on assorted OSes.
# Similarly for `tc`.
target_link_libraries (task_executable task tc commands tc columns libshared task libshared ${TASK_LIBRARIES})
# Similarly for `taskchampion-cpp`.
target_link_libraries (task_executable task taskchampion-cpp commands taskchampion-cpp columns libshared task libshared ${TASK_LIBRARIES})
target_link_libraries (tmp_executable taskchampion-cpp ${TASK_LIBRARIES})
target_link_libraries (calc_executable task tc commands tc columns libshared task libshared ${TASK_LIBRARIES})
target_link_libraries (lex_executable task tc commands tc columns libshared task libshared ${TASK_LIBRARIES})
target_link_libraries (calc_executable task taskchampion-cpp commands taskchampion-cpp columns libshared task libshared ${TASK_LIBRARIES})
target_link_libraries (lex_executable task taskchampion-cpp commands taskchampion-cpp columns libshared task libshared ${TASK_LIBRARIES})
if (DARWIN)
# SystemConfiguration is required by Rust libraries like reqwest, to get proxy configuration.
target_link_libraries (task_executable "-framework CoreFoundation -framework Security -framework SystemConfiguration")
Expand Down
112 changes: 77 additions & 35 deletions src/TDB2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,26 +46,19 @@
#include <unordered_set>
#include <vector>

#include "tc/Server.h"
#include "tc/util.h"

bool TDB2::debug_mode = false;
static void dependency_scan(std::vector<Task>&);

////////////////////////////////////////////////////////////////////////////////
TDB2::TDB2()
: replica{tc::Replica()} // in-memory Replica
,
_working_set{} {}

////////////////////////////////////////////////////////////////////////////////
void TDB2::open_replica(const std::string& location, bool create_if_missing) {
replica = tc::Replica(location, create_if_missing);
_replica = tc::new_replica_on_disk(location, create_if_missing);
}

////////////////////////////////////////////////////////////////////////////////
// Add the new task to the replica.
void TDB2::add(Task& task) {
// TODO
/*
// Ensure the task is consistent, and provide defaults if necessary.
// bool argument to validate() is "applyDefault", to apply default values for
// properties not otherwise given.
Expand All @@ -80,7 +73,7 @@ void TDB2::add(Task& task) {
auto innertask = replica.import_task_with_uuid(uuid);
{
auto guard = replica.mutate_task(innertask);
auto guard = replica().mutate_task(innertask);
// add the task attributes
for (auto& attr : task.all()) {
Expand Down Expand Up @@ -120,6 +113,7 @@ void TDB2::add(Task& task) {
if (id.has_value()) {
task.id = id.value();
}
*/
}

////////////////////////////////////////////////////////////////////////////////
Expand All @@ -138,6 +132,8 @@ void TDB2::add(Task& task) {
// to the user. This is especially unlikely since tasks are only deleted when
// they have been unmodified for a long time.
void TDB2::modify(Task& task) {
// TODO
/*
// All locally modified tasks are timestamped, implicitly overwriting any
// changes the user or hooks tried to apply to the "modified" attribute.
task.setAsNow("modified");
Expand Down Expand Up @@ -191,18 +187,28 @@ void TDB2::modify(Task& task) {
tctask.set_value(kv.first, {});
}
}
*/
}

////////////////////////////////////////////////////////////////////////////////
void TDB2::purge(Task& task) {
// TODO
/*
auto uuid = task.get("uuid");
replica.delete_task(uuid);
*/
}

////////////////////////////////////////////////////////////////////////////////
const tc::WorkingSet& TDB2::working_set() {
rust::Box<tc::Replica>& TDB2::replica() {
assert(_replica.has_value());
return _replica.value();
}

////////////////////////////////////////////////////////////////////////////////
const rust::Box<tc::WorkingSet>& TDB2::working_set() {
if (!_working_set.has_value()) {
_working_set = std::make_optional(replica.working_set());
_working_set = std::make_optional(replica()->working_set());
}
return _working_set.value();
}
Expand All @@ -217,22 +223,27 @@ void TDB2::get_changes(std::vector<Task>& changes) {

////////////////////////////////////////////////////////////////////////////////
void TDB2::revert() {
// TODO
/*
auto undo_ops = replica.get_undo_ops();
if (undo_ops.len == 0) {
std::cout << "No operations to undo.";
return;
}
if (confirm_revert(undo_ops)) {
// Has the side-effect of freeing undo_ops.
replica.commit_undo_ops(undo_ops, NULL);
replica().commit_undo_ops(undo_ops, NULL);
} else {
replica.free_replica_ops(undo_ops);
replica().free_replica_ops(undo_ops);
}
replica.rebuild_working_set(false);
*/
}

////////////////////////////////////////////////////////////////////////////////
bool TDB2::confirm_revert(struct tc::ffi::TCReplicaOpList undo_ops) {
bool TDB2::confirm_revert(rust::Vec<tc::Operation>) {
// TODO
/*
// TODO Use show_diff rather than this basic listing of operations, though
// this might be a worthy undo.style itself.
std::cout << "The following " << undo_ops.len << " operations would be reverted:\n";
Expand All @@ -241,10 +252,10 @@ bool TDB2::confirm_revert(struct tc::ffi::TCReplicaOpList undo_ops) {
tc::ffi::TCReplicaOp op = undo_ops.items[i];
switch (op.operation_type) {
case tc::ffi::TCReplicaOpType::Create:
std::cout << "Create " << replica.get_op_uuid(op);
std::cout << "Create " << replica().get_op_uuid(op);
break;
case tc::ffi::TCReplicaOpType::Delete:
std::cout << "Delete " << replica.get_op_old_task_description(op);
std::cout << "Delete " << replica().get_op_old_task_description(op);
break;
case tc::ffi::TCReplicaOpType::Update:
std::cout << "Update " << replica.get_op_uuid(op) << "\n";
Expand All @@ -265,6 +276,8 @@ bool TDB2::confirm_revert(struct tc::ffi::TCReplicaOpList undo_ops) {
confirm(
"The undo command is not reversible. Are you sure you want to revert to the previous "
"state?");
*/
return false;
}

////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -305,33 +318,39 @@ void TDB2::gc() {

// Allowed as an override, but not recommended.
if (Context::getContext().config.getBoolean("gc")) {
replica.rebuild_working_set(true);
replica()->rebuild_working_set(true);
}

Context::getContext().time_gc_us += timer.total_us();
}

////////////////////////////////////////////////////////////////////////////////
void TDB2::expire_tasks() { replica.expire_tasks(); }
void TDB2::expire_tasks() { replica()->expire_tasks(); }

////////////////////////////////////////////////////////////////////////////////
// Latest ID is that of the last pending task.
int TDB2::latest_id() {
const tc::WorkingSet& ws = working_set();
return (int)ws.largest_index();
auto& ws = working_set();
return (int)ws->largest_index();
}

////////////////////////////////////////////////////////////////////////////////
const std::vector<Task> TDB2::all_tasks() {
// TODO
/*
auto all_tctasks = replica.all_tasks();
std::vector<Task> all;
for (auto& tctask : all_tctasks) all.push_back(Task(std::move(tctask)));
return all;
*/
return {};
}

////////////////////////////////////////////////////////////////////////////////
const std::vector<Task> TDB2::pending_tasks() {
// TODO
/*
const tc::WorkingSet& ws = working_set();
auto largest_index = ws.largest_index();
Expand All @@ -349,10 +368,14 @@ const std::vector<Task> TDB2::pending_tasks() {
dependency_scan(result);
return result;
*/
return {};
}

////////////////////////////////////////////////////////////////////////////////
const std::vector<Task> TDB2::completed_tasks() {
// TODO
/*
auto all_tctasks = replica.all_tasks();
const tc::WorkingSet& ws = working_set();
Expand All @@ -365,27 +388,34 @@ const std::vector<Task> TDB2::completed_tasks() {
}
return result;
*/
return {};
}

////////////////////////////////////////////////////////////////////////////////
// Locate task by ID, wherever it is.
bool TDB2::get(int id, Task& task) {
// TODO
/*
const tc::WorkingSet& ws = working_set();
const auto maybe_uuid = ws.by_index(id);
if (maybe_uuid) {
auto maybe_task = replica.get_task(*maybe_uuid);
auto maybe_task = replica().get_task(*maybe_uuid);
if (maybe_task) {
task = Task{std::move(*maybe_task)};
return true;
}
}
*/

return false;
}

////////////////////////////////////////////////////////////////////////////////
// Locate task by UUID, including by partial ID, wherever it is.
bool TDB2::get(const std::string& uuid, Task& task) {
// TOOD
/*
// try by raw uuid, if the length is right
if (uuid.size() == 36) {
try {
Expand All @@ -406,6 +436,7 @@ bool TDB2::get(const std::string& uuid, Task& task) {
return true;
}
}
*/

return false;
}
Expand Down Expand Up @@ -444,24 +475,25 @@ const std::vector<Task> TDB2::siblings(Task& task) {
const std::vector<Task> TDB2::children(Task& parent) {
// scan _pending_ tasks for those with `parent` equal to this task
std::vector<Task> results;
// TODO
/*
std::string this_uuid = parent.get("uuid");
const tc::WorkingSet& ws = working_set();
size_t end_idx = ws.largest_index();
auto& ws = working_set();
size_t end_idx = ws->largest_index();
for (size_t i = 0; i <= end_idx; i++) {
auto uuid_opt = ws.by_index(i);
if (!uuid_opt) {
auto uuid = ws->by_index(i);
if (uuid.is_nil()) {
continue;
}
auto uuid = uuid_opt.value();
// skip self-references
if (uuid == this_uuid) {
if (uuid.to_string() == this_uuid) {
continue;
}
auto task_opt = replica.get_task(uuid_opt.value());
auto task_opt = replica.get_task(uuid.value());
if (!task_opt) {
continue;
}
Expand All @@ -477,31 +509,41 @@ const std::vector<Task> TDB2::children(Task& parent) {
results.push_back(Task(std::move(task)));
}
}

*/
return results;
}

////////////////////////////////////////////////////////////////////////////////
std::string TDB2::uuid(int id) {
// TODO
/*
const tc::WorkingSet& ws = working_set();
return ws.by_index((size_t)id).value_or("");
*/
return "";
}

////////////////////////////////////////////////////////////////////////////////
int TDB2::id(const std::string& uuid) {
// TODO
/*
const tc::WorkingSet& ws = working_set();
return (int)ws.by_uuid(uuid).value_or(0);
*/
}

////////////////////////////////////////////////////////////////////////////////
int TDB2::num_local_changes() { return (int)replica.num_local_operations(); }
int TDB2::num_local_changes() { return (int)replica()->num_local_operations(); }

////////////////////////////////////////////////////////////////////////////////
int TDB2::num_reverts_possible() { return (int)replica.num_undo_points(); }
int TDB2::num_reverts_possible() { return (int)replica()->num_undo_points(); }

////////////////////////////////////////////////////////////////////////////////
void TDB2::sync(tc::Server server, bool avoid_snapshots) {
replica.sync(std::move(server), avoid_snapshots);
void TDB2::sync(bool avoid_snapshots) {
// TODO
/*
replica()->sync(std::move(server), avoid_snapshots);
*/
}

////////////////////////////////////////////////////////////////////////////////
Expand Down
Loading

0 comments on commit 6ce0134

Please sign in to comment.