read_url/internal/
internal_url.rs

1use super::{
2    super::{context::*, url::*, util::*},
3    metadata::*,
4};
5
6use std::fmt;
7
8//
9// InternalUrl
10//
11
12/// An internal URL.
13///
14/// The URL scheme is "internal:", followed by a custom path representation.
15///
16/// The [URL::base] and [URL::relative] functions are supported in two modes. When
17/// slashable is true, they will interpret the path as a Unix-style filesystem
18/// path, whereby the path separator is "/", and "." and ".." are supported for path
19/// traversal. When slashable is false, [URL::relative] does simple string concatenation,
20/// and you must explicitly register a base_path if you want to support [URL::base].
21///
22/// [URL::conform] is critical for internal URLs: it makes sure to fill in metadata
23/// from the registry.
24///
25/// If your use case is testing, it could be that [MockUrl](super::super::mock::MockUrl)
26/// would be easier to use, as it is not owned by [UrlContext] and can mock
27/// any scheme.
28#[derive(Clone, Debug)]
29pub struct InternalUrl {
30    /// The path.
31    pub path: String,
32
33    /// Metadata.
34    pub metadata: InternalUrlMetadata,
35
36    /// The optional host (for representation purposes only).
37    pub host: Option<String>,
38
39    /// The optional query.
40    pub query: Option<UrlQuery>,
41
42    /// The optional fragment.
43    pub fragment: Option<String>,
44
45    pub(crate) context: UrlContextRef,
46}
47
48impl InternalUrl {
49    /// Constructor.
50    pub fn new(
51        context: &UrlContextRef,
52        path: String,
53        slashable: bool,
54        base_path: Option<String>,
55        host: Option<String>,
56        query: Option<UrlQuery>,
57        fragment: Option<String>,
58    ) -> Self {
59        Self {
60            path,
61            metadata: InternalUrlMetadata::new(slashable, base_path, None),
62            host,
63            query,
64            fragment,
65            context: context.clone(),
66        }
67    }
68
69    /// Constructor.
70    pub fn new_with(&self, path: String) -> Self {
71        Self::new(&self.context, path, self.metadata.slashable, None, self.host.clone(), None, None)
72    }
73}
74
75impl fmt::Display for InternalUrl {
76    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
77        let host = self.host.clone().unwrap_or_default();
78        let query = url_query_string(&self.query);
79        let fragment = url_fragment_string(&self.fragment);
80
81        write!(formatter, "internal://{}{}{}{}", host, self.path, query, fragment)
82    }
83}
84
85// Conversions
86
87impl Into<UrlRef> for InternalUrl {
88    fn into(self) -> UrlRef {
89        Box::new(self)
90    }
91}