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}