fuchsia_url/
builtin_url.rs1pub use crate::errors::ParseError;
6use crate::{Scheme, UrlParts};
7
8pub const SCHEME: &str = "fuchsia-builtin";
9
10#[derive(Clone, Debug, PartialEq, Eq)]
19pub struct BuiltinUrl {
20 resource: Option<crate::Resource>,
21}
22
23impl BuiltinUrl {
24 pub fn parse(input: &str) -> Result<Self, ParseError> {
25 Self::try_from_parts(UrlParts::parse(input)?)
26 }
27
28 fn try_from_parts(
29 UrlParts { scheme, host, path, hash, resource }: UrlParts,
30 ) -> Result<Self, ParseError> {
31 if scheme.ok_or(ParseError::MissingScheme)? != Scheme::Builtin {
32 return Err(ParseError::InvalidScheme);
33 }
34
35 if host.is_some() {
36 return Err(ParseError::HostMustBeEmpty);
37 }
38
39 if hash.is_some() {
40 return Err(ParseError::CannotContainHash);
41 }
42
43 if path.is_some() {
44 return Err(ParseError::PathMustBeRoot);
45 }
46
47 Ok(Self { resource })
48 }
49
50 pub fn resource(&self) -> Option<&crate::Resource> {
51 self.resource.as_ref()
52 }
53}
54
55impl std::fmt::Display for BuiltinUrl {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 write!(f, "{}://", SCHEME)?;
58 if let Some(ref resource) = self.resource {
59 write!(f, "#{}", resource.percent_encode())?;
60 }
61 Ok(())
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68 use crate::errors::PackagePathSegmentError;
69 use crate::resource::ResourcePathError;
70 use assert_matches::assert_matches;
71
72 #[test]
73 fn test_parse_ok() {
74 assert_eq!(BuiltinUrl::parse("fuchsia-builtin://").unwrap().resource(), None);
75 assert_eq!(
76 BuiltinUrl::parse("fuchsia-builtin://#a").unwrap().resource().map(|r| r.as_ref()),
77 Some("a")
78 );
79 assert_eq!(
80 BuiltinUrl::parse("fuchsia-builtin://#elf_runner.cm")
81 .unwrap()
82 .resource()
83 .map(|r| r.as_ref()),
84 Some("elf_runner.cm")
85 );
86 }
87
88 #[test]
89 fn test_parse_error_wrong_scheme() {
90 assert_matches!(BuiltinUrl::parse("foobar://").unwrap_err(), ParseError::InvalidScheme);
91 assert_matches!(
92 BuiltinUrl::parse("fuchsia-boot://").unwrap_err(),
93 ParseError::InvalidScheme
94 );
95 assert_matches!(
96 BuiltinUrl::parse("fuchsia-pkg://").unwrap_err(),
97 ParseError::InvalidScheme
98 );
99 }
100
101 #[test]
102 fn test_parse_error_missing_scheme() {
103 assert_matches!(BuiltinUrl::parse("package").unwrap_err(), ParseError::MissingScheme);
104 }
105
106 #[test]
107 fn test_parse_error_invalid_path() {
108 assert_matches!(
109 BuiltinUrl::parse("fuchsia-builtin:////").unwrap_err(),
110 ParseError::InvalidPathSegment(PackagePathSegmentError::Empty)
111 );
112 }
113
114 #[test]
115 fn test_parse_error_invalid_character() {
116 assert_matches!(
117 BuiltinUrl::parse("fuchsia-builtin:///package:1234").unwrap_err(),
118 ParseError::InvalidPathSegment(PackagePathSegmentError::InvalidCharacter {
119 character: ':'
120 })
121 );
122 }
123
124 #[test]
125 fn test_parse_error_host_must_be_empty() {
126 assert_matches!(
127 BuiltinUrl::parse("fuchsia-builtin://hello").unwrap_err(),
128 ParseError::HostMustBeEmpty
129 );
130 }
131
132 #[test]
133 fn test_parse_error_resource_cannot_be_slash() {
134 assert_matches!(
135 BuiltinUrl::parse("fuchsia-builtin://#/").unwrap_err(),
136 ParseError::InvalidResourcePath(ResourcePathError::PathStartsWithSlash)
137 );
138 }
139}