diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2016-07-16 15:01:38 +0200 |
---|---|---|
committer | Malte Brandy <malte.brandy@maralorn.de> | 2018-04-18 00:36:24 +0200 |
commit | 0dc43d01c167e020656774849c40a7349e7e5b0f (patch) | |
tree | fff6d0d168b57a5837b4755bc534a2e6d200c85a /src/task.rs | |
parent | 1dab9869b189506f66331a994faa7149abc3e3a3 (diff) |
Add basic UDA support
Diffstat (limited to 'src/task.rs')
-rw-r--r-- | src/task.rs | 321 |
1 files changed, 288 insertions, 33 deletions
diff --git a/src/task.rs b/src/task.rs index cb2b806..f481c64 100644 --- a/src/task.rs +++ b/src/task.rs @@ -6,6 +6,15 @@ //! Module containing `Task` type as well as trait implementations +use std::result::Result as RResult; +use std::collections::BTreeMap; + +use serde::Serialize; +use serde::Serializer; +use serde::Deserialize; +use serde::Deserializer; +use serde::de::Visitor; +use serde::de::MapVisitor as DeserializeMapVisitor; use uuid::Uuid; use priority::TaskPriority; @@ -14,6 +23,7 @@ use project::Project; use tag::Tag; use date::Date; use annotation::Annotation; +use uda::{UDAName, UDAValue}; /// Task type /// @@ -29,60 +39,29 @@ use annotation::Annotation; /// /// It is deserializeable and serializeable via serde_json, so importing and exporting taskwarrior /// tasks is simply serializing and deserializing objects of this type. -#[derive(Debug, Clone, Deserialize, Serialize)] +#[derive(Debug, Clone)] pub struct Task { status : TaskStatus, uuid : Uuid, entry : Date, description : String, - - #[serde(skip_serializing_if = "Option::is_none")] annotations : Option<Vec<Annotation>>, - - #[serde(skip_serializing_if = "Option::is_none")] depends : Option<String>, - - #[serde(skip_serializing_if = "Option::is_none")] due : Option<Date>, - - #[serde(skip_serializing_if = "Option::is_none")] end : Option<Date>, - - #[serde(skip_serializing_if = "Option::is_none")] imask : Option<i64>, - - #[serde(skip_serializing_if = "Option::is_none")] mask : Option<String>, - - #[serde(skip_serializing_if = "Option::is_none")] modified : Option<Date>, - - #[serde(skip_serializing_if = "Option::is_none")] parent : Option<Uuid>, - - #[serde(skip_serializing_if = "Option::is_none")] priority : Option<TaskPriority>, - - #[serde(skip_serializing_if = "Option::is_none")] project : Option<Project>, - - #[serde(skip_serializing_if = "Option::is_none")] recur : Option<String>, - - #[serde(skip_serializing_if = "Option::is_none")] scheduled : Option<Date>, - - #[serde(skip_serializing_if = "Option::is_none")] start : Option<Date>, - - #[serde(skip_serializing_if = "Option::is_none")] tags : Option<Vec<Tag>>, - - #[serde(skip_serializing_if = "Option::is_none")] until : Option<Date>, - - #[serde(skip_serializing_if = "Option::is_none")] wait : Option<Date>, + uda : BTreeMap<UDAName, UDAValue>, } /* @@ -114,6 +93,7 @@ impl Task { tags : Option<Vec<Tag>>, until : Option<Date>, wait : Option<Date>, + uda : BTreeMap<UDAName, UDAValue>, ) -> Task { Task { @@ -138,6 +118,7 @@ impl Task { tags : tags, until : until, wait : wait, + uda : uda, } } @@ -345,9 +326,283 @@ impl Task { pub fn wait_mut(&mut self) -> Option<&mut Date> { self.wait.as_mut() } + /// Get the BTreeMap that contains the UDA + pub fn uda(&self) -> &BTreeMap<UDAName, UDAValue> { + &self.uda + + /// Get the BTreeMap that contains the UDA mutable + pub fn uda(&mut self) -> &mut BTreeMap<UDAName, UDAValue> { + &self.uda +} + +impl Serialize for Task { + + fn serialize<S>(&self, serializer: &mut S) -> RResult<(), S::Error> + where S: Serializer + { + let mut state = try!(serializer.serialize_struct("Task", 19)); + try!(serializer.serialize_struct_elt(&mut state, "status", &self.status)); + try!(serializer.serialize_struct_elt(&mut state, "uuid", &self.uuid)); + try!(serializer.serialize_struct_elt(&mut state, "entry", &self.entry)); + try!(serializer.serialize_struct_elt(&mut state, "description", &self.description)); + try!(serializer.serialize_struct_elt(&mut state, "annotations", &self.annotations)); + try!(serializer.serialize_struct_elt(&mut state, "tags", &self.tags)); + + match self.recur { + Some(ref v) => try!(serializer.serialize_struct_elt(&mut state, "recur", v)), + None => { }, + } + match self.depends { + Some(ref v) => try!(serializer.serialize_struct_elt(&mut state, "depends", v)), + None => { }, + } + match self.due { + Some(ref v) => try!(serializer.serialize_struct_elt(&mut state, "due", v)), + None => { }, + } + match self.end { + Some(ref v) => try!(serializer.serialize_struct_elt(&mut state, "end", v)), + None => { }, + } + match self.imask { + Some(ref v) => try!(serializer.serialize_struct_elt(&mut state, "imask", v)), + None => { }, + } + match self.mask { + Some(ref v) => try!(serializer.serialize_struct_elt(&mut state, "mask", v)), + None => { }, + } + match self.modified { + Some(ref v) => try!(serializer.serialize_struct_elt(&mut state, "modified", v)), + None => { }, + } + match self.parent { + Some(ref v) => try!(serializer.serialize_struct_elt(&mut state, "parent", v)), + None => { }, + } + match self.priority { + Some(ref v) => try!(serializer.serialize_struct_elt(&mut state, "priority", v)), + None => { }, + } + match self.project { + Some(ref v) => try!(serializer.serialize_struct_elt(&mut state, "project", v)), + None => { }, + } + match self.scheduled { + Some(ref v) => try!(serializer.serialize_struct_elt(&mut state, "scheduled", v)), + None => { }, + } + match self.start { + Some(ref v) => try!(serializer.serialize_struct_elt(&mut state, "start", v)), + None => { }, + } + match self.until { + Some(ref v) => try!(serializer.serialize_struct_elt(&mut state, "until", v)), + None => { }, + } + match self.wait { + Some(ref v) => try!(serializer.serialize_struct_elt(&mut state, "wait", v)), + None => { }, + } + + serializer.serialize_struct_end(state) + } } +impl Deserialize for Task { + + fn deserialize<D>(deserializer: &mut D) -> RResult<Task, D::Error> + where D: Deserializer + { + static FIELDS: &'static [&'static str] = &[ + "status", + "uuid", + "entry", + "description", + + "annotations", + "depends", + "due", + "end", + "imask", + "mask", + "modified", + "parent", + "priority", + "project", + "recur", + "scheduled", + "start", + "tags", + "until", + "wait" + ]; + deserializer.deserialize_struct("Task", FIELDS, TaskDeserializeVisitor) + } + +} + +/// Helper type for task deserialization +struct TaskDeserializeVisitor; + +impl Visitor for TaskDeserializeVisitor { + type Value = Task; + + fn visit_map<V>(&mut self, mut visitor: V) -> RResult<Task, V::Error> + where V: DeserializeMapVisitor + { + let mut status = None; + let mut uuid = None; + let mut entry = None; + let mut description = None; + + let mut annotations = None; + let mut depends = None; + let mut due = None; + let mut end = None; + let mut imask = None; + let mut mask = None; + let mut modified = None; + let mut parent = None; + let mut priority = None; + let mut project = None; + let mut recur = None; + let mut scheduled = None; + let mut start = None; + let mut tags = None; + let mut until = None; + let mut wait = None; + + loop { + let key : Option<String> = try!(visitor.visit_key()); + if key.is_none() { + break; + } + let key = key.unwrap(); + + match &key[..] { + "status" => { + status = Some(try!(visitor.visit_value())); + }, + "uuid" => { + uuid = Some(try!(visitor.visit_value())); + }, + "entry" => { + entry = Some(try!(visitor.visit_value())); + }, + "description" => { + description = Some(try!(visitor.visit_value())); + }, + + "annotations" => { + annotations = Some(try!(visitor.visit_value())); + }, + "depends" => { + depends = Some(try!(visitor.visit_value())); + }, + "due" => { + due = Some(try!(visitor.visit_value())); + }, + "end" => { + end = Some(try!(visitor.visit_value())); + }, + "imask" => { + imask = Some(try!(visitor.visit_value())); + }, + "mask" => { + mask = Some(try!(visitor.visit_value())); + }, + "modified" => { + modified = Some(try!(visitor.visit_value())); + }, + "parent" => { + parent = Some(try!(visitor.visit_value())); + }, + "priority" => { + priority = Some(try!(visitor.visit_value())); + }, + "project" => { + project = Some(try!(visitor.visit_value())); + }, + "recur" => { + recur = Some(try!(visitor.visit_value())); + }, + "scheduled" => { + scheduled = Some(try!(visitor.visit_value())); + }, + "start" => { + start = Some(try!(visitor.visit_value())); + }, + "tags" => { + tags = Some(try!(visitor.visit_value())); + }, + "until" => { + until = Some(try!(visitor.visit_value())); + }, + "wait" => { + wait = Some(try!(visitor.visit_value())); + }, + + field => { + use serde::de::impls::IgnoredAny; + + debug!("field '{}' ignored", field); + let _: IgnoredAny = try!(visitor.visit_value()); + } + } + } + + let status = match status { + Some(status) => status, + None => try!(visitor.missing_field("status")), + }; + + let uuid = match uuid { + Some(uuid) => uuid, + None => try!(visitor.missing_field("uuid")), + }; + + let entry = match entry { + Some(entry) => entry, + None => try!(visitor.missing_field("entry")), + }; + + let description = match description { + Some(description) => description, + None => try!(visitor.missing_field("description")), + }; + + try!(visitor.end()); + + let task = Task::new( + status, + uuid, + entry, + description, + + annotations, + depends, + due, + end, + imask, + mask, + modified, + parent, + priority, + project, + recur, + scheduled, + start, + tags, + until, + wait + ); + + Ok(task) + } +} + #[cfg(test)] mod test { use date::Date; |