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
/// Represent a duration
33
#[derive(Clone, Debug, PartialEq, Eq)]
34
pub struct Duration {
35
    pub value: U64,
36
    pub unit: Option<DurationUnit>,
37
}
38

            
39
impl Duration {
40
180
    pub fn new(value: U64, unit: Option<DurationUnit>) -> Duration {
41
180
        Duration { value, unit }
42
    }
43
}
44

            
45
/// Represents a duration unit
46
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
47
pub enum DurationUnit {
48
    MilliSecond,
49
    Second,
50
    Minute,
51
}
52

            
53
impl fmt::Display for Count {
54
155
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55
155
        match self {
56
145
            Count::Finite(n) => {
57
145
                write!(f, "{n}")
58
            }
59
            Count::Infinite => {
60
10
                write!(f, "-1")
61
            }
62
        }
63
    }
64
}
65

            
66
impl fmt::Display for Duration {
67
65
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68
65
        let unit = if let Some(value) = self.unit {
69
65
            value.to_string()
70
        } else {
71
            String::new()
72
        };
73
65
        write!(f, "{}{unit}", self.value)
74
    }
75
}
76

            
77
impl fmt::Display for DurationUnit {
78
160
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79
160
        match self {
80
115
            DurationUnit::MilliSecond => write!(f, "ms"),
81
45
            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
170
    fn from_str(s: &str) -> Result<Self, Self::Err> {
91
170
        match s {
92
170
            "ms" => Ok(DurationUnit::MilliSecond),
93
60
            "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
59375
    pub fn new() -> Self {
129
59375
        SourceString(String::new())
130
    }
131

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

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

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

            
147
    /// Returns `true` if this [`SourceString`] starts with the char `c`.
148
32670
    pub fn starts_with(&self, c: char) -> bool {
149
32670
        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
46025
    fn to_source(&self) -> SourceString {
159
46025
        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
4115
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171
4115
        write!(f, "{}", self.0)
172
    }
173
}
174

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