diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2017-02-03 15:33:43 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-02-03 15:33:43 +0100 |
commit | 638e931b2e14c9869f50031bccb73f991c0b9c53 (patch) | |
tree | b6655d6c7c91a5170c6d69778464100d0531ac13 | |
parent | 545531d47a86f348ce96d0f022f32f7ac0358ebc (diff) | |
parent | b586490b2012742bce9d54542cf602eef5f07d7f (diff) |
Merge pull request #46 from matthiasbeyer/update-serde-rust1-15
Update serde for Rust 1.15 (custom derive feature)
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/annotation.rs | 99 | ||||
-rw-r--r-- | src/import.rs | 5 | ||||
-rw-r--r-- | src/lib.rs | 3 | ||||
-rw-r--r-- | src/priority.rs | 62 | ||||
-rw-r--r-- | src/status.rs | 67 | ||||
-rw-r--r-- | src/task.rs | 334 |
7 files changed, 58 insertions, 513 deletions
@@ -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] @@ -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; |