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
//! Hurl common types.
19
use core::fmt;
20
use std::borrow::Borrow;
21
use std::str::FromStr;
22

            
23
use crate::ast::U64;
24

            
25
/// Represents a count operation, either finite or infinite.
26
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
27
pub enum Count {
28
    Finite(usize),
29
    Infinite,
30
}
31

            
32
impl fmt::Display for Count {
33
180
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34
180
        match self {
35
170
            Count::Finite(n) => {
36
170
                write!(f, "{n}")
37
            }
38
            Count::Infinite => {
39
10
                write!(f, "-1")
40
            }
41
        }
42
    }
43
}
44

            
45
/// Represent a duration
46
#[derive(Clone, Debug, PartialEq, Eq)]
47
pub struct Duration {
48
    pub value: U64,
49
    pub unit: Option<DurationUnit>,
50
}
51

            
52
impl Duration {
53
305
    pub fn new(value: U64, unit: Option<DurationUnit>) -> Duration {
54
305
        Duration { value, unit }
55
    }
56
}
57

            
58
impl fmt::Display for Duration {
59
175
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60
175
        let unit = if let Some(value) = self.unit {
61
175
            value.to_string()
62
        } else {
63
            String::new()
64
        };
65
175
        write!(f, "{}{unit}", self.value)
66
    }
67
}
68

            
69
/// Represents a duration unit
70
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
71
pub enum DurationUnit {
72
    MilliSecond,
73
    Second,
74
    Minute,
75
}
76

            
77
impl fmt::Display for DurationUnit {
78
285
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79
285
        match self {
80
225
            DurationUnit::MilliSecond => write!(f, "ms"),
81
60
            DurationUnit::Second => write!(f, "s"),
82
            DurationUnit::Minute => write!(f, "m"),
83
        }
84
    }
85
}
86

            
87
impl FromStr for DurationUnit {
88
    type Err = String;
89

            
90
295
    fn from_str(s: &str) -> Result<Self, Self::Err> {
91
295
        match s {
92
295
            "ms" => Ok(DurationUnit::MilliSecond),
93
75
            "s" => Ok(DurationUnit::Second),
94
5
            "m" => Ok(DurationUnit::Minute),
95
5
            x => Err(format!("Invalid duration unit {x}")),
96
        }
97
    }
98
}
99

            
100
/// Represents bit rate.
101
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
102
pub struct BytesPerSec(pub u64);
103

            
104
impl fmt::Display for BytesPerSec {
105
10
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106
10
        write!(f, "{}", self.0)
107
    }
108
}
109

            
110
/// Represents a source string, in Hurl file format.
111
///
112
/// For instance, with this Hurl file:
113
///
114
/// ```hurl
115
/// GET https://example.org/api
116
/// HTTP 200
117
/// [Asserts]
118
/// jsonpath "$.slideshow.title" == "A beautiful \u{2708}!"
119
/// ```
120
///
121
/// `"A beautiful \u{2708}!"` is the source string, using a [Hurl Unicode literal](https://hurl.dev/docs/hurl-file.html#special-characters-in-strings).
122
/// It's string value is `A beautiful ✈!`.
123
#[derive(Clone, Debug, Default, PartialEq, Eq)]
124
pub struct SourceString(String);
125

            
126
impl SourceString {
127
    /// Creates a new empty [`SourceString`].
128
69545
    pub fn new() -> Self {
129
69545
        SourceString(String::new())
130
    }
131

            
132
    /// Appends a given string slice onto the end of this [`SourceString`].
133
1038735
    pub fn push_str(&mut self, string: &str) {
134
1038735
        self.0.push_str(string);
135
    }
136

            
137
    /// Appends the given char to the end of this [`SourceString`].
138
21075
    pub fn push(&mut self, c: char) {
139
21075
        self.0.push(c);
140
    }
141

            
142
    /// Extracts a string slice containing the entire [`SourceString`].
143
22610
    pub fn as_str(&self) -> &str {
144
22610
        self.0.as_str()
145
    }
146

            
147
    /// Returns `true` if this [`SourceString`] starts with the char `c`.
148
33205
    pub fn starts_with(&self, c: char) -> bool {
149
33205
        self.0.starts_with(c)
150
    }
151
}
152

            
153
pub trait ToSource {
154
    fn to_source(&self) -> SourceString;
155
}
156

            
157
impl ToSource for String {
158
50325
    fn to_source(&self) -> SourceString {
159
50325
        SourceString(self.clone())
160
    }
161
}
162

            
163
impl ToSource for &str {
164
60
    fn to_source(&self) -> SourceString {
165
60
        SourceString(self.to_string())
166
    }
167
}
168

            
169
impl fmt::Display for SourceString {
170
695
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171
695
        write!(f, "{}", self.0)
172
    }
173
}
174

            
175
impl Borrow<str> for SourceString {
176
25000
    fn borrow(&self) -> &str {
177
25000
        &self.0
178
    }
179
}