//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
//! Module containing `Task` type as well as trait implementations
use std::marker::PhantomData;
use std::result::Result as RResult;
use chrono::Utc;
use serde::{de, Deserialize, Deserializer};
use serde::{Serialize, Serializer};
use uuid::Uuid;
use crate::annotation::Annotation;
use crate::date::Date;
use crate::priority::TaskPriority;
use crate::project::Project;
use crate::status::TaskStatus;
use crate::tag::Tag;
use crate::uda::UDA;
use crate::urgency::Urgency;
/// Unit struct used to represent taskwarrior format 2.6.0 and newer.
/// See [Task] for more information.
#[derive(Debug, Clone)]
pub struct TW26;
/// Unit struct used to represent taskwarrior format 2.5.3 and older.
/// See [Task] for more information.
#[derive(Debug, Clone)]
pub struct TW25;
// Prevents folks outside this crate from implementing their own versions
mod private {
pub trait Sealed {}
impl Sealed for super::TW26 {}
impl Sealed for super::TW25 {}
}
/// Trait used to represent taskwarrior version types
pub trait TaskWarriorVersion: private::Sealed {}
impl TaskWarriorVersion for TW26 {}
impl TaskWarriorVersion for TW25 {}
/// Task type
///
/// A task must have four things:
///
/// - A Status
/// - An UUID
/// - An Entry-Date
/// - A Description
///
/// all other Data is optional by taskwarrior. This type is a simple rust representation of the
/// JSON exported by taskwarrior.
///
/// For further explanations of the fields please consult the documentation on https://taskwarrior.org/
///
/// It is deserializeable and serializeable via serde_json, so importing and exporting taskwarrior
/// tasks is simply serializing and deserializing objects of this type.
///
/// As of taskwarrior version 2.6.0 and newer, the representation of `depends` has changed from
/// being a comma seperated string of uuid's to being a proper json array. You can select which
/// behaviour you want at compiletime by providing either [TW26] (the default) or [TW25] to `Task` as its
/// type parameter.
#[derive(Debug, Clone, PartialEq, derive_builder::Builder, Serialize, Deserialize)]
#[builder(setter(into))]
pub struct Task<Version: TaskWarriorVersion + 'static = TW26> {
/// The temporary assigned task id
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
id: Option<u64>,
/// The status of the task
#[builder(default = "TaskStatus::Pending")]
status: TaskStatus,
/// The uuid which identifies the task and is important for syncing
#[builder(default = "Uuid::new_v4()")]
uuid: Uuid,
/// The entry date, when this task was created
#[builder(default = "Date::from(Utc::now().naive_utc())")]
entry: Date,
/// The description of the task (i.e. its main content)
/// This field is the only mandatory field, when using the TaskBuilder.
description: String,
/// A list of annotations with timestamps
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
annotations: Option<Vec<Annotation>>,
/// The uuids of other tasks which have to be completed before this one becomes unblocked.
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(serialize_with = "serialize_depends::<_, Version>")]
#[serde(deserialize_with = "deserialize_depends::<_, Version>", default)]
depends: Option<Vec<Uuid>>,
/// The due date of the task
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
due: Option<Date>,
/// When the task was last deleted or completed
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
end: Option<Date>,
/// The imask is used internally for recurrence
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
imask: Option<f64>,
/// The mask is used internally for recurrence
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
mask: Option<String>,
/// When the task was last modified
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
modified: Option<Date>,
/// A task can have a parent task
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
parent: Option<Uuid>,
/// The priority of the task
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
priority: Option<TaskPriority>,
/// A task can be part of a project. Typically of the form "project.subproject.subsubproject"
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
project: Option<Project>,
/// The timespan after which this task should recur
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
recur: Option<String>,
/// When the task becomes ready
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
scheduled: Option<Date>,
/// When the task becomes active
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
start: Option<Date>,
/// The tags associated with the task
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
tags: Option<Vec<Tag>>,
/// When the recurrence stops
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]
until: Option<Date>,
/// This hides the task until the wait date
#[builder(default)]
#[serde(skip_serializing_if = "Option::is_none")]