summaryrefslogtreecommitdiffstats
path: root/src/annotation.rs
blob: b2b3b8ae03e3fc0a25add6c3ecf07e57a00a6237 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//
// 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 types and functions for annotations of tasks

use std::result::Result as RResult;

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)]
pub struct Annotation {
    entry: Date,
    description: String
}

impl Annotation {

    /// Create a new Annotation object
    pub fn new(entry: Date, description: String) -> Annotation {
        Annotation {
            entry: entry,
            description: description,
        }
    }

    /// Get the entry date
    pub fn entry(&self) -> &Date {
        &self.entry
    }

    /// Get the description text
    pub fn description(&self) -> &String {
        &self.description
    }

}

impl Serialize for Annotation {

    fn serialize<S>(&self, serializer: &mut S) -> RResult<(), S::Error>
        where S: Serializer
    {
        let mut state = try!(serializer.serialize_struct("Annotation", 2));
        try!(serializer.serialize_struct_elt(&mut state, "entry", &self.entry));
        try!(serializer.serialize_struct_elt(&mut state, "description", &self.description));
        serializer.serialize_struct_end(state)
    }

}

impl Deserialize for Annotation {

    fn deserialize<D>(deserializer: &mut 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 visit_map<V>(&mut self, mut visitor: V) -> RResult<Annotation, V::Error>
        where V: DeserializeMapVisitor
    {
        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 => try!(visitor.missing_field("entry")),
        };

        let description = match description {
            Some(description) => description,
            None => try!(visitor.missing_field("description")),
        };

        try!(visitor.end());

        Ok(Annotation::new(entry, description))
    }
}

#[cfg(test)]
mod test {
}