summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2017-02-03 15:33:43 +0100
committerGitHub <noreply@github.com>2017-02-03 15:33:43 +0100
commit638e931b2e14c9869f50031bccb73f991c0b9c53 (patch)
treeb6655d6c7c91a5170c6d69778464100d0531ac13
parent545531d47a86f348ce96d0f022f32f7ac0358ebc (diff)
parentb586490b2012742bce9d54542cf602eef5f07d7f (diff)
Merge pull request #46 from matthiasbeyer/update-serde-rust1-15
Update serde for Rust 1.15 (custom derive feature)
-rw-r--r--Cargo.toml1
-rw-r--r--src/annotation.rs99
-rw-r--r--src/import.rs5
-rw-r--r--src/lib.rs3
-rw-r--r--src/priority.rs62
-rw-r--r--src/status.rs67
-rw-r--r--src/task.rs334
7 files changed, 58 insertions, 513 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 1ee4f2e..e8b63e3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,6 +18,7 @@ license = "MPL-2.0"
chrono = "0.2"
log = "0.3"
serde = "0.9"
+serde_derive = "0.9"
serde_json = "0.9"
uuid = { version = "0.4", features = ["serde"] }
diff --git a/src/annotation.rs b/src/annotation.rs
index a56c41b..5f43e2d 100644
--- a/src/annotation.rs
+++ b/src/annotation.rs
@@ -6,23 +6,12 @@
//! Module containing types and functions for annotations of tasks
-use std::result::Result as RResult;
-use std::fmt::Formatter;
-use std::fmt::Result as FmtResult;
-
-use serde::Serialize;
-use serde::Serializer;
-use serde::Deserialize;
-use serde::Deserializer;
-use serde::de::Visitor;
-use serde::de::MapVisitor as DeserializeMapVisitor;
-
use date::Date;
/// Annotation type for task annotations.
/// Each annotation in taskwarrior consists of a date and a description,
/// the date is named "entry", the description "description" in the JSON export.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Annotation {
entry: Date,
description: String
@@ -50,92 +39,6 @@ impl Annotation {
}
-impl Serialize for Annotation {
-
- fn serialize<S>(&self, serializer: S) -> RResult<S::Ok, S::Error>
- where S: Serializer
- {
- use serde::ser::SerializeStruct;
-
- let mut state = try!(serializer.serialize_struct("Annotation", 2));
- try!(state.serialize_field("entry", &self.entry));
- try!(state.serialize_field("description", &self.description));
- state.end()
- }
-
-}
-
-impl Deserialize for Annotation {
-
- fn deserialize<D>(deserializer: D) -> RResult<Annotation, D::Error>
- where D: Deserializer
- {
- static FIELDS: &'static [&'static str] = &[
- "entry",
- "description"
- ];
-
- deserializer.deserialize_struct("Annotation", FIELDS, AnnotationDeserializeVisitor)
- }
-
-}
-
-/// Helper type for the `Deserialize` implementation
-struct AnnotationDeserializeVisitor;
-
-impl Visitor for AnnotationDeserializeVisitor {
- type Value = Annotation;
-
- fn expecting(&self, fmt: &mut Formatter) -> FmtResult {
- write!(fmt, "a taskwarrior annotation object")
- }
-
- fn visit_map<V>(self, mut visitor: V) -> RResult<Annotation, V::Error>
- where V: DeserializeMapVisitor
- {
- use serde::de::Error;
-
- let mut entry = None;
- let mut description = None;
-
- loop {
- let key : Option<String> = try!(visitor.visit_key());
- if key.is_none() {
- break;
- }
- let key = key.unwrap();
-
- match &key[..] {
- "entry" => {
- entry = Some(try!(visitor.visit_value()));
- },
- "description" => {
- description = Some(try!(visitor.visit_value()));
- },
-
- field => {
- use serde::de::impls::IgnoredAny;
-
- debug!("field '{}' ignored", field);
- let _: IgnoredAny = try!(visitor.visit_value());
- }
- }
- }
-
- let entry = match entry {
- Some(entry) => entry,
- None => return Err(V::Error::missing_field("entry")),
- };
-
- let description = match description {
- Some(description) => description,
- None => return Err(V::Error::missing_field("description")),
- };
-
- Ok(Annotation::new(entry, description))
- }
-}
-
#[cfg(test)]
mod test {
}
diff --git a/src/import.rs b/src/import.rs
index 117be36..20c1405 100644
--- a/src/import.rs
+++ b/src/import.rs
@@ -126,10 +126,7 @@ fn test_two() {
"#;
- let imported = import(s.as_bytes());
- assert!(imported.is_ok());
- let imported = imported.unwrap();
- assert!(imported.len() == 3);
+ assert!(import(s.as_bytes()).unwrap().len() == 3);
}
#[test]
diff --git a/src/lib.rs b/src/lib.rs
index ea484d0..2ed6b3c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -45,8 +45,9 @@
)]
extern crate chrono;
-#[macro_use] extern crate log;
+extern crate log;
extern crate serde;
+#[macro_use] extern crate serde_derive;
extern crate serde_json;
extern crate uuid;
diff --git a/src/priority.rs b/src/priority.rs
index d9a2554..d3fa8f4 100644
--- a/src/priority.rs
+++ b/src/priority.rs
@@ -6,73 +6,19 @@
//! Module containing TaskPriority types and trait impls
-use serde::Serialize;
-use serde::ser::Serializer;
-use serde::de::Deserialize;
-use serde::de::Deserializer;
-use serde::de::Error as DeError;
-use serde::de::Visitor;
-
-use std::fmt::Formatter;
-use std::fmt::Result as FmtResult;
-
/// Enum for the priorities taskwarrior supports.
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum TaskPriority {
/// Low prio for a Task
+ #[serde(rename = "L")]
Low,
/// Medium prio for a Task
+ #[serde(rename = "M")]
Medium,
/// High prio for a Task
+ #[serde(rename = "H")]
High,
}
-
-impl Serialize for TaskPriority {
-
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where S: Serializer
- {
- serializer.serialize_str(
- match self {
- &TaskPriority::Low => "L",
- &TaskPriority::Medium => "M",
- &TaskPriority::High => "H",
- }
- )
- }
-
-}
-
-impl Deserialize for TaskPriority {
-
- fn deserialize<D>(deserializer: D) -> Result<TaskPriority, D::Error>
- where D: Deserializer
- {
- struct TaskPriorityVisitor;
-
- impl Visitor for TaskPriorityVisitor {
- type Value = TaskPriority;
-
- fn expecting(&self, fmt: &mut Formatter) -> FmtResult {
- write!(fmt, "one of 'L', 'M', 'H'")
- }
-
- fn visit_str<E>(self, value: &str) -> Result<TaskPriority, E>
- where E: DeError
- {
- match value {
- "L" => Ok(TaskPriority::Low),
- "M" => Ok(TaskPriority::Medium),
- "H" => Ok(TaskPriority::High),
- _ => Err(DeError::custom("expected one of 'L', 'M', 'H'")),
- }
- }
- }
-
- deserializer.deserialize(TaskPriorityVisitor)
- }
-}
-
diff --git a/src/status.rs b/src/status.rs
index 8cdf420..0bf6cd8 100644
--- a/src/status.rs
+++ b/src/status.rs
@@ -6,33 +6,29 @@
//! Module containing `TaskStatus` type and trait impls
-use std::fmt::{Display, Formatter};
-use std::fmt::Error as FmtError;
-use std::fmt::Result as FmtResult;
-
-use serde::Serialize;
-use serde::Serializer;
-use serde::Deserialize;
-use serde::Deserializer;
-use serde::de::Error;
-use serde::de::Visitor;
+use std::fmt::{Display, Formatter, Error as FmtError};
/// Enum for status taskwarrior supports.
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub enum TaskStatus {
/// Pening status type
+ #[serde(rename = "pending")]
Pending,
/// Deleted status type
+ #[serde(rename = "deleted")]
Deleted,
/// Completed status type
+ #[serde(rename = "completed")]
Completed,
/// Waiting status type
+ #[serde(rename = "waiting")]
Waiting,
/// Recurring status type
+ #[serde(rename = "recurring")]
Recurring
}
@@ -49,52 +45,3 @@ impl Display for TaskStatus {
}
}
-impl Serialize for TaskStatus {
-
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where S: Serializer
- {
- serializer.serialize_str(
- match self {
- &TaskStatus::Pending => "pending",
- &TaskStatus::Deleted => "deleted",
- &TaskStatus::Completed => "completed",
- &TaskStatus::Waiting => "waiting",
- &TaskStatus::Recurring => "recurring",
- }
- )
- }
-
-}
-
-impl Deserialize for TaskStatus {
- fn deserialize<D>(deserializer: D) -> Result<TaskStatus, D::Error>
- where D: Deserializer
- {
- struct TaskStatusVisitor;
-
- impl Visitor for TaskStatusVisitor {
- type Value = TaskStatus;
-
- fn expecting(&self, fmt: &mut Formatter) -> FmtResult {
- write!(fmt, "a taskwarrior status ('pending', 'deleted', ...)")
- }
-
- fn visit_str<E>(self, value: &str) -> Result<TaskStatus, E>
- where E: Error
- {
- match value {
- "pending" => Ok(TaskStatus::Pending),
- "deleted" => Ok(TaskStatus::Deleted),
- "completed" => Ok(TaskStatus::Completed),
- "waiting" => Ok(TaskStatus::Waiting),
- "recurring" => Ok(TaskStatus::Recurring),
- _ => Err(Error::custom("expected one of pending, deleted, completed, waiting, recurring")),
- }
- }
- }
-
- deserializer.deserialize(TaskStatusVisitor)
- }
-}
-
diff --git a/src/task.rs b/src/task.rs
index c28d8ea..70c198b 100644
--- a/src/task.rs
+++ b/src/task.rs
@@ -6,16 +6,6 @@
//! Module containing `Task` type as well as trait implementations
-use std::result::Result as RResult;
-use std::fmt::Formatter;
-use std::fmt::Result as FmtResult;
-
-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;
@@ -39,28 +29,59 @@ 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)]
+#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Task {
status : TaskStatus,
uuid : Uuid,
entry : Date,
description : String,
- annotations : Vec<Annotation>,
+ #[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>,
- tags : Vec<Tag>,
+
+ #[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>,
}
@@ -101,7 +122,7 @@ impl Task {
entry : entry,
description : description,
- annotations : annotations.unwrap_or(vec![]),
+ annotations : annotations,
depends : depends,
due : due,
end : end,
@@ -114,7 +135,7 @@ impl Task {
recur : recur,
scheduled : scheduled,
start : start,
- tags : tags.unwrap_or(vec![]),
+ tags : tags,
until : until,
wait : wait,
}
@@ -142,12 +163,15 @@ impl Task {
/// Get the annotations of the task
pub fn annotations(&self) -> Option<&Vec<Annotation>> {
- Some(&self.annotations)
+ self.annotations.as_ref()
}
/// Add an annotation to this task
pub fn add_annotation(&mut self, an: Annotation) {
- self.annotations.push(an)
+ match self.annotations {
+ None => self.annotations = Some(vec![an]),
+ Some(ref mut n) => n.push(an),
+ }
}
/// Add annotations to this task
@@ -223,7 +247,7 @@ impl Task {
/// Get the tags of the task
pub fn tags(&self) -> Option<&Vec<Tag>> {
- Some(&self.tags)
+ self.tags.as_ref()
}
/// Get the until date of the task
@@ -238,280 +262,6 @@ impl Task {
}
-impl Serialize for Task {
-
- fn serialize<S>(&self, serializer: S) -> RResult<S::Ok, S::Error>
- where S: Serializer
- {
- use serde::ser::SerializeStruct;
-
- let mut state = try!(serializer.serialize_struct("Task", 19));
- try!(state.serialize_field("status", &self.status));
- try!(state.serialize_field("uuid", &self.uuid));
- try!(state.serialize_field("entry", &self.entry));
- try!(state.serialize_field("description", &self.description));
- try!(state.serialize_field("annotations", &self.annotations));
- try!(state.serialize_field("tags", &self.tags));
-
- match self.recur {
- Some(ref v) => try!(state.serialize_field("recur", v)),
- None => { },
- }
- match self.depends {
- Some(ref v) => try!(state.serialize_field("depends", v)),
- None => { },
- }
- match self.due {
- Some(ref v) => try!(state.serialize_field("due", v)),
- None => { },
- }
- match self.end {
- Some(ref v) => try!(state.serialize_field("end", v)),
- None => { },
- }
- match self.imask {
- Some(ref v) => try!(state.serialize_field("imask", v)),
- None => { },
- }
- match self.mask {
- Some(ref v) => try!(state.serialize_field("mask", v)),
- None => { },
- }
- match self.modified {
- Some(ref v) => try!(state.serialize_field("modified", v)),
- None => { },
- }
- match self.parent {
- Some(ref v) => try!(state.serialize_field("parent", v)),
- None => { },
- }
- match self.priority {
- Some(ref v) => try!(state.serialize_field("priority", v)),
- None => { },
- }
- match self.project {
- Some(ref v) => try!(state.serialize_field("project", v)),
- None => { },
- }
- match self.scheduled {
- Some(ref v) => try!(state.serialize_field("scheduled", v)),
- None => { },
- }
- match self.start {
- Some(ref v) => try!(state.serialize_field("start", v)),
- None => { },
- }
- match self.until {
- Some(ref v) => try!(state.serialize_field("until", v)),
- None => { },
- }
- match self.wait {
- Some(ref v) => try!(state.serialize_field("wait", v)),
- None => { },
- }
-
- state.end()
- }
-
-}
-
-impl Deserialize for Task {
-
- fn deserialize<D>(deserializer: 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 expecting(&self, fmt: &mut Formatter) -> FmtResult {
- write!(fmt, "a taskwarrior exported JSON object")
- }
-
- fn visit_map<V>(self, mut visitor: V) -> RResult<Task, V::Error>
- where V: DeserializeMapVisitor
- {
- use serde::de::Error;
-
- 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 => return Err(V::Error::missing_field("status")),
- };
-
- let uuid = match uuid {
- Some(uuid) => uuid,
- None => return Err(V::Error::missing_field("uuid")),
- };
-
- let entry = match entry {
- Some(entry) => entry,
- None => return Err(V::Error::missing_field("entry")),
- };
-
- let description = match description {
- Some(description) => description,
- None => return Err(V::Error::missing_field("description")),
- };
-
- 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;