1
/*
2
 * Hurl (https://hurl.dev)
3
 * Copyright (C) 2025 Orange
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *          http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
use std::fmt;
19

            
20
use crate::ast::primitive::{
21
    LineTerminator, Number, Placeholder, SourceInfo, Template, Whitespace, U64,
22
};
23
use crate::typing::{Count, Duration, SourceString, ToSource};
24

            
25
#[derive(Clone, Debug, PartialEq, Eq)]
26
pub struct EntryOption {
27
    pub line_terminators: Vec<LineTerminator>,
28
    pub space0: Whitespace,
29
    pub space1: Whitespace,
30
    pub space2: Whitespace,
31
    pub kind: OptionKind,
32
    pub line_terminator0: LineTerminator,
33
}
34

            
35
#[derive(Clone, Debug, PartialEq, Eq)]
36
pub enum OptionKind {
37
    AwsSigV4(Template),
38
    CaCertificate(Template),
39
    ClientCert(Template),
40
    ClientKey(Template),
41
    Compressed(BooleanOption),
42
    ConnectTo(Template),
43
    ConnectTimeout(DurationOption),
44
    Delay(DurationOption),
45
    Header(Template),
46
    Http10(BooleanOption),
47
    Http11(BooleanOption),
48
    Http2(BooleanOption),
49
    Http3(BooleanOption),
50
    Insecure(BooleanOption),
51
    IpV4(BooleanOption),
52
    IpV6(BooleanOption),
53
    FollowLocation(BooleanOption),
54
    FollowLocationTrusted(BooleanOption),
55
    LimitRate(NaturalOption),
56
    MaxRedirect(CountOption),
57
    MaxTime(DurationOption),
58
    Negotiate(BooleanOption),
59
    NetRc(BooleanOption),
60
    NetRcFile(Template),
61
    NetRcOptional(BooleanOption),
62
    Ntlm(BooleanOption),
63
    Output(Template),
64
    PathAsIs(BooleanOption),
65
    PinnedPublicKey(Template),
66
    Proxy(Template),
67
    Repeat(CountOption),
68
    Resolve(Template),
69
    Retry(CountOption),
70
    RetryInterval(DurationOption),
71
    Skip(BooleanOption),
72
    UnixSocket(Template),
73
    User(Template),
74
    Variable(VariableDefinition),
75
    Verbose(BooleanOption),
76
    VeryVerbose(BooleanOption),
77
}
78

            
79
impl OptionKind {
80
    /// Returns the Hurl string identifier of this option.
81
4620
    pub fn identifier(&self) -> &'static str {
82
4620
        match self {
83
50
            OptionKind::AwsSigV4(_) => "aws-sigv4",
84
75
            OptionKind::CaCertificate(_) => "cacert",
85
80
            OptionKind::ClientCert(_) => "cert",
86
60
            OptionKind::ClientKey(_) => "key",
87
420
            OptionKind::Compressed(_) => "compressed",
88
75
            OptionKind::ConnectTo(_) => "connect-to",
89
40
            OptionKind::ConnectTimeout(_) => "connect-timeout",
90
330
            OptionKind::Delay(_) => "delay",
91
450
            OptionKind::FollowLocation(_) => "location",
92
60
            OptionKind::FollowLocationTrusted(_) => "location-trusted",
93
65
            OptionKind::Header(_) => "header",
94
130
            OptionKind::Http10(_) => "http1.0",
95
100
            OptionKind::Http11(_) => "http1.1",
96
60
            OptionKind::Http2(_) => "http2",
97
40
            OptionKind::Http3(_) => "http3",
98
105
            OptionKind::Insecure(_) => "insecure",
99
40
            OptionKind::IpV4(_) => "ipv4",
100
40
            OptionKind::IpV6(_) => "ipv6",
101
45
            OptionKind::LimitRate(_) => "limit-rate",
102
95
            OptionKind::MaxRedirect(_) => "max-redirs",
103
40
            OptionKind::MaxTime(_) => "max-time",
104
50
            OptionKind::Negotiate(_) => "negotiate",
105
40
            OptionKind::NetRc(_) => "netrc",
106
45
            OptionKind::NetRcFile(_) => "netrc-file",
107
40
            OptionKind::NetRcOptional(_) => "netrc-optional",
108
55
            OptionKind::Ntlm(_) => "ntlm",
109
155
            OptionKind::Output(_) => "output",
110
45
            OptionKind::PathAsIs(_) => "path-as-is",
111
50
            OptionKind::PinnedPublicKey(_) => "pinnedpubkey",
112
80
            OptionKind::Proxy(_) => "proxy",
113
175
            OptionKind::Repeat(_) => "repeat",
114
60
            OptionKind::Resolve(_) => "resolve",
115
160
            OptionKind::Retry(_) => "retry",
116
130
            OptionKind::RetryInterval(_) => "retry-interval",
117
50
            OptionKind::Skip(_) => "skip",
118
40
            OptionKind::UnixSocket(_) => "unix-socket",
119
135
            OptionKind::User(_) => "user",
120
660
            OptionKind::Variable(_) => "variable",
121
190
            OptionKind::Verbose(_) => "verbose",
122
60
            OptionKind::VeryVerbose(_) => "very-verbose",
123
        }
124
    }
125
}
126

            
127
impl fmt::Display for OptionKind {
128
2190
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129
2190
        let value = match self {
130
10
            OptionKind::AwsSigV4(value) => value.to_string(),
131
35
            OptionKind::CaCertificate(filename) => filename.to_string(),
132
20
            OptionKind::ClientCert(filename) => filename.to_string(),
133
20
            OptionKind::ClientKey(filename) => filename.to_string(),
134
285
            OptionKind::Compressed(value) => value.to_string(),
135
35
            OptionKind::ConnectTo(value) => value.to_string(),
136
            OptionKind::ConnectTimeout(value) => value.to_string(),
137
250
            OptionKind::Delay(value) => value.to_string(),
138
310
            OptionKind::FollowLocation(value) => value.to_string(),
139
15
            OptionKind::FollowLocationTrusted(value) => value.to_string(),
140
25
            OptionKind::Header(value) => value.to_string(),
141
60
            OptionKind::Http10(value) => value.to_string(),
142
40
            OptionKind::Http11(value) => value.to_string(),
143
20
            OptionKind::Http2(value) => value.to_string(),
144
            OptionKind::Http3(value) => value.to_string(),
145
45
            OptionKind::Insecure(value) => value.to_string(),
146
            OptionKind::IpV4(value) => value.to_string(),
147
            OptionKind::IpV6(value) => value.to_string(),
148
5
            OptionKind::LimitRate(value) => value.to_string(),
149
45
            OptionKind::MaxRedirect(value) => value.to_string(),
150
            OptionKind::MaxTime(value) => value.to_string(),
151
            OptionKind::Negotiate(value) => value.to_string(),
152
            OptionKind::NetRc(value) => value.to_string(),
153
5
            OptionKind::NetRcFile(filename) => filename.to_string(),
154
            OptionKind::NetRcOptional(value) => value.to_string(),
155
5
            OptionKind::Ntlm(value) => value.to_string(),
156
115
            OptionKind::Output(filename) => filename.to_string(),
157
5
            OptionKind::PathAsIs(value) => value.to_string(),
158
10
            OptionKind::PinnedPublicKey(value) => value.to_string(),
159
30
            OptionKind::Proxy(value) => value.to_string(),
160
105
            OptionKind::Repeat(value) => value.to_string(),
161
20
            OptionKind::Resolve(value) => value.to_string(),
162
55
            OptionKind::Retry(value) => value.to_string(),
163
40
            OptionKind::RetryInterval(value) => value.to_string(),
164
10
            OptionKind::Skip(value) => value.to_string(),
165
            OptionKind::UnixSocket(value) => value.to_string(),
166
65
            OptionKind::User(value) => value.to_string(),
167
410
            OptionKind::Variable(value) => value.to_string(),
168
80
            OptionKind::Verbose(value) => value.to_string(),
169
15
            OptionKind::VeryVerbose(value) => value.to_string(),
170
        };
171
2190
        write!(f, "{}: {}", self.identifier(), value)
172
    }
173
}
174

            
175
#[derive(Clone, Debug, PartialEq, Eq)]
176
pub enum BooleanOption {
177
    Literal(bool),
178
    Placeholder(Placeholder),
179
}
180

            
181
impl fmt::Display for BooleanOption {
182
890
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183
890
        match self {
184
885
            BooleanOption::Literal(v) => write!(f, "{v}"),
185
5
            BooleanOption::Placeholder(v) => write!(f, "{v}"),
186
        }
187
    }
188
}
189

            
190
#[derive(Clone, Debug, PartialEq, Eq)]
191
pub enum NaturalOption {
192
    Literal(U64),
193
    Placeholder(Placeholder),
194
}
195

            
196
impl fmt::Display for NaturalOption {
197
5
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198
5
        match self {
199
5
            NaturalOption::Literal(v) => write!(f, "{v}"),
200
            NaturalOption::Placeholder(v) => write!(f, "{v}"),
201
        }
202
    }
203
}
204

            
205
#[derive(Clone, Debug, PartialEq, Eq)]
206
pub enum CountOption {
207
    Literal(Count),
208
    Placeholder(Placeholder),
209
}
210

            
211
impl fmt::Display for CountOption {
212
205
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213
205
        match self {
214
195
            CountOption::Literal(v) => write!(f, "{v}"),
215
10
            CountOption::Placeholder(v) => write!(f, "{v}"),
216
        }
217
    }
218
}
219

            
220
#[derive(Clone, Debug, PartialEq, Eq)]
221
pub enum DurationOption {
222
    Literal(Duration),
223
    Placeholder(Placeholder),
224
}
225

            
226
impl fmt::Display for DurationOption {
227
290
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228
290
        match self {
229
285
            DurationOption::Literal(v) => write!(f, "{v}"),
230
5
            DurationOption::Placeholder(v) => write!(f, "{v}"),
231
        }
232
    }
233
}
234

            
235
#[derive(Clone, Debug, PartialEq, Eq)]
236
pub struct VariableDefinition {
237
    pub source_info: SourceInfo,
238
    pub name: String,
239
    pub space0: Whitespace,
240
    pub space1: Whitespace,
241
    pub value: VariableValue,
242
}
243

            
244
impl fmt::Display for VariableDefinition {
245
410
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246
410
        write!(f, "{}={}", self.name, self.value)
247
    }
248
}
249

            
250
#[derive(Clone, Debug, PartialEq, Eq)]
251
pub enum VariableValue {
252
    Null,
253
    Bool(bool),
254
    Number(Number),
255
    String(Template),
256
}
257

            
258
impl fmt::Display for VariableValue {
259
410
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
260
410
        let s = match self {
261
            VariableValue::Null => "null".to_string(),
262
5
            VariableValue::Bool(value) => value.to_string(),
263
155
            VariableValue::Number(n) => n.to_string(),
264
250
            VariableValue::String(s) => s.to_string(),
265
        };
266
410
        write!(f, "{s}")
267
    }
268
}
269

            
270
impl ToSource for VariableValue {
271
90
    fn to_source(&self) -> SourceString {
272
90
        match self {
273
10
            VariableValue::Null => "null".to_source(),
274
10
            VariableValue::Bool(value) => value.to_string().to_source(),
275
20
            VariableValue::Number(value) => value.to_source(),
276
50
            VariableValue::String(value) => value.to_source(),
277
        }
278
    }
279
}