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
pub trait Record {
type Read : ::std::io::Read;
type Hash : AsRef<[u8]>;
type Str : AsRef<str>;
type Iter : Iterator<Item=(Self::Str, Self::Read)>;
fn hash(&self) -> Self::Hash;
fn encoded_hash(&self) -> Self::Str;
fn issue_id(&self) -> Self::Str;
fn file_iter(&self) -> Self::Iter;
}
use serde_json::{Value as JsonValue, Map as JsonMap};
use serde::Serializer;
use serde::ser::SerializeStruct;
pub trait RecordExt: Record {
fn has_type<S: AsRef<str>>(&self, typ: S) -> bool {
let len = 6 + typ.as_ref().len();
self.file_iter().any(|(name, _)| {
let name = name.as_ref();
name.len() == len &&
name.starts_with(".type/") &&
name.ends_with(typ.as_ref())
})
}
fn file<S: AsRef<str>>(&self, file: S) -> Option<Self::Read> {
let file = file.as_ref();
self.file_iter().find(|&(ref name, _)| name.as_ref() == file).and_then(|(_, reader)| Some(reader))
}
fn serde_serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where
S: Serializer {
use std::io::Read;
let mut record = serializer.serialize_struct("Record", 2)?;
let mut files = JsonMap::new();
let mut buf = Vec::new();
for (name, mut reader) in self.file_iter() {
let name = name.as_ref().into();
match reader.read_to_end(&mut buf) {
Ok(_) => {
match ::std::str::from_utf8(&buf) {
Err(_) => {
let mut typ = JsonMap::new();
typ.insert("type".into(), JsonValue::String("binary".into()));
files.insert(name, JsonValue::Object(typ));
},
Ok(str) => {
files.insert(name, JsonValue::String(str.into()));
}
}
},
Err(err) => {
let mut error = JsonMap::new();
error.insert("error".into(), JsonValue::String(format!("{}", err)));
files.insert(name, JsonValue::Object(error));
}
}
buf.clear();
}
record.serialize_field("hash", self.encoded_hash().as_ref().into())?;
record.serialize_field("files", &JsonValue::Object(files))?;
record.end()
}
}
impl<T> RecordExt for T where T: Record {}