1use serde_json;
4use uuid::Uuid;
5
6use dev_prefix::*;
7use types::*;
8use cmd::check;
9use utils::UUID;
10
11#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
12pub struct LocData {
13 pub path: String,
14 pub line: u64,
15}
16
17#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
18pub struct ArtifactData {
19 pub id: u64,
20 pub revision: u64,
21 pub name: String,
22 pub def: String,
23 pub text: String,
24 pub partof: Vec<String>,
25
26 #[serde(default)] pub parts: Vec<String>,
29 #[serde(default)] pub code: Option<LocData>,
30 #[serde(default)] pub done: Option<String>,
31 #[serde(default = "default_comp_tested")] pub completed: f32,
32 #[serde(default = "default_comp_tested")] pub tested: f32,
33}
34
35#[derive(Serialize, Debug, Default, Clone, PartialEq)]
36pub struct ProjectData {
37 pub artifacts: Vec<ArtifactData>,
38 pub files: Vec<String>,
39 pub checked: String,
40 pub uuid: Uuid,
41}
42
43fn default_comp_tested() -> f32 {
44 -1.0_f32
45}
46
47impl Project {
48 pub fn to_data(&self) -> ProjectData {
49 let artifacts = self.artifacts
50 .iter()
51 .map(|(n, a)| a.to_data(&self.origin, n))
52 .collect();
53
54 let files: Vec<String> = self.files
55 .iter()
56 .map(|p| {
57 p.strip_prefix(&self.origin)
58 .expect("origin invalid")
59 .to_string_lossy()
60 .to_string()
61 })
62 .collect();
63
64 let mut checked: Vec<u8> = Vec::new();
65 let cmd = check::Cmd { color: false };
66
67 check::display_check(&mut checked, &self.origin, self, &cmd);
68
69 ProjectData {
70 artifacts: artifacts,
71 files: files,
72 checked: String::from_utf8(checked).expect("invalid-utf8 from checked"),
73 uuid: *UUID,
74 }
75 }
76}
77
78impl Artifact {
79 pub fn to_data(&self, origin: &Path, name: &NameRc) -> ArtifactData {
81 let (code, done) = match self.done {
82 Done::Code(ref l) => (
83 Some(LocData {
84 path: l.path
85 .strip_prefix(origin)
86 .expect("origin invalid")
87 .to_string_lossy()
88 .to_string(),
89 line: l.line as u64,
90 }),
91 None,
92 ),
93 Done::Defined(ref s) => (None, Some(s.clone())),
94 Done::NotDone => (None, None),
95 };
96 let mut partof: Vec<_> = self.partof.iter().map(|n| n.raw.clone()).collect();
97 let mut parts: Vec<_> = self.parts.iter().map(|n| n.raw.clone()).collect();
98
99 partof.sort();
100 parts.sort();
101 let path = self.def
102 .strip_prefix(origin)
103 .expect("origin invalid")
104 .to_string_lossy()
105 .to_string();
106
107 ArtifactData {
108 id: self.id,
109 revision: self.revision,
110 name: name.raw.clone(),
111 def: path,
112 text: self.text.clone(),
113 partof: partof,
114 parts: parts,
115 code: code,
116 done: done,
117 completed: self.completed,
118 tested: self.tested,
119 }
120 }
121
122 pub fn from_data(repo: &Path, data: &ArtifactData) -> Result<(NameRc, Artifact)> {
124 let name = try!(NameRc::from_str(&data.name));
125 let mut partof: HashSet<NameRc> = HashSet::new();
126 for p in &data.partof {
127 let pname = try!(NameRc::from_str(p));
128 partof.insert(pname);
129 }
130 let done = if data.done.is_some() && data.code.is_some() {
131 let msg = "has both done and code defined".to_string();
132 return Err(ErrorKind::InvalidArtifact(data.name.clone(), msg).into());
133 } else if let Some(ref d) = data.done {
134 if d == "" {
135 return Err(
136 ErrorKind::InvalidAttr(
137 name.to_string(),
138 "done cannot be an empty string.".to_string(),
139 ).into(),
140 );
141 }
142 Done::Defined(d.clone())
143 } else if let Some(ref c) = data.code {
144 Done::Code(Loc {
145 path: repo.join(&c.path),
146 line: c.line as usize,
147 })
148 } else {
149 Done::NotDone
150 };
151
152 Ok((
153 name,
154 Artifact {
155 id: data.id,
156 revision: data.revision,
157 def: repo.join(&data.def),
158 text: data.text.clone(),
159 partof: partof,
160 done: done,
161 parts: HashSet::new(),
162 completed: -1.0,
163 tested: -1.0,
164 },
165 ))
166 }
167}
168
169pub fn project_artifacts_to_json(project: &Project, names: Option<&[NameRc]>) -> String {
171 let out_arts: Vec<_> = if let Some(names) = names {
172 names
173 .iter()
174 .map(|n| project.artifacts[n].to_data(&project.origin, n))
175 .collect()
176 } else {
177 project
178 .artifacts
179 .iter()
180 .map(|(n, a)| a.to_data(&project.origin, n))
181 .collect()
182 };
183
184 let value = serde_json::to_value(out_arts).unwrap();
185 serde_json::to_string(&value).unwrap()
186}
187
188#[test]
189fn test_serde() {
190 let artifact = ArtifactData {
191 id: 10,
192 revision: 0,
193 name: "name".to_string(),
194 def: "path".to_string(),
195 text: "text".to_string(),
196 partof: Vec::from_iter(vec!["partof-1".to_string()]),
197 parts: Vec::from_iter(vec!["part-1".to_string()]),
198 done: None,
199 code: Some(LocData {
200 path: "path".to_string(),
201 line: 10,
202 }),
203 completed: 0.,
204 tested: 0.,
205 };
206
207 let serialized = serde_json::to_string(&artifact).unwrap();
208 let deserialized: ArtifactData = serde_json::from_str(&serialized).unwrap();
209
210 assert_eq!(artifact, deserialized);
211
212
213 }