nix_uri/flakeref/
resource_url.rs1use std::fmt::Display;
2
3use serde::{Deserialize, Serialize};
4use winnow::{
5 ModalResult, Parser,
6 combinator::{alt, opt},
7 error::StrContext,
8 token::take_till,
9};
10
11use crate::{error::tag, parser::parse_sep};
12
13use super::{RefLocation, TransportLayer};
14
15#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
30#[non_exhaustive]
31pub struct ResourceUrl {
32 pub res_type: ResourceType,
33 pub location: String,
34 pub transport_type: Option<TransportLayer>,
35 pub ref_: Option<String>,
36 pub rev: Option<String>,
37 pub ref_location: RefLocation,
38}
39
40impl ResourceUrl {
41 pub fn new(
45 res_type: ResourceType,
46 location: String,
47 transport_type: Option<TransportLayer>,
48 ) -> Self {
49 Self {
50 res_type,
51 location,
52 transport_type,
53 ref_: None,
54 rev: None,
55 ref_location: RefLocation::PathComponent,
56 }
57 }
58
59 #[allow(dead_code)]
60 pub(crate) fn parse(input: &mut &str) -> ModalResult<Self> {
61 let res_type = ResourceType::parse(input)?;
62 let transport_type = opt(TransportLayer::plus_parse).parse_next(input)?;
63 let _ = parse_sep(input)?;
64 let location = take_till(0.., |c| c == '#' || c == '?')
65 .context(StrContext::Label("url location"))
66 .parse_next(input)?;
67 Ok(Self::new(res_type, location.to_string(), transport_type))
68 }
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
75#[non_exhaustive]
76pub enum ResourceType {
77 Git,
78 Mercurial,
79 File,
80 Tarball,
81}
82
83impl ResourceType {
84 #[allow(dead_code)]
85 pub(crate) fn parse(input: &mut &str) -> ModalResult<Self> {
86 alt((
87 tag("git").value(Self::Git),
88 tag("hg").value(Self::Mercurial),
89 tag("file").value(Self::File),
90 tag("tarball").value(Self::Tarball),
91 ))
92 .context(StrContext::Label("resource selection"))
93 .parse_next(input)
94 }
95}
96
97impl Display for ResourceType {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 let out_str = match self {
100 Self::Git => "git",
101 Self::Mercurial => "hg",
102 Self::File => "file",
103 Self::Tarball => "tarball",
104 };
105 write!(f, "{}", out_str)
106 }
107}
108
109#[cfg(test)]
110mod res_url {
111 use cool_asserts::assert_matches;
112
113 use super::*;
114
115 #[test]
116 fn git() {
117 let url = "gitfoobar";
118 let (rest, parsed) = ResourceType::parse.parse_peek(url).unwrap();
119 let expected = ResourceType::Git;
120 assert_eq!(expected, parsed);
121 assert_eq!("foobar", rest);
122 }
123
124 #[test]
125 fn unknown_resource_scheme_routes_to_uri_type_unsupported() {
126 use crate::{NixUriError, error::UnsupportedReason, parser::parse_nix_uri};
127
128 assert_matches!(
129 parse_nix_uri("gat://x"),
130 Err(NixUriError::Unsupported(UnsupportedReason::UriType { ty }))
131 => assert_eq!(ty, "gat")
132 );
133 }
134}