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/taskd
src/libtask.a src/libtask.a
src/commands/libcommands.a src/commands/libcommands.a
src/tc/libtc.a
src/columns/libcolumns.a src/columns/libcolumns.a
*~ *~
.*.swp .*.swp

6
.gitmodules vendored
View file

@ -1,3 +1,9 @@
[submodule "src/libshared"] [submodule "src/libshared"]
path = src/libshared path = src/libshared
url = https://github.com/GothenburgBitFactory/libshared.git 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) 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 (CheckFunctionExists)
include (CheckStructHasMember) 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_RCDIR "${TASK_DOCDIR}/rc" CACHE STRING "Installation directory for configuration files")
SET (TASK_BINDIR bin CACHE STRING "Installation directory for the binary") SET (TASK_BINDIR bin CACHE STRING "Installation directory for the binary")
# rust libs require these
set (TASK_LIBRARIES dl pthread)
if (USE_GNUTLS) if (USE_GNUTLS)
message ("-- Looking for GnuTLS") message ("-- Looking for GnuTLS")
find_package (GnuTLS) find_package (GnuTLS)
@ -150,6 +155,8 @@ configure_file (
add_subdirectory (src) add_subdirectory (src)
add_subdirectory (src/commands) add_subdirectory (src/commands)
add_subdirectory (src/tc)
add_subdirectory (src/tc/rust)
add_subdirectory (src/columns) add_subdirectory (src/columns)
add_subdirectory (doc) add_subdirectory (doc)
add_subdirectory (scripts) add_subdirectory (scripts)
@ -185,7 +192,7 @@ set (CPACK_SOURCE_IGNORE_FILES "CMakeCache" "CMakeFiles" "CPackConfig" "CPackSo
"_CPack_Packages" "cmake_install" "install_manifest" "Makefile$" "_CPack_Packages" "cmake_install" "install_manifest" "Makefile$"
"test" "package-config" "misc/*" "src/task$" "src/calc$" "performance" "test" "package-config" "misc/*" "src/task$" "src/calc$" "performance"
"src/libtask.a" "src/columns/libcolumns.a" "src/commands/libcommands.a" "src/libtask.a" "src/columns/libcolumns.a" "src/commands/libcommands.a"
"swp$" "src/lex$" "task-.*.tar.gz" "commit.h" "cmake.h$" "\\\\.gitmodules" "src/tc/libtc.a" "swp$" "src/lex$" "task-.*.tar.gz" "commit.h" "cmake.h$"
"src/libshared/\\\\.git" ".github/" ".*\\\\.gitignore$" "\\\\.gitmodules" "src/libshared/\\\\.git" ".github/" ".*\\\\.gitignore$"
"src/liblibshared.a" "docker-compose.yml" "\\\\.git/") "src/liblibshared.a" "docker-compose.yml" "\\\\.git/")
include (CPack) include (CPack)

View file

