This repository has been archived by the owner on Oct 23, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 166
/
Copy pathoptions.rs
137 lines (127 loc) · 4.84 KB
/
options.rs
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
134
135
136
137
use crate::v0::support::option_parsing::ParseError;
use std::convert::TryFrom;
#[derive(Debug)]
pub struct RefsOptions {
/// This can start with /ipfs/ but doesn't have to, can continue with paths, if a link cannot
/// be found it's an json error from go-ipfs
pub arg: Vec<String>,
/// This can be used to format the output string into the `{ "Ref": "here" .. }`
pub format: Option<String>,
/// This cannot be used with `format`, prepends "source -> " to the `Ref` response
pub edges: bool,
/// Not sure if this is tested by conformance testing but I'd assume this destinatinos on their
/// first linking.
pub unique: bool,
pub recursive: bool,
// `int` in the docs apparently is platform specific
// go-ipfs only honors this when `recursive` is true.
// go-ipfs treats -2 as -1 when `recursive` is true.
// go-ipfs doesn't use the json return value if this value is too large or non-int
pub max_depth: Option<i64>,
/// Pretty much any other duration, but since we are not using serde, we can just have it
/// directly.
pub timeout: Option<humantime::Duration>,
}
impl RefsOptions {
pub fn max_depth(&self) -> Option<u64> {
if self.recursive {
match self.max_depth {
// zero means do nothing
Some(x) if x >= 0 => Some(x as u64),
_ => None,
}
} else {
// only immediate links after the path
Some(1)
}
}
}
impl<'a> TryFrom<&'a str> for RefsOptions {
type Error = ParseError<'a>;
fn try_from(q: &'a str) -> Result<Self, Self::Error> {
use ParseError::*;
// TODO: check how go-ipfs handles duplicate parameters for non-Vec fields
//
// this manual deserialization is required because `serde_urlencoded` (used by
// warp::query) does not support multiple instances of the same field, nor does
// `serde_qs` (it would support arg[]=...). supporting this in `serde_urlencoded` is
// out of scope; not sure of `serde_qs`.
let parse = url::form_urlencoded::parse(q.as_bytes());
let mut args = Vec::new();
let mut format = None;
let mut timeout: Option<humantime::Duration> = None;
let mut edges = None;
let mut unique = None;
let mut recursive = None;
let mut max_depth = None;
for (key, value) in parse {
let target = match &*key {
"arg" => {
args.push(value.into_owned());
continue;
}
"format" => {
if format.is_none() {
// not parsing this the whole way as there might be hope to have this
// function removed in the future.
format = Some(value.into_owned());
continue;
} else {
return Err(DuplicateField(key));
}
}
"timeout" => {
if timeout.is_none() {
timeout = Some(
value
.parse()
.map_err(|e| ParseError::InvalidDuration("timeout".into(), e))?,
);
continue;
} else {
return Err(DuplicateField(key));
}
}
"max-depth" => {
if max_depth.is_none() {
max_depth = match value.parse::<i64>() {
Ok(max_depth) => Some(max_depth),
Err(_) => return Err(InvalidNumber(key, value)),
};
continue;
} else {
return Err(DuplicateField(key));
}
}
"edges" => &mut edges,
"unique" => &mut unique,
"recursive" => &mut recursive,
_ => {
// ignore unknown fields
continue;
}
};
// common bool field handling
if target.is_none() {
match value.parse::<bool>() {
Ok(value) => *target = Some(value),
Err(_) => return Err(InvalidBoolean(key, value)),
}
} else {
return Err(DuplicateField(key));
}
}
if args.is_empty() {
return Err(MissingArg);
}
Ok(RefsOptions {
arg: args,
format,
edges: edges.unwrap_or(false),
unique: unique.unwrap_or(false),
recursive: recursive.unwrap_or(false),
max_depth,
timeout,
})
}
}