Add a C++ wrapper around TC FFI

This uses CMake to build a simple Rust library (in `src/tc/rust`) that
just re-exports everything from the `taskchampion-lib` crate.

The C++ wrappers then wrap this into C++ objects with proper lifecycle
maintenance, in the `tc` namespace.

The C++ wrappers are incomplete, and missing methods are tagged with
"TODO".  These will be added as needed.
This commit is contained in:
Dustin J. Mitchell 2022-03-12 22:07:42 +00:00 committed by Tomas Babej
parent fd03169314
commit 8c30400af3
32 changed files with 1760 additions and 30 deletions

1
.gitignore vendored
View file

@ -5,6 +5,7 @@ src/task
src/taskd
src/libtask.a
src/commands/libcommands.a
src/tc/libtc.a
src/columns/libcolumns.a
*~
.*.swp

6
.gitmodules vendored
View file

@ -1,3 +1,9 @@
[submodule "src/libshared"]
path = src/libshared
url = https://github.com/GothenburgBitFactory/libshared.git
[submodule "cmake/CMakeRust"]
path = cmake/CMakeRust
url = https://github.com/Devolutions/CMakeRust
[submodule "src/taskchampion"]
path = src/taskchampion
url = https://github.com/taskchampion/taskchampion

View file

@ -1,6 +1,8 @@
cmake_minimum_required (VERSION 3.0)
set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake" "${CMAKE_SOURCE_DIR}/cmake/CMakeRust/cmake")
enable_language (Rust)
include (CMakeCargo)
include (CheckFunctionExists)
include (CheckStructHasMember)
@ -66,6 +68,9 @@ SET (TASK_DOCDIR share/doc/task CACHE STRING "Installation directory for doc fi
SET (TASK_RCDIR "${TASK_DOCDIR}/rc" CACHE STRING "Installation directory for configuration files")
SET (TASK_BINDIR bin CACHE STRING "Installation directory for the binary")
# rust libs require these
set (TASK_LIBRARIES dl pthread)
if (USE_GNUTLS)
message ("-- Looking for GnuTLS")
find_package (GnuTLS)
@ -150,6 +155,8 @@ configure_file (
add_subdirectory (src)
add_subdirectory (src/commands)
add_subdirectory (src/tc)
add_subdirectory (src/tc/rust)
add_subdirectory (src/columns)
add_subdirectory (doc)
add_subdirectory (scripts)
@ -185,7 +192,7 @@ set (CPACK_SOURCE_IGNORE_FILES "CMakeCache" "CMakeFiles" "CPackConfig" "CPackSo
"_CPack_Packages" "cmake_install" "install_manifest" "Makefile$"
"test" "package-config" "misc/*" "src/task$" "src/calc$" "performance"
"src/libtask.a" "src/columns/libcolumns.a" "src/commands/libcommands.a"
"swp$" "src/lex$" "task-.*.tar.gz" "commit.h" "cmake.h$" "\\\\.gitmodules"
"src/libshared/\\\\.git" ".github/" ".*\\\\.gitignore$"
"src/tc/libtc.a" "swp$" "src/lex$" "task-.*.tar.gz" "commit.h" "cmake.h$"
"\\\\.gitmodules" "src/libshared/\\\\.git" ".github/" ".*\\\\.gitignore$"
"src/liblibshared.a" "docker-compose.yml" "\\\\.git/")
include (CPack)

View file

@ -7,3 +7,6 @@ members = [
"rust/integration-tests",
"rust/xtask",
]
# src/tc/rust is just part of the TW build and not a public crate
exclude = [ "src/tc/rust" ]

View file

@ -112,9 +112,10 @@ Then build:
Your contributions are especially welcome.
Whether it comes in the form of code patches, ideas, discussion, bug reports, encouragement or criticism, your input is needed.
Visit [Github](https://github.com/GothenburgBitFactory/taskwarrior) and participate in the future of Taskwarrior.
See further development documentation in [`docs/`](./docs).
## Sponsoring
[![GitHub Sponsors](https://img.shields.io/github/sponsors/GothenburgBitFactory?color=green)](https://github.com/sponsors/GothenburgBitFactory/)

1
cmake/CMakeRust Submodule

@ -0,0 +1 @@
Subproject commit 9a4a7a19b41e58deef5efc9a7ba53a69bc40449b

View file

@ -11,7 +11,7 @@ Taskwarrior and Taskserver use the same branching model.
## Git Branching
Git allows arbitrary and low-cost branching, which means that any branching model can be used.
A new Git repository has one branch, the default branch, named `master`, but even this is not required.
A new Git repository has one branch, the default branch, named `stable`, but even this is not required.
[![master](master.png)](master.png)

View file

@ -0,0 +1,29 @@
# Rust and C++
Taskwarrior has historically been a C++ project, but as part of an [ongoing effort to replace its storage backend](https://github.com/GothenburgBitFactory/taskwarrior/issues/2770) it now includes a Rust library called TaskChampion.
To develop Taskwarrior, you will need both a [C++ compiler and tools](./development.md), and a [Rust toolchain](https://www.rust-lang.org/tools/install).
However, most tasks will only require you to be familiar with one of the two languages.
## TaskChampion
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.
TaskChampion provides a C interface via the `taskchampion-lib` crate.
Other applications, besides Taskwarrior, can use TaskChampion to manage tasks.
Applications written in Rust can use the `taskchampion` crate, while those in other languages may use the `taskchampion-lib` crate.
Taskwarrior is just one application using the TaskChampion interface.
You can build Taskchampion locally by simply running `cargo build` in the root of this repository.
The implementation, including more documentation, is in the [`rust`](../../rust) subdirectory.
## Taskwarrior's use of TaskChampion
Taskwarrior's interface to TaskChampion has a few laters:
* The skeletal Rust crate in [`src/tc/rust`](../../src/tc/rust) brings the symbols from `taskchampion-lib` under CMake's management.
The corresponding header file is included from [`rust/lib`](../../rust/lib).
All of these symbols are placed in the C++ namespace, `tc::ffi`.
* C++ wrappers for the types from `taskchampion-lib` are 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`.

View file

@ -7,12 +7,13 @@ For all other documenation, see https://taskwarrior.org.
## Contributing to Taskwarrior
* [How to become an Open Source Contributor](./contrib/first_time)
* [Contributing to Taskwarrior](./contrib/contribute)
* [Developing Taskwarrior](./contrib/development)
* [Building Taskwarrior](./contrib/build)
* [Coding Style](./contrib/coding_style)
* [Branching Model](./contrib/branching)
* [How to become an Open Source Contributor](./contrib/first_time.md)
* [Contributing to Taskwarrior](./contrib/contribute.md)
* [Developing Taskwarrior](./contrib/development.md)
* [Building Taskwarrior](./contrib/build.md)
* [Coding Style](./contrib/coding_style.md)
* [Branching Model](./contrib/branching.md)
* [Rust and C++](./contrib/rust-and-c++.md)
## RFC's
@ -21,14 +22,14 @@ This is where design documents (RFCs) are kept.
Although these documents are less formal than [IETF RFCs](https://www.ietf.org/rfc) they serve a similar purpose.
These documents apply only to the Taskwarrior family of products, and are placed here to invite comment before designs finalize.
- [General Plans](./rfcs/plans)
- [Rules System](./rfcs/rules)
- [Full DOM Support ](./rfcs/dom)
- [Work Week Support](./rfcs/workweek)
- [Recurrence](./rfcs/recurrence)
- [Taskwarrior JSON Format](./rfcs/task)
- [CLI Updates ](./rfcs/cli)
- [Taskserver Sync Protocol](./rfcs/protocol)
- [Taskserver Message Format](./rfcs/request)
- [Taskserver Sync Algorithm](./rfcs/sync)
- [Taskserver Client](./rfcs/client)
- [General Plans](./rfcs/plans.md)
- [Rules System](./rfcs/rules.md)
- [Full DOM Support ](./rfcs/dom.md)
- [Work Week Support](./rfcs/workweek.md)
- [Recurrence](./rfcs/recurrence.md)
- [Taskwarrior JSON Format](./rfcs/task.md)
- [CLI Updates ](./rfcs/cli.md)
- [Taskserver Sync Protocol](./rfcs/protocol.md)
- [Taskserver Message Format](./rfcs/request.md)
- [Taskserver Sync Algorithm](./rfcs/sync.md)
- [Taskserver Client](./rfcs/client.md)

View file

@ -3,9 +3,9 @@ name = "taskchampion-lib"
version = "0.1.0"
edition = "2018"
[lib]
name = "taskchampionlib"
crate-type = ["staticlib", "cdylib", "rlib"]
#[lib]
#name = "taskchampionlib"
#crate-type = ["staticlib", "cdylib", "rlib"]
[dependencies]
libc = "0.2.126"

View file

@ -1,9 +1,11 @@
cmake_minimum_required (VERSION 3.0)
include_directories (${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_SOURCE_DIR}/src/tc
${CMAKE_SOURCE_DIR}/src/commands
${CMAKE_SOURCE_DIR}/src/columns
${CMAKE_SOURCE_DIR}/src/libshared/src
${CMAKE_SOURCE_DIR}/rust/lib
${TASK_INCLUDE_DIRS})
add_library (task STATIC CLI2.cpp CLI2.h
@ -50,9 +52,9 @@ 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.
target_link_libraries (task_executable task commands columns libshared task libshared ${TASK_LIBRARIES})
target_link_libraries (calc_executable task commands columns libshared task libshared ${TASK_LIBRARIES})
target_link_libraries (lex_executable task commands columns libshared task libshared ${TASK_LIBRARIES})
target_link_libraries (task_executable task tc tc-rust commands columns libshared task libshared ${TASK_LIBRARIES})
target_link_libraries (calc_executable task tc tc-rust commands columns libshared task libshared ${TASK_LIBRARIES})
target_link_libraries (lex_executable task tc tc-rust commands columns libshared task libshared ${TASK_LIBRARIES})
set_property (TARGET task_executable PROPERTY OUTPUT_NAME "task")

View file

@ -1,9 +1,11 @@
cmake_minimum_required (VERSION 3.0)
include_directories (${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_SOURCE_DIR}/src/tc
${CMAKE_SOURCE_DIR}/src/commands
${CMAKE_SOURCE_DIR}/src/columns
${CMAKE_SOURCE_DIR}/src/libshared/src
${CMAKE_SOURCE_DIR}/rust/lib
${TASK_INCLUDE_DIRS})
set (columns_SRCS Column.cpp Column.h

View file

@ -1,9 +1,11 @@
cmake_minimum_required (VERSION 3.0)
include_directories (${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_SOURCE_DIR}/src/tc
${CMAKE_SOURCE_DIR}/src/commands
${CMAKE_SOURCE_DIR}/src/columns
${CMAKE_SOURCE_DIR}/src/libshared/src
${CMAKE_SOURCE_DIR}/rust/lib
${TASK_INCLUDE_DIRS})
set (commands_SRCS Command.cpp Command.h

1
src/taskchampion Submodule

@ -0,0 +1 @@
Subproject commit 1631f29b8aed9002a7cf6dd605c83d9f0181e66d

16
src/tc/CMakeLists.txt Normal file
View file

@ -0,0 +1,16 @@
cmake_minimum_required (VERSION 3.0)
include_directories (${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_SOURCE_DIR}/src/tc
${CMAKE_SOURCE_DIR}/src/libshared/src
${CMAKE_SOURCE_DIR}/rust/lib
${TASK_INCLUDE_DIRS})
set (tc_SRCS
ffi.h
util.cpp util.h
Replica.cpp Replica.h
WorkingSet.cpp WorkingSet.h
Task.cpp Task.h)
add_library (tc STATIC ${tc_SRCS})

162
src/tc/Replica.cpp Normal file
View file

@ -0,0 +1,162 @@
////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2022, Dustin J. Mitchell
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// https://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////
#include <cmake.h>
#include <format.h>
#include "tc/Replica.h"
#include "tc/Task.h"
#include "tc/WorkingSet.h"
#include "tc/util.h"
using namespace tc::ffi;
////////////////////////////////////////////////////////////////////////////////
tc::Replica::Replica ()
{
inner = unique_tcreplica_ptr (
tc_replica_new_in_memory (),
[](TCReplica* rep) { tc_replica_free (rep); });
}
////////////////////////////////////////////////////////////////////////////////
tc::Replica::Replica (Replica &&other) noexcept
{
// move inner from other
inner = unique_tcreplica_ptr (
other.inner.release (),
[](TCReplica* rep) { tc_replica_free (rep); });
}
////////////////////////////////////////////////////////////////////////////////
tc::Replica& tc::Replica::operator= (Replica &&other) noexcept
{
if (this != &other) {
// move inner from other
inner = unique_tcreplica_ptr (
other.inner.release (),
[](TCReplica* rep) { tc_replica_free (rep); });
}
return *this;
}
////////////////////////////////////////////////////////////////////////////////
tc::Replica::Replica (const std::string& dir)
{
TCString path = tc_string_borrow (dir.c_str ());
TCString error;
auto tcreplica = tc_replica_new_on_disk (path, &error);
if (!tcreplica) {
auto errmsg = format ("Could not create replica at {1}: {2}", dir, tc_string_content (&error));
tc_string_free (&error);
throw errmsg;
}
inner = unique_tcreplica_ptr (
tcreplica,
[](TCReplica* rep) { tc_replica_free (rep); });
}
////////////////////////////////////////////////////////////////////////////////
tc::WorkingSet tc::Replica::working_set ()
{
TCWorkingSet *tcws = tc_replica_working_set (&*inner);
if (!tcws) {
throw replica_error ();
}
return WorkingSet {tcws};
}
////////////////////////////////////////////////////////////////////////////////
std::optional<tc::Task> tc::Replica::get_task (const std::string &uuid)
{
TCTask *tctask = tc_replica_get_task (&*inner, uuid2tc (uuid));
if (!tctask) {
auto error = tc_replica_error (&*inner);
if (error.ptr) {
throw replica_error (error);
} else {
return std::nullopt;
}
}
return std::make_optional (Task (tctask));
}
////////////////////////////////////////////////////////////////////////////////
tc::Task tc::Replica::new_task (tc::Status status, const std::string &description)
{
TCTask *tctask = tc_replica_new_task (&*inner, (tc::ffi::TCStatus)status, string2tc (description));
if (!tctask) {
throw replica_error ();
}
return Task (tctask);
}
////////////////////////////////////////////////////////////////////////////////
std::vector<tc::Task> tc::Replica::all_tasks ()
{
TCTaskList tasks = tc_replica_all_tasks (&*inner);
if (!tasks.items) {
throw replica_error ();
}
std::vector <Task> all;
all.reserve (tasks.len);
for (size_t i = 0; i < tasks.len; i++) {
auto tctask = tc_task_list_take (&tasks, i);
if (tctask) {
all.push_back (Task (tctask));
}
}
return all;
}
////////////////////////////////////////////////////////////////////////////////
void tc::Replica::rebuild_working_set ()
{
auto res = tc_replica_rebuild_working_set (&*inner, true);
if (res != TC_RESULT_OK) {
throw replica_error ();
}
}
////////////////////////////////////////////////////////////////////////////////
std::string tc::Replica::replica_error () {
return replica_error (tc_replica_error (&*inner));
}
////////////////////////////////////////////////////////////////////////////////
std::string tc::Replica::replica_error (TCString error) {
std::string errmsg;
if (!error.ptr) {
errmsg = std::string ("Unknown TaskChampion error");
} else {
errmsg = std::string (tc_string_content (&error));
}
tc_string_free (&error);
return errmsg;
}
////////////////////////////////////////////////////////////////////////////////

85
src/tc/Replica.h Normal file
View file

@ -0,0 +1,85 @@
////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2022, Dustin J. Mitchell
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// https://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_TC_REPLICA
#define INCLUDED_TC_REPLICA
#include <string>
#include <functional>
#include <memory>
#include <optional>
#include "tc/ffi.h"
#include "tc/Task.h"
namespace tc {
class Task;
class WorkingSet;
// a unique_ptr to a TCReplica which will automatically free the value when
// it goes out of scope.
using unique_tcreplica_ptr = std::unique_ptr<
tc::ffi::TCReplica,
std::function<void(tc::ffi::TCReplica*)>>;
// Replica wraps the TCReplica type, managing its memory, errors, and so on.
//
// Except as noted, method names match the suffix to `tc_replica_..`.
class Replica
{
public:
Replica (); // tc_replica_new_in_memory
Replica (const std::string& dir); // tc_replica_new_on_disk
// This object "owns" inner, so copy is not allowed.
Replica (const Replica &) = delete;
Replica &operator=(const Replica &) = delete;
// Explicit move constructor and assignment
Replica (Replica &&) noexcept;
Replica &operator=(Replica &&) noexcept;
std::vector<tc::Task> all_tasks ();
// TODO: struct TCUuidList tc_replica_all_task_uuids(struct TCReplica *rep);
tc::WorkingSet working_set ();
std::optional<tc::Task> get_task (const std::string &uuid);
tc::Task new_task (Status status, const std::string &description);
// TODO: struct TCTask *tc_replica_import_task_with_uuid(struct TCReplica *rep, struct TCUuid tcuuid);
// TODO: TCResult tc_replica_sync(struct TCReplica *rep, struct TCServer *server, bool avoid_snapshots);
// TODO: TCResult tc_replica_undo(struct TCReplica *rep, int32_t *undone_out);
// TODO: TCResult tc_replica_add_undo_point(struct TCReplica *rep, bool force);
void rebuild_working_set ();
private:
unique_tcreplica_ptr inner;
// construct an error message from tc_replica_error, or from the given
// string retrieved from tc_replica_error.
std::string replica_error ();
std::string replica_error (tc::ffi::TCString string);
};
}
#endif
////////////////////////////////////////////////////////////////////////////////

115
src/tc/Task.cpp Normal file
View file

@ -0,0 +1,115 @@
////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2022, Dustin J. Mitchell
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// https://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////
#include <cmake.h>
#include <assert.h>
#include "tc/Task.h"
#include "tc/util.h"
using namespace tc::ffi;
////////////////////////////////////////////////////////////////////////////////
tc::Task::Task (TCTask *tctask)
{
inner = unique_tctask_ptr(
tctask,
[](TCTask* task) { tc_task_free(task); });
}
////////////////////////////////////////////////////////////////////////////////
tc::Task::Task (Task &&other) noexcept
{
// move inner from other
inner = unique_tctask_ptr(
other.inner.release(),
[](TCTask* task) { tc_task_free(task); });
}
////////////////////////////////////////////////////////////////////////////////
tc::Task& tc::Task::operator= (Task &&other) noexcept
{
if (this != &other) {
// move inner from other
inner = unique_tctask_ptr(
other.inner.release(),
[](TCTask* task) { tc_task_free(task); });
}
return *this;
}
////////////////////////////////////////////////////////////////////////////////
std::string tc::Task::get_uuid () const
{
auto uuid = tc_task_get_uuid(&*inner);
return tc2uuid(uuid);
}
////////////////////////////////////////////////////////////////////////////////
tc::Status tc::Task::get_status () const
{
auto status = tc_task_get_status(&*inner);
return tc::Status(status);
}
////////////////////////////////////////////////////////////////////////////////
std::map <std::string, std::string> tc::Task::get_taskmap () const
{
TCKVList kv = tc_task_get_taskmap (&*inner);
if (!kv.items) {
throw task_error ();
}
std::map<std::string, std::string> taskmap;
for (size_t i = 0; i < kv.len; i++) {
auto k = tc2string_clone(kv.items[i].key);
auto v = tc2string_clone(kv.items[i].value);
taskmap[k] = v;
}
return taskmap;
}
////////////////////////////////////////////////////////////////////////////////
std::string tc::Task::get_description () const
{
auto desc = tc_task_get_description(&*inner);
return tc2string(desc);
}
////////////////////////////////////////////////////////////////////////////////
std::string tc::Task::task_error () const {
TCString error = tc_task_error (&*inner);
std::string errmsg;
if (!error.ptr) {
errmsg = std::string ("Unknown TaskChampion error");
} else {
errmsg = std::string (tc_string_content (&error));
}
tc_string_free (&error);
return errmsg;
}
////////////////////////////////////////////////////////////////////////////////

119
src/tc/Task.h Normal file
View file

@ -0,0 +1,119 @@
////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2022, Dustin J. Mitchell, Tomas Babej, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// https://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_TC_TASK
#define INCLUDED_TC_TASK
#include <string>
#include <functional>
#include <memory>
#include <map>
#include "tc/ffi.h"
namespace tc {
class Replica;
enum Status {
Pending = tc::ffi::TC_STATUS_PENDING,
Completed = tc::ffi::TC_STATUS_COMPLETED,
Deleted = tc::ffi::TC_STATUS_DELETED,
Unknown = tc::ffi::TC_STATUS_UNKNOWN,
};
// a unique_ptr to a TCReplica which will automatically free the value when
// it goes out of scope.
using unique_tctask_ptr = std::unique_ptr<
tc::ffi::TCTask,
std::function<void(tc::ffi::TCTask*)>>;
// Task wraps the TCTask type, managing its memory, errors, and so on.
//
// Except as noted, method names match the suffix to `tc_task_..`.
class Task
{
protected:
// Tasks may only be created by tc::Replica
friend class tc::Replica;
explicit Task (tc::ffi::TCTask *);
public:
// This object "owns" inner, so copy is not allowed.
Task (const Task &) = delete;
Task &operator=(const Task &) = delete;
// Explicit move constructor and assignment
Task (Task &&) noexcept;
Task &operator=(Task &&) noexcept;
// TODO: void tc_task_to_mut(struct TCTask *task, struct TCReplica *tcreplica);
// TODO: void tc_task_to_immut(struct TCTask *task);
std::string get_uuid () const;
Status get_status () const;
std::map <std::string, std::string> get_taskmap() const;
std::string get_description() const;
// TODO: time_t tc_task_get_entry(struct TCTask *task);
// TODO: time_t tc_task_get_wait(struct TCTask *task);
// TODO: time_t tc_task_get_modified(struct TCTask *task);
// TODO: bool tc_task_is_waiting(struct TCTask *task);
// TODO: bool tc_task_is_active(struct TCTask *task);
// TODO: bool tc_task_has_tag(struct TCTask *task, struct TCString tag);
// TODO: struct TCStringList tc_task_get_tags(struct TCTask *task);
// TODO: struct TCAnnotationList tc_task_get_annotations(struct TCTask *task);
// TODO: struct TCString tc_task_get_uda(struct TCTask *task, struct TCString ns, struct TCString key);
// TODO: struct TCString tc_task_get_legacy_uda(struct TCTask *task, struct TCString key);
// TODO: struct TCUdaList tc_task_get_udas(struct TCTask *task);
// TODO: struct TCUdaList tc_task_get_legacy_udas(struct TCTask *task);
// TODO: TCResult tc_task_set_status(struct TCTask *task, enum TCStatus status);
// TODO: TCResult tc_task_set_description(struct TCTask *task, struct TCString description);
// TODO: TCResult tc_task_set_entry(struct TCTask *task, time_t entry);
// TODO: TCResult tc_task_set_wait(struct TCTask *task, time_t wait);
// TODO: TCResult tc_task_set_modified(struct TCTask *task, time_t modified);
// TODO: TCResult tc_task_start(struct TCTask *task);
// TODO: TCResult tc_task_stop(struct TCTask *task);
// TODO: TCResult tc_task_done(struct TCTask *task);
// TODO: TCResult tc_task_delete(struct TCTask *task);
// TODO: TCResult tc_task_add_tag(struct TCTask *task, struct TCString tag);
// TODO: TCResult tc_task_remove_tag(struct TCTask *task, struct TCString tag);
// TODO: TCResult tc_task_add_annotation(struct TCTask *task, struct TCAnnotation *annotation);
// TODO: TCResult tc_task_remove_annotation(struct TCTask *task, int64_t entry);
// TODO: TCResult tc_task_set_uda(struct TCTask *task,
// TODO: TCResult tc_task_remove_uda(struct TCTask *task, struct TCString ns, struct TCString key);
// TODO: TCResult tc_task_set_legacy_uda(struct TCTask *task, struct TCString key, struct TCString value);
// TODO: TCResult tc_task_remove_legacy_uda(struct TCTask *task, struct TCString key);
private:
unique_tctask_ptr inner;
std::string task_error () const; // tc_task_error
};
}
// TODO: struct TCTask *tc_task_list_take(struct TCTaskList *tasks, size_t index);
// TODO: void tc_task_list_free(struct TCTaskList *tasks);
#endif
////////////////////////////////////////////////////////////////////////////////

98
src/tc/WorkingSet.cpp Normal file
View file

@ -0,0 +1,98 @@
////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2022, Dustin J. Mitchell
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// https://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////
#include <cmake.h>
#include <format.h>
#include "tc/WorkingSet.h"
#include "tc/Task.h"
#include "tc/util.h"
using namespace tc::ffi;
////////////////////////////////////////////////////////////////////////////////
tc::WorkingSet::WorkingSet (WorkingSet &&other) noexcept
{
// move inner from other
inner = unique_tcws_ptr (
other.inner.release (),
[](TCWorkingSet* ws) { tc_working_set_free (ws); });
}
////////////////////////////////////////////////////////////////////////////////
tc::WorkingSet& tc::WorkingSet::operator= (WorkingSet &&other) noexcept
{
if (this != &other) {
// move inner from other
inner = unique_tcws_ptr (
other.inner.release (),
[](TCWorkingSet* ws) { tc_working_set_free (ws); });
}
return *this;
}
////////////////////////////////////////////////////////////////////////////////
tc::WorkingSet::WorkingSet (tc::ffi::TCWorkingSet* tcws)
{
inner = unique_tcws_ptr (
tcws,
[](TCWorkingSet* ws) { tc_working_set_free (ws); });
}
////////////////////////////////////////////////////////////////////////////////
size_t tc::WorkingSet::len () const noexcept
{
return tc_working_set_len (&*inner);
}
////////////////////////////////////////////////////////////////////////////////
size_t tc::WorkingSet::largest_index () const noexcept
{
return tc_working_set_largest_index (&*inner);
}
////////////////////////////////////////////////////////////////////////////////
std::optional<std::string> tc::WorkingSet::by_index (size_t index) const noexcept
{
TCUuid uuid;
if (tc_working_set_by_index (&*inner, index, &uuid)) {
return std::make_optional (tc2uuid (uuid));
} else {
return std::nullopt;
}
}
////////////////////////////////////////////////////////////////////////////////
std::optional<size_t> tc::WorkingSet::by_uuid (const std::string &uuid) const noexcept
{
auto index = tc_working_set_by_uuid (&*inner, uuid2tc (uuid));
if (index > 0) {
return std::make_optional (index);
} else {
return std::nullopt;
}
}
////////////////////////////////////////////////////////////////////////////////

75
src/tc/WorkingSet.h Normal file
View file

@ -0,0 +1,75 @@
////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2022, Dustin J. Mitchell
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// https://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_TC_WORKINGSET
#define INCLUDED_TC_WORKINGSET
#include <string>
#include <functional>
#include <memory>
#include <optional>
#include "tc/ffi.h"
#include "tc/Task.h"
namespace tc {
class Task;
// a unique_ptr to a TCWorkingSet which will automatically free the value when
// it goes out of scope.
using unique_tcws_ptr = std::unique_ptr<
tc::ffi::TCWorkingSet,
std::function<void(tc::ffi::TCWorkingSet*)>>;
// WorkingSet wraps the TCWorkingSet type, managing its memory, errors, and so on.
//
// Except as noted, method names match the suffix to `tc_working_set_..`.
class WorkingSet
{
protected:
friend class tc::Replica;
WorkingSet (tc::ffi::TCWorkingSet*); // via tc_replica_working_set
public:
// This object "owns" inner, so copy is not allowed.
WorkingSet (const WorkingSet &) = delete;
WorkingSet &operator=(const WorkingSet &) = delete;
// Explicit move constructor and assignment
WorkingSet (WorkingSet &&) noexcept;
WorkingSet &operator=(WorkingSet &&) noexcept;
size_t len () const noexcept; // tc_working_set_len
size_t largest_index () const noexcept; // tc_working_set_largest_index
std::optional<std::string> by_index (size_t index) const noexcept; // tc_working_set_by_index
std::optional<size_t> by_uuid (const std::string &index) const noexcept; // tc_working_set_by_uuid
private:
unique_tcws_ptr inner;
};
}
#endif
////////////////////////////////////////////////////////////////////////////////

36
src/tc/ffi.h Normal file
View file

@ -0,0 +1,36 @@
////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2022, Dustin J. Mitchell, Tomas Babej, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// https://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_TC_FFI
#define INCLUDED_TC_FFI
// The entire FFI API is embedded in the `tc::ffi` namespace
namespace tc::ffi {
#include <taskchampion.h>
}
#endif
////////////////////////////////////////////////////////////////////////////////

3
src/tc/rust/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
target
x86_64-unknown-linux-gnu
.rustc_info.json

View file

@ -0,0 +1 @@
cargo_build(NAME tc-rust)

708
src/tc/rust/Cargo.lock generated Normal file
View file

@ -0,0 +1,708 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "ahash"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
dependencies = [
"getrandom",
"once_cell",
"version_check",
]
[[package]]
name = "anyhow"
version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "base64"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bumpalo"
version = "3.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"libc",
"num-integer",
"num-traits",
"serde",
"time",
"winapi",
]
[[package]]
name = "chunked_transfer"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e"
[[package]]
name = "crc32fast"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
dependencies = [
"cfg-if",
]
[[package]]
name = "fallible-iterator"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
[[package]]
name = "fallible-streaming-iterator"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
[[package]]
name = "flate2"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f"
dependencies = [
"cfg-if",
"crc32fast",
"libc",
"miniz_oxide",
]
[[package]]
name = "form_urlencoded"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
dependencies = [
"matches",
"percent-encoding",
]
[[package]]
name = "getrandom"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
dependencies = [
"ahash",
]
[[package]]
name = "hashlink"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf"
dependencies = [
"hashbrown",
]
[[package]]
name = "heck"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "idna"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "itoa"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]]
name = "js-sys"
version = "0.3.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
[[package]]
name = "libsqlite3-sys"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14"
dependencies = [
"cc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
[[package]]
name = "matches"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "miniz_oxide"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
dependencies = [
"adler",
"autocfg",
]
[[package]]
name = "num-integer"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pkg-config"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
[[package]]
name = "proc-macro2"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58"
dependencies = [
"proc-macro2",
]
[[package]]
name = "ring"
version = "0.16.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
dependencies = [
"cc",
"libc",
"once_cell",
"spin",
"untrusted",
"web-sys",
"winapi",
]
[[package]]
name = "rusqlite"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85127183a999f7db96d1a976a309eebbfb6ea3b0b400ddd8340190129de6eb7a"
dependencies = [
"bitflags",
"fallible-iterator",
"fallible-streaming-iterator",
"hashlink",
"libsqlite3-sys",
"memchr",
"smallvec",
]
[[package]]
name = "rustls"
version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fbfeb8d0ddb84706bc597a5574ab8912817c52a397f819e5b614e2265206921"
dependencies = [
"log",
"ring",
"sct",
"webpki",
]
[[package]]
name = "rustversion"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0a5f7c728f5d284929a1cccb5bc19884422bfe6ef4d6c409da2c41838983fcf"
[[package]]
name = "ryu"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
[[package]]
name = "sct"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "serde"
version = "1.0.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1578c6245786b9d168c5447eeacfb96856573ca56c9d68fdcf394be134882a47"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "023e9b1467aef8a10fb88f25611870ada9800ef7e22afce356bb0d2387b6f27c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "smallvec"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "strum"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
[[package]]
name = "strum_macros"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4faebde00e8ff94316c01800f9054fd2ba77d30d9e922541913051d1d978918b"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn",
]
[[package]]
name = "syn"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "taskchampion"
version = "0.4.1"
dependencies = [
"anyhow",
"byteorder",
"chrono",
"flate2",
"log",
"ring",
"rusqlite",
"serde",
"serde_json",
"strum",
"strum_macros",
"thiserror",
"ureq",
"uuid",
]
[[package]]
name = "taskchampion-lib"
version = "0.1.0"
dependencies = [
"anyhow",
"libc",
"taskchampion",
]
[[package]]
name = "tc-rust"
version = "0.1.0"
dependencies = [
"taskchampion-lib",
]
[[package]]
name = "thiserror"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "time"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "tinyvec"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "unicode-bidi"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
[[package]]
name = "unicode-normalization"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "untrusted"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "ureq"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9399fa2f927a3d327187cbd201480cee55bee6ac5d3c77dd27f0c6814cff16d5"
dependencies = [
"base64",
"chunked_transfer",
"flate2",
"log",
"once_cell",
"rustls",
"url",
"webpki",
"webpki-roots",
]
[[package]]
name = "url"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
dependencies = [
"form_urlencoded",
"idna",
"matches",
"percent-encoding",
]
[[package]]
name = "uuid"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f"
dependencies = [
"getrandom",
"serde",
]
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "wasm-bindgen"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2"
[[package]]
name = "web-sys"
version = "0.3.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "webpki"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "webpki-roots"
version = "0.22.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449"
dependencies = [
"webpki",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

9
src/tc/rust/Cargo.toml Normal file
View file

@ -0,0 +1,9 @@
[package]
name = "tc-rust"
version = "0.1.0"
[lib]
crate-type = ["staticlib"]
[dependencies]
taskchampion-lib = {path = "../../../rust/lib"}

2
src/tc/rust/src/lib.rs Normal file
View file

@ -0,0 +1,2 @@
extern crate taskchampion_lib;
pub use taskchampion_lib::*;

81
src/tc/util.cpp Normal file
View file

@ -0,0 +1,81 @@
////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2022, Dustin J. Mitchell
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// https://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////
#include <cmake.h>
#include <format.h>
#include <assert.h>
#include "tc/Replica.h"
#include "tc/Task.h"
using namespace tc::ffi;
namespace tc {
////////////////////////////////////////////////////////////////////////////////
TCString string2tc (const std::string& str)
{
return tc_string_clone_with_len (str.data (), str.size ());
}
////////////////////////////////////////////////////////////////////////////////
std::string tc2string_clone (const TCString& str)
{
size_t len;
auto ptr = tc_string_content_with_len (&str, &len);
auto rv = std::string (ptr, len);
return rv;
}
////////////////////////////////////////////////////////////////////////////////
std::string tc2string (TCString& str)
{
auto rv = tc2string_clone(str);
tc_string_free (&str);
return rv;
}
////////////////////////////////////////////////////////////////////////////////
TCUuid uuid2tc(const std::string& str)
{
TCString tcstr = tc_string_borrow(str.c_str());
TCUuid rv;
if (TC_RESULT_OK != tc_uuid_from_str(tcstr, &rv)) {
throw std::string ("invalid UUID");
}
return rv;
}
////////////////////////////////////////////////////////////////////////////////
std::string tc2uuid (TCUuid& uuid)
{
char s[TC_UUID_STRING_BYTES];
tc_uuid_to_buf (uuid, s);
std::string str;
str.assign (s, TC_UUID_STRING_BYTES);
return str;
}
////////////////////////////////////////////////////////////////////////////////
}

51
src/tc/util.h Normal file
View file

@ -0,0 +1,51 @@
////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2022, Dustin J. Mitchell
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// https://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_TC_UTIL
#define INCLUDED_TC_UTIL
#include <string>
#include "tc/ffi.h"
namespace tc {
// convert a std::string into a TCString, copying the contained data
tc::ffi::TCString string2tc(const std::string&);
// convert a TCString into a std::string, leaving the TCString as-is
std::string tc2string_clone(const tc::ffi::TCString&);
// convert a TCString into a std::string, freeing the TCString
std::string tc2string(tc::ffi::TCString&);
// convert a TCUuid into a std::string
std::string tc2uuid(tc::ffi::TCUuid&);
// parse a std::string into a TCUuid (throwing if parse fails)
tc::ffi::TCUuid uuid2tc(const std::string&);
}
#endif
////////////////////////////////////////////////////////////////////////////////

1
test/.gitignore vendored
View file

@ -34,6 +34,7 @@ variant_partial.t
variant_subtract.t
variant_xor.t
view.t
tc.t
tw-2689.t
json_test

View file

@ -14,9 +14,10 @@ include_directories (${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/src/columns
${CMAKE_SOURCE_DIR}/src/libshared/src
${CMAKE_SOURCE_DIR}/test
${CMAKE_SOURCE_DIR}/rust/lib
${TASK_INCLUDE_DIRS})
set (test_SRCS col.t dom.t eval.t lexer.t t.t tw-2689.t tdb2.t util.t variant_add.t variant_and.t variant_cast.t variant_divide.t variant_equal.t variant_exp.t variant_gt.t variant_gte.t variant_inequal.t variant_lt.t variant_lte.t variant_match.t variant_math.t variant_modulo.t variant_multiply.t variant_nomatch.t variant_not.t variant_or.t variant_partial.t variant_subtract.t variant_xor.t view.t)
set (test_SRCS col.t dom.t eval.t lexer.t t.t tw-2689.t tdb2.t tc.t util.t variant_add.t variant_and.t variant_cast.t variant_divide.t variant_equal.t variant_exp.t variant_gt.t variant_gte.t variant_inequal.t variant_lt.t variant_lte.t variant_match.t variant_math.t variant_modulo.t variant_multiply.t variant_nomatch.t variant_not.t variant_or.t variant_partial.t variant_subtract.t variant_xor.t view.t)
add_custom_target (test ./run_all --verbose
DEPENDS ${test_SRCS} task_executable
@ -27,7 +28,7 @@ add_custom_target (build_tests DEPENDS ${test_SRCS}
foreach (src_FILE ${test_SRCS})
add_executable (${src_FILE} "${src_FILE}.cpp" test.cpp)
target_link_libraries (${src_FILE} task commands columns libshared task commands columns libshared task commands columns libshared ${TASK_LIBRARIES})
target_link_libraries (${src_FILE} task tc commands columns libshared task tc tc-rust commands columns libshared task commands columns libshared ${TASK_LIBRARIES})
endforeach (src_FILE)
configure_file(run_all run_all COPYONLY)

111
test/tc.t.cpp Normal file
View file

@ -0,0 +1,111 @@
////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2022, Dustin J. Mitchell
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// https://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////
#include <cmake.h>
#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include "test.h"
#include "tc/Replica.h"
#include "tc/WorkingSet.h"
#include "tc/Task.h"
#include "tc/util.h"
////////////////////////////////////////////////////////////////////////////////
int main (int, char**)
{
UnitTest t (21);
// This function contains unit tests for the various bits of the wrappers for
// taskchampion-lib (that is, for `src/tc/*.cpp`).
//// util
{
auto s1 = std::string ("a\0string!");
auto stc = tc::string2tc (s1);
auto s2 = tc::tc2string (stc);
t.is (s1, s2, "round-trip to tc string and back (containing an embedded NUL)");
}
{
auto s1 = std::string ("62123ec9-c443-4f7e-919a-35362a8bef8d");
auto tcuuid = tc::uuid2tc (s1);
auto s2 = tc::tc2uuid (tcuuid);
t.is(s1, s2, "round-trip to TCUuid and back");
}
//// Replica
auto rep = tc::Replica ();
t.pass ("replica constructed");
auto maybe_task = rep.get_task("24478a28-4609-4257-bc19-44ec51391431");
t.notok(maybe_task.has_value(), "task with fixed uuid does not exist");
auto task = rep.new_task (tc::Status::Pending, "a test");
t.pass ("new task constructed");
t.is (task.get_description (), std::string ("a test"), "task description round-trip");
t.is (task.get_status (), tc::Status::Pending, "task status round-trip");
auto uuid = task.get_uuid();
auto maybe_task2 = rep.get_task (uuid);
t.ok(maybe_task2.has_value(), "task lookup by uuid finds task");
t.is ((*maybe_task2).get_description (), std::string ("a test"), "task description round-trip");
rep.rebuild_working_set ();
t.pass ("rebuild_working_set");
auto tasks = rep.all_tasks ();
t.is ((int)tasks.size(), 1, "all_tasks returns one task");
//// Task
task = std::move(tasks[0]);
t.is (task.get_uuid(), uuid, "returned task has correct uuid");
t.is (task.get_status(), tc::Status::Pending, "returned task is pending");
auto map = task.get_taskmap ();
t.is (map["description"], "a test", "task description in taskmap");
t.is (task.get_description(), "a test", "returned task has correct description");
//// WorkingSet
auto ws = rep.working_set ();
t.is (ws.len (), (size_t)1, "WorkingSet::len");
t.is (ws.largest_index (), (size_t)1, "WorkingSet::largest_index");
t.is (ws.by_index (1).value(), uuid, "WorkingSet::by_index");
t.is (ws.by_index (2).has_value(), false, "WorkingSet::by_index for unknown index");
t.is (ws.by_uuid (uuid).value (), (size_t)1, "WorkingSet::by_uuid");
t.is (ws.by_uuid ("3e18a306-e3a8-4a53-a85c-fa7c057759a2").has_value (), false, "WorkingSet::by_uuid for unknown uuid");
return 0;
}
////////////////////////////////////////////////////////////////////////////////