parse_dat_url/
lib.rs

1#![doc(html_root_url = "https://docs.rs/parse-dat-url/0.1.0/")]
2#![deny(missing_docs)]
3
4//! # parse-dat-url
5//! url parser to support versioned [dat](https://dat.foundation) URLs
6//!
7//! Useful links:
8//!
9//! - [dat.foundation](https://dat.foundation) - Main webpage
10//! - [How dat works](https://datprotocol.github.io/how-dat-works/) - Detailed Guide
11//! - [datprocol](https://github.com/datprotocol) - Main implementation
12//! - [datrs](https://github.com/datrs/) - Rust implementation
13
14use core::fmt;
15use core::str::FromStr;
16use lazy_static::lazy_static;
17use regex::Regex;
18use std::borrow::Cow;
19use url::Url;
20
21#[cfg(feature = "serde")]
22mod serde;
23
24lazy_static! {
25    static ref VERSION_REGEX: Regex = Regex::new(
26        r#"(?i)^(?P<scheme>\w+://)?(?P<hostname>[^/+]+)(\+(?P<version>[^/]+))?(?P<path>.*)$"#
27    )
28    .expect("Version regex not valid");
29}
30
31/// Possible errors returned by the parsing operation
32#[derive(Debug, Eq, PartialEq)]
33pub enum Error {
34    /// Correspond to invalid regex matching.
35    InvalidRegex,
36    /// Correspond to invalid domain or url, such as bad IPv6 address, or bad encoding on domain names.
37    /// Contains a reference to the original `url` parssing error inside.
38    InvalidUrl(url::ParseError),
39    /// Correspond to missing domain on data.
40    MissingHostname,
41}
42
43impl fmt::Display for Error {
44    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45        match self {
46            Error::InvalidRegex => write!(f, "regex defined on library can't match the value")?,
47            Error::InvalidUrl(_) => write!(f, "malformed url not conforming to URL Spec")?,
48            Error::MissingHostname => write!(f, "missing hostname on url")?,
49        };
50        Ok(())
51    }
52}
53
54impl std::error::Error for Error {}
55
56/// Main structure exported. It holds a reference to the string itself, but it is capable of becoming owned, in order to send it across threads.
57///
58/// It accepts valid urls as well, such as HTTP, domains or IP based URLs. Mal-formed url data might fail, such as bad formatted IPv6 addresses.
59/// It is capable to clone the structure into a onwed reference, as it uses [Cow](std::borrow::Cow) internally.
60///
61/// # Example
62///
63/// ```rust
64/// use parse_dat_url::DatUrl;
65///
66/// if let Ok(dat_url) = DatUrl::parse("dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+0.0.0.1/path/to+file.txt") {
67///   println!("{}", dat_url);
68/// }
69/// ```
70#[derive(Debug, Eq, PartialEq, Clone)]
71pub struct DatUrl<'a> {
72    scheme: Cow<'a, str>,
73    host: Cow<'a, str>,
74    version: Option<Cow<'a, str>>,
75    path: Option<Cow<'a, str>>,
76    url: Url,
77}
78
79impl<'a> fmt::Display for DatUrl<'a> {
80    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81        write!(f, "{}{}", self.scheme, self.host,)?;
82        if let Some(version) = &self.version {
83            write!(f, "+{}", version)?;
84        }
85        if let Some(path) = &self.path {
86            write!(f, "{}", path)?;
87        }
88        Ok(())
89    }
90}
91
92impl<'a> DatUrl<'a> {
93    fn url_str(scheme: &str, host: &str, path: &Option<&str>) -> String {
94        format!("{}{}{}", scheme, host, path.map_or("", |path| &path))
95    }
96
97    /// Main parsing operation. Returns a struct which makes reference to the `&str` passed, with the same lifetime.
98    ///
99    /// It is capable to clone the structure into a onwed reference, as it uses [Cow](std::borrow::Cow) internally.
100    pub fn parse(url: &str) -> Result<DatUrl, Error> {
101        let capture = VERSION_REGEX.captures(url).ok_or(Error::InvalidRegex)?;
102
103        let version = capture.name("version").map(|c| c.as_str());
104
105        let host = capture
106            .name("hostname")
107            .ok_or(Error::MissingHostname)?
108            .as_str();
109
110        let path = capture.name("path").and_then(|c| match c.as_str() {
111            "" => None,
112            s => Some(s),
113        });
114
115        let scheme = capture
116            .name("scheme")
117            .map(|c| c.as_str())
118            .unwrap_or("dat://");
119
120        let valid_url = Url::parse(&DatUrl::url_str(&scheme, &host, &path))
121            .map_err(|e| Error::InvalidUrl(e))?;
122
123        Ok(DatUrl {
124            version: version.map(Cow::from),
125            host: host.into(),
126            path: path.map(Cow::from),
127            scheme: scheme.into(),
128            url: valid_url,
129        })
130    }
131
132    /// Converts a [DatUrl](parse_dat_url::DatUrl) with a `'a` lifetime into a owned struct, with the `'static` lifetime.
133    ///
134    /// ## Examples
135    ///
136    /// ```rust
137    /// # use std::error::Error;
138    /// #
139    /// # fn main() -> Result<(), Box<Error>> {
140    /// #
141    /// use parse_dat_url::{DatUrl, Error};
142    /// // A dynamic URL example.
143    /// let url = String::from("dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+0.0.0.1/path/to+file.txt");
144    /// let dat_url = DatUrl::parse(&url)?;
145    /// let owned_dat_url : DatUrl<'static> = dat_url.into_owned();
146    /// #
147    /// # Ok(())
148    /// # }
149    /// ```
150    pub fn into_owned(self) -> DatUrl<'static> {
151        DatUrl {
152            host: self.host.to_owned().into_owned().into(),
153            scheme: self.scheme.to_owned().into_owned().into(),
154            version: self.version.to_owned().map(|v| v.into_owned().into()),
155            path: self.path.to_owned().map(|p| p.into_owned().into()),
156            url: self.url,
157        }
158    }
159
160    /// Returns a reference to the scheme used on the url. If no scheme is provided on the string, it fallsback to `dat://`
161    #[inline]
162    pub fn scheme(&self) -> &Cow<str> {
163        &self.scheme
164    }
165
166    /// Returns the host part of the url.
167    #[inline]
168    pub fn host(&self) -> &Cow<str> {
169        &self.host
170    }
171
172    /// Returns a reference to the version on the dat url, if present.
173    #[inline]
174    pub fn version(&self) -> &Option<Cow<str>> {
175        &self.version
176    }
177
178    /// Returns a reference to the path on the dat url, if present.
179    #[inline]
180    pub fn path(&self) -> &Option<Cow<str>> {
181        &self.path
182    }
183}
184
185impl<'a> FromStr for DatUrl<'a> {
186    type Err = Error;
187
188    fn from_str(s: &str) -> Result<Self, Self::Err> {
189        DatUrl::parse(s).map(DatUrl::into_owned)
190    }
191}
192
193impl<'a> std::convert::TryFrom<&'a str> for DatUrl<'a> {
194    type Error = Error;
195
196    #[inline]
197    fn try_from(s: &'a str) -> Result<Self, Self::Error> {
198        DatUrl::parse(s)
199    }
200}
201
202impl<'a> AsRef<Url> for DatUrl<'a> {
203    #[inline]
204    fn as_ref(&self) -> &Url {
205        &self.url
206    }
207}
208
209impl<'a> From<DatUrl<'a>> for Url {
210    #[inline]
211    fn from(dat_url: DatUrl<'a>) -> Self {
212        dat_url.url
213    }
214}
215
216#[cfg(test)]
217mod tests {
218    use pretty_assertions::assert_eq;
219
220    use super::DatUrl;
221    use url::Url;
222
223    #[test]
224    fn it_parses_the_urls() {
225        let inputs: &str =
226            "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+0.0.0.1/
227dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+1/
228dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+c1/
229dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+v1/
230dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+v1.0.0/
231dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+latest/
232dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+0.0.0.1/path/to+file.txt
233dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+1/path/to+file.txt
234dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+c1/path/to+file.txt
235dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+v1/path/to+file.txt
236dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+v1.0.0/path/to+file.txt
237dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+latest/path/to+file.txt
238dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+0.0.0.1
239dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+1
240dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+c1
241dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+v1
242dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+v1.0.0
243dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+latest
244dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/
245dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/path/to+file.txt
246dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21
247584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+0.0.0.1/
248584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+1/
249584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+c1/
250584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+v1/
251584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+v1.0.0/
252584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+latest/
253584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+0.0.0.1/path/to+file.txt
254584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+1/path/to+file.txt
255584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+c1/path/to+file.txt
256584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+v1/path/to+file.txt
257584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+v1.0.0/path/to+file.txt
258584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+latest/path/to+file.txt
259584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+0.0.0.1
260584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+1
261584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+c1
262584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+v1
263584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+v1.0.0
264584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21+latest
265584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/
266584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21
267584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/path/to+file.txt
268dat://example.com+0.0.0.1/
269dat://example.com+1/
270dat://example.com+c1/
271dat://example.com+v1/
272dat://example.com+v1.0.0/
273dat://example.com+latest/
274dat://example.com+0.0.0.1/path/to+file.txt
275dat://example.com+1/path/to+file.txt
276dat://example.com+c1/path/to+file.txt
277dat://example.com+v1/path/to+file.txt
278dat://example.com+v1.0.0/path/to+file.txt
279dat://example.com+latest/path/to+file.txt
280dat://example.com+0.0.0.1
281dat://example.com+1
282dat://example.com+c1
283dat://example.com+v1
284dat://example.com+v1.0.0
285dat://example.com+latest
286dat://example.com/
287dat://example.com
288dat://example.com/path/to+file.txt
289example.com+0.0.0.1/
290example.com+1/
291example.com+c1/
292example.com+v1/
293example.com+v1.0.0/
294example.com+latest/
295example.com+0.0.0.1/path/to+file.txt
296example.com+1/path/to+file.txt
297example.com+c1/path/to+file.txt
298example.com+v1/path/to+file.txt
299example.com+v1.0.0/path/to+file.txt
300example.com+latest/path/to+file.txt
301example.com+0.0.0.1
302example.com+1
303example.com+c1
304example.com+v1
305example.com+v1.0.0
306example.com+latest
307example.com/
308example.com
309example.com/path/to+file.txt
310192.0.2.0
311192.0.2.0+v1
312192.0.2.0+0.0.0.1/path/to+file.txt
313192.0.2.0/path/to+file.txt
314[2001:DB8::0]
315[2001:DB8::0]+0.0.0.1/path/to+file.txt";
316
317        let outputs: &[DatUrl] = &[
318            DatUrl {
319                version: Some("0.0.0.1".into()),
320                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
321                path: Some("/".into()),
322                scheme: "dat://".into(),
323                url: Url::parse(
324                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21",
325                )
326                .expect("Invalid test data"),
327            },
328            DatUrl {
329                version: Some("1".into()),
330                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
331                path: Some("/".into()),
332                scheme: "dat://".into(),
333                url: Url::parse(
334                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21",
335                )
336                .expect("Invalid test data"),
337            },
338            DatUrl {
339                version: Some("c1".into()),
340                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
341                path: Some("/".into()),
342                scheme: "dat://".into(),
343                url: Url::parse(
344                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21",
345                )
346                .expect("Invalid test data"),
347            },
348            DatUrl {
349                version: Some("v1".into()),
350                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
351                path: Some("/".into()),
352                scheme: "dat://".into(),
353                url: Url::parse(
354                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21",
355                )
356                .expect("Invalid test data"),
357            },
358            DatUrl {
359                version: Some("v1.0.0".into()),
360                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
361                path: Some("/".into()),
362                scheme: "dat://".into(),
363                url: Url::parse(
364                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21",
365                )
366                .expect("Invalid test data"),
367            },
368            DatUrl {
369                version: Some("latest".into()),
370                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
371                path: Some("/".into()),
372                scheme: "dat://".into(),
373                url: Url::parse(
374                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21",
375                )
376                .expect("Invalid test data"),
377            },
378            DatUrl {
379                version: Some("0.0.0.1".into()),
380                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
381                path: Some("/path/to+file.txt".into()),
382                scheme: "dat://".into(),
383                url: Url::parse(
384                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/path/to+file.txt",
385                )
386                .expect("Invalid test data"),
387            },
388            DatUrl {
389                version: Some("1".into()),
390                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
391                path: Some("/path/to+file.txt".into()),
392                scheme: "dat://".into(),
393                url: Url::parse(
394                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/path/to+file.txt",
395                )
396                .expect("Invalid test data"),
397                },
398            DatUrl {
399                version: Some("c1".into()),
400                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
401                path: Some("/path/to+file.txt".into()),
402                scheme: "dat://".into(),
403                url: Url::parse(
404                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/path/to+file.txt",
405                )
406                .expect("Invalid test data"),
407            },
408            DatUrl {
409                version: Some("v1".into()),
410                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
411                path: Some("/path/to+file.txt".into()),
412                scheme: "dat://".into(),
413                url: Url::parse(
414                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/path/to+file.txt",
415                )
416                .expect("Invalid test data"),
417            },
418            DatUrl {
419                version: Some("v1.0.0".into()),
420                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
421                path: Some("/path/to+file.txt".into()),
422                scheme: "dat://".into(),
423                url: Url::parse(
424                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/path/to+file.txt",
425                )
426                .expect("Invalid test data"),
427            },
428            DatUrl {
429                version: Some("latest".into()),
430                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
431                path: Some("/path/to+file.txt".into()),
432                scheme: "dat://".into(),
433                url: Url::parse(
434                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/path/to+file.txt",
435                )
436                .expect("Invalid test data"),
437            },
438            DatUrl {
439                version: Some("0.0.0.1".into()),
440                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
441                path: None,
442                scheme: "dat://".into(),
443                url: Url::parse(
444                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/",
445                )
446                .expect("Invalid test data"),
447            },
448            DatUrl {
449                version: Some("1".into()),
450                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
451                path: None,
452                scheme: "dat://".into(),
453                url: Url::parse(
454                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/",
455                )
456                .expect("Invalid test data"),
457            },
458            DatUrl {
459                version: Some("c1".into()),
460                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
461                path: None,
462                scheme: "dat://".into(),
463                url: Url::parse(
464                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/",
465                )
466                .expect("Invalid test data"),
467            },
468            DatUrl {
469                version: Some("v1".into()),
470                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
471                path: None,
472                scheme: "dat://".into(),
473                url: Url::parse(
474                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/",
475                )
476                .expect("Invalid test data"),
477            },
478            DatUrl {
479                version: Some("v1.0.0".into()),
480                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
481                path: None,
482                scheme: "dat://".into(),
483                url: Url::parse(
484                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/",
485                )
486                .expect("Invalid test data"),
487            },
488            DatUrl {
489                version: Some("latest".into()),
490                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
491                path: None,
492                scheme: "dat://".into(),
493                url: Url::parse(
494                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/",
495                )
496                .expect("Invalid test data"),
497            },
498            DatUrl {
499                version: None,
500                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
501                path: Some("/".into()),
502                scheme: "dat://".into(),
503                url: Url::parse(
504                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/",
505                )
506                .expect("Invalid test data"), },
507            DatUrl {
508                version: None,
509                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
510                path: Some("/path/to+file.txt".into()),
511                scheme: "dat://".into(),url: Url::parse(
512                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/path/to+file.txt",
513                )
514                .expect("Invalid test data"),
515            },
516            DatUrl {
517                version: None,
518                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
519                path: None,
520                scheme: "dat://".into(),
521                url: Url::parse(
522                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/",
523                )
524                .expect("Invalid test data"),
525            },
526            DatUrl {
527                version: Some("0.0.0.1".into()),
528                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
529                path: Some("/".into()),
530                scheme: "dat://".into(),
531                url: Url::parse(
532                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/",
533                )
534                .expect("Invalid test data"),
535            },
536            DatUrl {
537                version: Some("1".into()),
538                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
539                path: Some("/".into()),
540                scheme: "dat://".into(),
541                url: Url::parse(
542                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/",
543                )
544                .expect("Invalid test data"),
545            },
546            DatUrl {
547                version: Some("c1".into()),
548                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
549                path: Some("/".into()),
550                scheme: "dat://".into(),
551                url: Url::parse(
552                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/",
553                )
554                .expect("Invalid test data"),
555            },
556            DatUrl {
557                version: Some("v1".into()),
558                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
559                path: Some("/".into()),
560                scheme: "dat://".into(),
561                url: Url::parse(
562                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/",
563                )
564                .expect("Invalid test data"),
565            },
566            DatUrl {
567                version: Some("v1.0.0".into()),
568                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
569                path: Some("/".into()),
570                scheme: "dat://".into(),
571                url: Url::parse(
572                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/",
573                )
574                .expect("Invalid test data"),
575            },
576            DatUrl {
577                version: Some("latest".into()),
578                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
579                path: Some("/".into()),
580                scheme: "dat://".into(),
581                url: Url::parse(
582                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/",
583                )
584                .expect("Invalid test data"),
585            },
586            DatUrl {
587                version: Some("0.0.0.1".into()),
588                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
589                path: Some("/path/to+file.txt".into()),
590                scheme: "dat://".into(),
591                url: Url::parse(
592                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/path/to+file.txt",
593                )
594                .expect("Invalid test data"),
595            },
596            DatUrl {
597                version: Some("1".into()),
598                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
599                path: Some("/path/to+file.txt".into()),
600                scheme: "dat://".into(),
601                url: Url::parse(
602                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/path/to+file.txt",
603                )
604                .expect("Invalid test data"),
605            },
606            DatUrl {
607                version: Some("c1".into()),
608                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
609                path: Some("/path/to+file.txt".into()),
610                scheme: "dat://".into(),
611                url: Url::parse(
612                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/path/to+file.txt",
613                )
614                .expect("Invalid test data"),
615            },
616            DatUrl {
617                version: Some("v1".into()),
618                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
619                path: Some("/path/to+file.txt".into()),
620                scheme: "dat://".into(),
621                url: Url::parse(
622                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/path/to+file.txt",
623                )
624                .expect("Invalid test data"),
625            },
626            DatUrl {
627                version: Some("v1.0.0".into()),
628                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
629                path: Some("/path/to+file.txt".into()),
630                scheme: "dat://".into(),
631                url: Url::parse(
632                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/path/to+file.txt",
633                )
634                .expect("Invalid test data"),
635            },
636            DatUrl {
637                version: Some("latest".into()),
638                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
639                path: Some("/path/to+file.txt".into()),
640                scheme: "dat://".into(),
641                url: Url::parse(
642                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/path/to+file.txt",
643                )
644                .expect("Invalid test data"),
645            },
646            DatUrl {
647                version: Some("0.0.0.1".into()),
648                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
649                path: None,
650                scheme: "dat://".into(),
651                url: Url::parse(
652                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21",
653                )
654                .expect("Invalid test data"),
655            },
656            DatUrl {
657                version: Some("1".into()),
658                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
659                path: None,
660                scheme: "dat://".into(),
661                url: Url::parse(
662                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21",
663                )
664                .expect("Invalid test data"),
665
666            },
667            DatUrl {
668                version: Some("c1".into()),
669                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
670                path: None,
671                scheme: "dat://".into(),
672                url: Url::parse(
673                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21",
674                )
675                .expect("Invalid test data"),
676
677            },
678            DatUrl {
679                version: Some("v1".into()),
680                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
681                path: None,
682                scheme: "dat://".into(),
683                url: Url::parse(
684                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21",
685                )
686                .expect("Invalid test data"),
687            },
688            DatUrl {
689                version: Some("v1.0.0".into()),
690                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
691                path: None,
692                scheme: "dat://".into(),
693                url: Url::parse(
694                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21",
695                )
696                .expect("Invalid test data"),
697            },
698            DatUrl {
699                version: Some("latest".into()),
700                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
701                path: None,
702                scheme: "dat://".into(),
703                url: Url::parse(
704                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21",
705                )
706                .expect("Invalid test data"),
707            },
708            DatUrl {
709                version: None,
710                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
711                path: Some("/".into()),
712                scheme: "dat://".into(),
713                url: Url::parse(
714                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21",
715                )
716                .expect("Invalid test data"),
717            },
718            DatUrl {
719                version: None,
720                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
721                path: None,
722                scheme: "dat://".into(),
723                url: Url::parse(
724                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21",
725                )
726                .expect("Invalid test data"),
727            },
728            DatUrl {
729                version: None,
730                host: "584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21".into(),
731                path: Some("/path/to+file.txt".into()),
732                scheme: "dat://".into(),
733                url: Url::parse(
734                    "dat://584faa05d394190ab1a3f0240607f9bf2b7e2bd9968830a11cf77db0cea36a21/path/to+file.txt",
735                )
736                .expect("Invalid test data"),
737            },
738            DatUrl {
739                version: Some("0.0.0.1".into()),
740                host: "example.com".into(),
741                path: Some("/".into()),
742                scheme: "dat://".into(),
743                url: Url::parse(
744                    "dat://example.com",
745                )
746                .expect("Invalid test data"),
747            },
748            DatUrl {
749                version: Some("1".into()),
750                host: "example.com".into(),
751                path: Some("/".into()),
752                scheme: "dat://".into(),
753                url: Url::parse(
754                    "dat://example.com",
755                )
756                .expect("Invalid test data"),
757            },
758            DatUrl {
759                version: Some("c1".into()),
760                host: "example.com".into(),
761                path: Some("/".into()),
762                scheme: "dat://".into(),
763                url: Url::parse(
764                    "dat://example.com",
765                )
766                .expect("Invalid test data"),
767            },
768            DatUrl {
769                version: Some("v1".into()),
770                host: "example.com".into(),
771                path: Some("/".into()),
772                scheme: "dat://".into(),
773                url: Url::parse(
774                    "dat://example.com",
775                )
776                .expect("Invalid test data"),
777            },
778            DatUrl {
779                version: Some("v1.0.0".into()),
780                host: "example.com".into(),
781                path: Some("/".into()),
782                scheme: "dat://".into(),
783                url: Url::parse(
784                    "dat://example.com",
785                )
786                .expect("Invalid test data"),
787            },
788            DatUrl {
789                version: Some("latest".into()),
790                host: "example.com".into(),
791                path: Some("/".into()),
792                scheme: "dat://".into(),
793                url: Url::parse(
794                    "dat://example.com",
795                )
796                .expect("Invalid test data"),
797            },
798            DatUrl {
799                version: Some("0.0.0.1".into()),
800                host: "example.com".into(),
801                path: Some("/path/to+file.txt".into()),
802                scheme: "dat://".into(),
803                url: Url::parse(
804                    "dat://example.com/path/to+file.txt",
805                )
806                .expect("Invalid test data"),
807            },
808            DatUrl {
809                version: Some("1".into()),
810                host: "example.com".into(),
811                path: Some("/path/to+file.txt".into()),
812                scheme: "dat://".into(),
813                url: Url::parse(
814                    "dat://example.com/path/to+file.txt",
815                )
816                .expect("Invalid test data"),
817
818            },
819            DatUrl {
820                version: Some("c1".into()),
821                host: "example.com".into(),
822                path: Some("/path/to+file.txt".into()),
823                scheme: "dat://".into(),
824                url: Url::parse(
825                    "dat://example.com/path/to+file.txt",
826                )
827                .expect("Invalid test data"),
828
829            },
830            DatUrl {
831                version: Some("v1".into()),
832                host: "example.com".into(),
833                path: Some("/path/to+file.txt".into()),
834                scheme: "dat://".into(),
835                url: Url::parse(
836                    "dat://example.com/path/to+file.txt",
837                )
838                .expect("Invalid test data"),
839
840            },
841            DatUrl {
842                version: Some("v1.0.0".into()),
843                host: "example.com".into(),
844                path: Some("/path/to+file.txt".into()),
845                scheme: "dat://".into(),
846                url: Url::parse(
847                    "dat://example.com/path/to+file.txt",
848                )
849                .expect("Invalid test data"),
850
851            },
852            DatUrl {
853                version: Some("latest".into()),
854                host: "example.com".into(),
855                path: Some("/path/to+file.txt".into()),
856                scheme: "dat://".into(),
857                url: Url::parse(
858                    "dat://example.com/path/to+file.txt",
859                )
860                .expect("Invalid test data"),
861
862            },
863            DatUrl {
864                version: Some("0.0.0.1".into()),
865                host: "example.com".into(),
866                path: None,
867                scheme: "dat://".into(),
868                url: Url::parse(
869                    "dat://example.com/",
870                )
871                .expect("Invalid test data"),
872
873            },
874            DatUrl {
875                version: Some("1".into()),
876                host: "example.com".into(),
877                path: None,
878                scheme: "dat://".into(),
879                url: Url::parse(
880                    "dat://example.com/",
881                )
882                .expect("Invalid test data"),
883
884            },
885            DatUrl {
886                version: Some("c1".into()),
887                host: "example.com".into(),
888                path: None,
889                scheme: "dat://".into(),
890                url: Url::parse(
891                    "dat://example.com/",
892                )
893                .expect("Invalid test data"),
894
895            },
896            DatUrl {
897                version: Some("v1".into()),
898                host: "example.com".into(),
899                path: None,
900                scheme: "dat://".into(),
901                url: Url::parse(
902                    "dat://example.com/",
903                )
904                .expect("Invalid test data"),
905
906            },
907            DatUrl {
908                version: Some("v1.0.0".into()),
909                host: "example.com".into(),
910                path: None,
911                scheme: "dat://".into(),
912                url: Url::parse(
913                    "dat://example.com/",
914                )
915                .expect("Invalid test data"),
916
917            },
918            DatUrl {
919                version: Some("latest".into()),
920                host: "example.com".into(),
921                path: None,
922                scheme: "dat://".into(),
923                url: Url::parse(
924                    "dat://example.com/",
925                )
926                .expect("Invalid test data"),
927
928            },
929            DatUrl {
930                version: None,
931                host: "example.com".into(),
932                path: Some("/".into()),
933                scheme: "dat://".into(),
934                url: Url::parse(
935                    "dat://example.com/",
936                )
937                .expect("Invalid test data"),
938
939            },
940            DatUrl {
941                version: None,
942                host: "example.com".into(),
943                path: None,
944                scheme: "dat://".into(),
945                url: Url::parse(
946                    "dat://example.com/",
947                )
948                .expect("Invalid test data"),
949
950            },
951            DatUrl {
952                version: None,
953                host: "example.com".into(),
954                path: Some("/path/to+file.txt".into()),
955                scheme: "dat://".into(),
956                url: Url::parse(
957                    "dat://example.com/path/to+file.txt",
958                )
959                .expect("Invalid test data"),
960
961            },
962            DatUrl {
963                version: Some("0.0.0.1".into()),
964                host: "example.com".into(),
965                path: Some("/".into()),
966                scheme: "dat://".into(),
967                url: Url::parse(
968                    "dat://example.com/",
969                )
970                .expect("Invalid test data"),
971
972            },
973            DatUrl {
974                version: Some("1".into()),
975                host: "example.com".into(),
976                path: Some("/".into()),
977                scheme: "dat://".into(),
978                url: Url::parse(
979                    "dat://example.com/",
980                )
981                .expect("Invalid test data"),
982
983            },
984            DatUrl {
985                version: Some("c1".into()),
986                host: "example.com".into(),
987                path: Some("/".into()),
988                scheme: "dat://".into(),
989                url: Url::parse(
990                    "dat://example.com/",
991                )
992                .expect("Invalid test data"),
993
994            },
995            DatUrl {
996                version: Some("v1".into()),
997                host: "example.com".into(),
998                path: Some("/".into()),
999                scheme: "dat://".into(),
1000                url: Url::parse(
1001                    "dat://example.com/",
1002                )
1003                .expect("Invalid test data"),
1004            },
1005            DatUrl {
1006                version: Some("v1.0.0".into()),
1007                host: "example.com".into(),
1008                path: Some("/".into()),
1009                scheme: "dat://".into(),
1010                url: Url::parse(
1011                    "dat://example.com/",
1012                )
1013                .expect("Invalid test data"),
1014            },
1015            DatUrl {
1016                version: Some("latest".into()),
1017                host: "example.com".into(),
1018                path: Some("/".into()),
1019                scheme: "dat://".into(),
1020                url: Url::parse(
1021                    "dat://example.com/",
1022                )
1023                .expect("Invalid test data"),
1024            },
1025            DatUrl {
1026                version: Some("0.0.0.1".into()),
1027                host: "example.com".into(),
1028                path: Some("/path/to+file.txt".into()),
1029                scheme: "dat://".into(),
1030                url: Url::parse(
1031                    "dat://example.com/path/to+file.txt",
1032                )
1033                .expect("Invalid test data"),
1034            },
1035            DatUrl {
1036                version: Some("1".into()),
1037                host: "example.com".into(),
1038                path: Some("/path/to+file.txt".into()),
1039                scheme: "dat://".into(),
1040   url: Url::parse(
1041                    "dat://example.com/path/to+file.txt",
1042                )
1043                .expect("Invalid test data"),
1044            },
1045            DatUrl {
1046                version: Some("c1".into()),
1047                host: "example.com".into(),
1048                path: Some("/path/to+file.txt".into()),
1049                scheme: "dat://".into(),
1050                url: Url::parse(
1051                    "dat://example.com/path/to+file.txt",
1052                )
1053                .expect("Invalid test data"),
1054            },
1055            DatUrl {
1056                version: Some("v1".into()),
1057                host: "example.com".into(),
1058                path: Some("/path/to+file.txt".into()),
1059                scheme: "dat://".into(),
1060                url: Url::parse(
1061                    "dat://example.com/path/to+file.txt",
1062                )
1063                .expect("Invalid test data"),
1064            },
1065            DatUrl {
1066                version: Some("v1.0.0".into()),
1067                host: "example.com".into(),
1068                path: Some("/path/to+file.txt".into()),
1069                scheme: "dat://".into(),
1070                url: Url::parse(
1071                    "dat://example.com/path/to+file.txt",
1072                )
1073                .expect("Invalid test data"),
1074            },
1075            DatUrl {
1076                version: Some("latest".into()),
1077                host: "example.com".into(),
1078                path: Some("/path/to+file.txt".into()),
1079                scheme: "dat://".into(),
1080                url: Url::parse(
1081                    "dat://example.com/path/to+file.txt",
1082                )
1083                .expect("Invalid test data"),
1084            },
1085            DatUrl {
1086                version: Some("0.0.0.1".into()),
1087                host: "example.com".into(),
1088                path: None,
1089                scheme: "dat://".into(),
1090                url: Url::parse(
1091                    "dat://example.com/",
1092                )
1093                .expect("Invalid test data"),
1094            },
1095            DatUrl {
1096                version: Some("1".into()),
1097                host: "example.com".into(),
1098                path: None,
1099                scheme: "dat://".into(),
1100                url: Url::parse(
1101                    "dat://example.com/",
1102                )
1103                .expect("Invalid test data"),
1104            },
1105            DatUrl {
1106                version: Some("c1".into()),
1107                host: "example.com".into(),
1108                path: None,
1109                scheme: "dat://".into(),
1110                url: Url::parse(
1111                    "dat://example.com/",
1112                )
1113                .expect("Invalid test data"),
1114            },
1115            DatUrl {
1116                version: Some("v1".into()),
1117                host: "example.com".into(),
1118                path: None,
1119                scheme: "dat://".into(),
1120                url: Url::parse(
1121                    "dat://example.com/",
1122                )
1123                .expect("Invalid test data"),
1124            },
1125            DatUrl {
1126                version: Some("v1.0.0".into()),
1127                host: "example.com".into(),
1128                path: None,
1129                scheme: "dat://".into(),
1130                url: Url::parse(
1131                    "dat://example.com/",
1132                )
1133                .expect("Invalid test data"),
1134            },
1135            DatUrl {
1136                version: Some("latest".into()),
1137                host: "example.com".into(),
1138                path: None,
1139                scheme: "dat://".into(),
1140                url: Url::parse(
1141                    "dat://example.com/",
1142                )
1143                .expect("Invalid test data"),
1144            },
1145            DatUrl {
1146                version: None,
1147                host: "example.com".into(),
1148                path: Some("/".into()),
1149                scheme: "dat://".into(),
1150                url: Url::parse(
1151                    "dat://example.com/",
1152                )
1153                .expect("Invalid test data"),
1154            },
1155            DatUrl {
1156                version: None,
1157                host: "example.com".into(),
1158                path: None,
1159                scheme: "dat://".into(),
1160                url: Url::parse(
1161                    "dat://example.com/",
1162                )
1163                .expect("Invalid test data"),
1164            },
1165            DatUrl {
1166                version: None,
1167                host: "example.com".into(),
1168                path: Some("/path/to+file.txt".into()),
1169                scheme: "dat://".into(),
1170                url: Url::parse(
1171                    "dat://example.com/path/to+file.txt",
1172                )
1173                .expect("Invalid test data"),
1174            },
1175            DatUrl {
1176                version: None,
1177                host: "192.0.2.0".into(),
1178                path: None,
1179                scheme: "dat://".into(),
1180                url: Url::parse(
1181                    "dat://192.0.2.0",
1182                )
1183                .expect("Invalid test data"),
1184            },
1185            DatUrl {
1186                version: Some("v1".into()),
1187                host: "192.0.2.0".into(),
1188                path: None,
1189                scheme: "dat://".into(),
1190                url: Url::parse(
1191                    "dat://192.0.2.0",
1192                )
1193                .expect("Invalid test data"),
1194            },
1195            DatUrl {
1196                version: Some("0.0.0.1".into()),
1197                host: "192.0.2.0".into(),
1198                path: Some("/path/to+file.txt".into()),
1199                scheme: "dat://".into(),
1200                url: Url::parse(
1201                    "dat://192.0.2.0/path/to+file.txt",
1202                )
1203                .expect("Invalid test data"),
1204            },
1205            DatUrl {
1206                version: None,
1207                host: "192.0.2.0".into(),
1208                path: Some("/path/to+file.txt".into()),
1209                scheme: "dat://".into(),
1210                url: Url::parse(
1211                    "dat://192.0.2.0/path/to+file.txt",
1212                )
1213                .expect("Invalid test data"),
1214            },
1215            DatUrl {
1216                version: None,
1217                host: "[2001:DB8::0]".into(),
1218                path: None,
1219                scheme: "dat://".into(),
1220                url: Url::parse(
1221                    "dat://[2001:DB8::0]",
1222                )
1223                .expect("Invalid test data"),
1224            },
1225            DatUrl {
1226                version: Some("0.0.0.1".into()),
1227                host: "[2001:DB8::0]".into(),
1228                path: Some("/path/to+file.txt".into()),
1229                scheme: "dat://".into(),
1230                url: Url::parse(
1231                    "dat://[2001:DB8::0]/path/to+file.txt",
1232                )
1233                .expect("Invalid test data"),
1234            },
1235        ];
1236
1237        for (url, output) in inputs.lines().zip(outputs) {
1238            assert_eq!(&DatUrl::parse(url).expect("Invalid test data"), output);
1239        }
1240        // assert_eq!(inputs.lines().count(), outputs.len());
1241    }
1242}