read_url/url.rs
1use super::context::*;
2
3use std::{collections::*, fmt, io, path::*};
4
5#[cfg(any(feature = "blocking", feature = "async"))]
6use super::errors::*;
7
8#[cfg(feature = "async")]
9use {
10 std::{future::*, pin::*},
11 tokio::io::AsyncRead,
12};
13
14/// Common reference type for [URL].
15pub type UrlRef = Box<dyn URL + Send + Sync>;
16
17/// URL query.
18pub type UrlQuery = HashMap<String, String>;
19
20/// Common reference type for [Read](io::Read).
21pub type ReadRef = Box<dyn io::Read>;
22
23/// Common reference type for [AsyncRead].
24#[cfg(feature = "async")]
25pub type AsyncReadRef = Pin<Box<dyn AsyncRead>>;
26
27/// Common [Future] type for [URL::conform_async].
28#[cfg(feature = "async")]
29pub type ConformFuture = Pin<Box<dyn Future<Output = Result<UrlRef, UrlError>>>>;
30
31/// Common [Future] type for [URL::open_async].
32#[cfg(feature = "async")]
33pub type OpenFuture = Pin<Box<dyn Future<Output = Result<AsyncReadRef, UrlError>>>>;
34
35//
36// URL
37//
38
39/// URL.
40pub trait URL
41where
42 Self: fmt::Debug + fmt::Display,
43{
44 /// The [UrlContext] used to create this URL.
45 fn context(&self) -> &UrlContext;
46
47 /// Returns a string that uniquely identifies the URL.
48 ///
49 /// Useful as a map or cache key.
50 fn key(&self) -> String {
51 format!("{}", self)
52 }
53
54 /// The optional query.
55 fn query(&self) -> Option<UrlQuery> {
56 None
57 }
58
59 /// The optional fragment.
60 fn fragment(&self) -> Option<String> {
61 None
62 }
63
64 /// Format of the URL content's canonical representation.
65 ///
66 /// Can return "text", "yaml", "json", "tar", "tar.gz", etc.
67 ///
68 /// The format is often derived from a file extension if available, otherwise
69 /// it might be retrieved from metadata.
70 ///
71 /// An attempt is made to standardize the return values, e.g. a "yml" file
72 /// extension is always returned as "yaml", and a "tgz" file extension is
73 /// always returned as "tar.gz".
74 fn format(&self) -> Option<String> {
75 None
76 }
77
78 /// If this URL points to a local path, returns it.
79 fn local(&self) -> Option<PathBuf> {
80 None
81 }
82
83 /// Returns a URL that is the equivalent of a "base directory" for the URL.
84 ///
85 /// The base URL will normally *not* have the query and fragment of this URL.
86 ///
87 /// Note that the base might not be readable, e.g. you would not be able to call
88 /// [open](URL::open) on it if it is a filesystem directory.
89 fn base(&self) -> Option<UrlRef> {
90 None
91 }
92
93 /// Parses the argument as a path relative to the URL. That means that this
94 /// URL is treated as a "base directory" (see [base](URL::base)). The argument
95 /// supports ".." and ".", with the returned URL path always being absolute.
96 ///
97 /// The relative URL will normally *not* have the query and fragment of this URL.
98 fn relative(&self, path: &str) -> UrlRef;
99
100 /// Ensures that the URL conforms with the expectations of its functions. If
101 /// successful, this function may change the URL appropriately, e.g. a relative
102 /// path would be turned into an absolute path.
103 ///
104 /// This includes the expectation that [open](URL::open) would minimally succeed,
105 /// e.g. that the file exists or that the network endpoint is responsive. It does
106 /// not otherwise guarantee that reading would be successful.
107 #[cfg(feature = "blocking")]
108 fn conform(&mut self) -> Result<(), UrlError>;
109
110 /// Async version of [URL::conform].
111 ///
112 /// Am important difference is that instead of mutating the URL it returns the
113 /// new conformed version.
114 #[cfg(feature = "async")]
115 fn conform_async(&self) -> Result<ConformFuture, UrlError>;
116
117 /// Opens the URL for reading by providing a `dyn` [Read][io::Read].
118 ///
119 /// Note that for some URLs it may involve lengthy operations, e.g. cloning a
120 /// remote repository, download a file, and/or unpacking an archive.
121 ///
122 /// Thus, an effort is made to not repeat these lengthy operations by caching
123 /// relevant state via the URL's [UrlContext]. For example, when accessing a "git:"
124 /// URL on a remote repository that repository will be cloned locally only if it's
125 /// the first time the repository has been referred to for the [UrlContext].
126 /// Subsequent [open](URL::open) calls for URLs that refer to the same git
127 /// repository will reuse the existing clone.
128 ///
129 /// An effect of this optimization is that you might not be reading the most
130 /// recent version of the resource the URL points to. If that is undesirable,
131 /// call [reset](super::cache::UrlCache::reset) on the [UrlContext] cache.
132 #[cfg(feature = "blocking")]
133 fn open(&self) -> Result<ReadRef, UrlError>;
134
135 /// Async version of [URL::open]. Provides a `dyn` [AsyncRead](tokio::io::AsyncRead).
136 #[cfg(feature = "async")]
137 fn open_async(&self) -> Result<OpenFuture, UrlError>;
138}