@ -7,3 +7,6 @@ members = [
"rust/integration-tests", "rust/integration-tests",
"rust/xtask", "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. 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. 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. Visit [Github](https://github.com/GothenburgBitFactory/taskwarrior) and participate in the future of Taskwarrior.
See further development documentation in [`docs/`](./docs).
## Sponsoring ## Sponsoring
[![GitHub Sponsors](https://img.shields.io/github/sponsors/GothenburgBitFactory?color=green)](https://github.com/sponsors/GothenburgBitFactory/) [![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 Branching
Git allows arbitrary and low-cost branching, which means that any branching model can be used. 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) [![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 ## Contributing to Taskwarrior
* [How to become an Open Source Contributor](./contrib/first_time) * [How to become an Open Source Contributor](./contrib/first_time.md)
* [Contributing to Taskwarrior](./contrib/contribute) * [Contributing to Taskwarrior](./contrib/contribute.md)
* [Developing Taskwarrior](./contrib/development) * [Developing Taskwarrior](./contrib/development.md)
* [Building Taskwarrior](./contrib/build) * [Building Taskwarrior](./contrib/build.md)
* [Coding Style](./contrib/coding_style) * [Coding Style](./contrib/coding_style.md)
* [Branching Model](./contrib/branching) * [Branching Model](./contrib/branching.md)
* [Rust and C++](./contrib/rust-and-c++.md)
## RFC's ## 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. 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. These documents apply only to the Taskwarrior family of products, and are placed here to invite comment before designs finalize.
- [General Plans](./rfcs/plans) - [General Plans](./rfcs/plans.md)
- [Rules System](./rfcs/rules) - [Rules System](./rfcs/rules.md)
- [Full DOM Support ](./rfcs/dom) - [Full DOM Support ](./rfcs/dom.md)
- [Work Week Support](./rfcs/workweek) - [Work Week Support](./rfcs/workweek.md)
- [Recurrence](./rfcs/recurrence) - [Recurrence](./rfcs/recurrence.md)
- [Taskwarrior JSON Format](./rfcs/task) - [Taskwarrior JSON Format](./rfcs/task.md)
- [CLI Updates ](./rfcs/cli) - [CLI Updates ](./rfcs/cli.md)
- [Taskserver Sync Protocol](./rfcs/protocol) - [Taskserver Sync Protocol](./rfcs/protocol.md)
- [Taskserver Message Format](./rfcs/request) - [Taskserver Message Format](./rfcs/request.md)
- [Taskserver Sync Algorithm](./rfcs/sync) - [Taskserver Sync Algorithm](./rfcs/sync.md)
- [Taskserver Client](./rfcs/client) - [Taskserver Client](./rfcs/client.md)

View file

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

View file

@ -1,9 +1,11 @@
cmake_minimum_required (VERSION 3.0) cmake_minimum_required (VERSION 3.0)
include_directories (${CMAKE_SOURCE_DIR} include_directories (${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src
${CMAKE_SOURCE_DIR}/src/tc
${CMAKE_SOURCE_DIR}/src/commands ${CMAKE_SOURCE_DIR}/src/commands
${CMAKE_SOURCE_DIR}/src/columns ${CMAKE_SOURCE_DIR}/src/columns
${CMAKE_SOURCE_DIR}/src/libshared/src ${CMAKE_SOURCE_DIR}/src/libshared/src
${CMAKE_SOURCE_DIR}/rust/lib
${TASK_INCLUDE_DIRS}) ${TASK_INCLUDE_DIRS})
add_library (task STATIC CLI2.cpp CLI2.h add_library (task STATIC CLI2.cpp CLI2.h
@ -50,9 +52,9 @@ add_executable (calc_executable calc.cpp)
add_executable (lex_executable lex.cpp) add_executable (lex_executable lex.cpp)
# Yes, 'task' (and hence libshared) is included twice, otherwise linking fails on assorted OSes. # 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 (task_executable task tc tc-rust commands columns libshared task libshared ${TASK_LIBRARIES})
target_link_libraries (calc_executable task 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 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") set_property (TARGET task_executable PROPERTY OUTPUT_NAME "task")

View file

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

View file

@ -1,9 +1,11 @@
cmake_minimum_required (VERSION 3.0) cmake_minimum_required (VERSION 3.0)
include_directories (${CMAKE_SOURCE_DIR} include_directories (${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src
${CMAKE_SOURCE_DIR}/src/tc
${CMAKE_SOURCE_DIR}/src/commands ${CMAKE_SOURCE_DIR}/src/commands
${CMAKE_SOURCE_DIR}/src/columns ${CMAKE_SOURCE_DIR}/src/columns
${CMAKE_SOURCE_DIR}/src/libshared/src ${CMAKE_SOURCE_DIR}/src/libshared/src
${CMAKE_SOURCE_DIR}/rust/lib
${TASK_INCLUDE_DIRS}) ${TASK_INCLUDE_DIRS})
set (commands_SRCS Command.cpp Command.h 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_subtract.t
variant_xor.t variant_xor.t
view.t view.t
tc.t
tw-2689.t tw-2689.t
json_test json_test

View file

@ -14,9 +14,10 @@ include_directories (${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/src/columns ${CMAKE_SOURCE_DIR}/src/columns
${CMAKE_SOURCE_DIR}/src/libshared/src ${CMAKE_SOURCE_DIR}/src/libshared/src
${CMAKE_SOURCE_DIR}/test ${CMAKE_SOURCE_DIR}/test
${CMAKE_SOURCE_DIR}/rust/lib
${TASK_INCLUDE_DIRS}) ${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 add_custom_target (test ./run_all --verbose
DEPENDS ${test_SRCS} task_executable DEPENDS ${test_SRCS} task_executable
@ -27,7 +28,7 @@ add_custom_target (build_tests DEPENDS ${test_SRCS}
foreach (src_FILE ${test_SRCS}) foreach (src_FILE ${test_SRCS})
add_executable (${src_FILE} "${src_FILE}.cpp" test.cpp) 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) endforeach (src_FILE)
configure_file(run_all run_all COPYONLY) 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;
}
////////////////////////////////////////////////////////////////////////////////