Coverage Report

Created: 2025-12-31 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/anstyle-1.0.13/src/effect.rs
Line
Count
Source
1
/// A set of text effects
2
///
3
/// # Examples
4
///
5
/// ```rust
6
/// let effects = anstyle::Effects::BOLD | anstyle::Effects::UNDERLINE;
7
/// ```
8
#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
9
pub struct Effects(u16);
10
11
impl Effects {
12
    /// No [`Effects`] applied
13
    const PLAIN: Self = Effects(0);
14
15
    #[allow(missing_docs)]
16
    pub const BOLD: Self = Effects(1 << 0);
17
    #[allow(missing_docs)]
18
    pub const DIMMED: Self = Effects(1 << 1);
19
    /// Not widely supported. Sometimes treated as inverse or blink
20
    pub const ITALIC: Self = Effects(1 << 2);
21
    /// Style extensions exist for Kitty, VTE, mintty and iTerm2.
22
    pub const UNDERLINE: Self = Effects(1 << 3);
23
    #[allow(missing_docs)]
24
    pub const DOUBLE_UNDERLINE: Self = Effects(1 << 4);
25
    #[allow(missing_docs)]
26
    pub const CURLY_UNDERLINE: Self = Effects(1 << 5);
27
    #[allow(missing_docs)]
28
    pub const DOTTED_UNDERLINE: Self = Effects(1 << 6);
29
    #[allow(missing_docs)]
30
    pub const DASHED_UNDERLINE: Self = Effects(1 << 7);
31
    #[allow(missing_docs)]
32
    pub const BLINK: Self = Effects(1 << 8);
33
    /// Swap foreground and background colors; inconsistent emulation
34
    pub const INVERT: Self = Effects(1 << 9);
35
    #[allow(missing_docs)]
36
    pub const HIDDEN: Self = Effects(1 << 10);
37
    ///  Characters legible but marked as if for deletion. Not supported in Terminal.app
38
    pub const STRIKETHROUGH: Self = Effects(1 << 11);
39
40
    /// No effects enabled
41
    ///
42
    /// # Examples
43
    ///
44
    /// ```rust
45
    /// let effects = anstyle::Effects::new();
46
    /// ```
47
    #[inline]
48
0
    pub const fn new() -> Self {
49
0
        Self::PLAIN
50
0
    }
Unexecuted instantiation: <anstyle::effect::Effects>::new
Unexecuted instantiation: <anstyle::effect::Effects>::new
51
52
    /// Check if no effects are enabled
53
    ///
54
    /// # Examples
55
    ///
56
    /// ```rust
57
    /// let effects = anstyle::Effects::new();
58
    /// assert!(effects.is_plain());
59
    ///
60
    /// let effects = anstyle::Effects::BOLD | anstyle::Effects::UNDERLINE;
61
    /// assert!(!effects.is_plain());
62
    /// ```
63
    #[inline]
64
0
    pub const fn is_plain(self) -> bool {
65
0
        self.0 == Self::PLAIN.0
66
0
    }
67
68
    /// Returns `true` if all of the effects in `other` are contained within `self`.
69
    ///
70
    /// # Examples
71
    ///
72
    /// ```rust
73
    /// let effects = anstyle::Effects::BOLD | anstyle::Effects::UNDERLINE;
74
    /// assert!(effects.contains(anstyle::Effects::BOLD));
75
    ///
76
    /// let effects = anstyle::Effects::new();
77
    /// assert!(!effects.contains(anstyle::Effects::BOLD));
78
    /// ```
79
    #[inline(always)]
80
0
    pub const fn contains(self, other: Effects) -> bool {
81
0
        (other.0 & self.0) == other.0
82
0
    }
83
84
    /// Inserts the specified effects in-place.
85
    ///
86
    /// # Examples
87
    ///
88
    /// ```rust
89
    /// let effects = anstyle::Effects::new().insert(anstyle::Effects::new());
90
    /// assert!(effects.is_plain());
91
    ///
92
    /// let effects = anstyle::Effects::new().insert(anstyle::Effects::BOLD);
93
    /// assert!(effects.contains(anstyle::Effects::BOLD));
94
    /// ```
95
    #[inline(always)]
96
    #[must_use]
97
0
    pub const fn insert(mut self, other: Effects) -> Self {
98
0
        self.0 |= other.0;
99
0
        self
100
0
    }
101
102
    /// Removes the specified effects in-place.
103
    ///
104
    /// # Examples
105
    ///
106
    /// ```rust
107
    /// let effects = (anstyle::Effects::BOLD | anstyle::Effects::UNDERLINE).remove(anstyle::Effects::BOLD);
108
    /// assert!(!effects.contains(anstyle::Effects::BOLD));
109
    /// assert!(effects.contains(anstyle::Effects::UNDERLINE));
110
    /// ```
111
    #[inline(always)]
112
    #[must_use]
113
0
    pub const fn remove(mut self, other: Effects) -> Self {
114
0
        self.0 &= !other.0;
115
0
        self
116
0
    }
117
118
    /// Reset all effects in-place
119
    /// ```rust
120
    /// let effects = (anstyle::Effects::BOLD | anstyle::Effects::UNDERLINE).clear();
121
    /// assert!(!effects.contains(anstyle::Effects::BOLD));
122
    /// assert!(!effects.contains(anstyle::Effects::UNDERLINE));
123
    /// ```
124
    #[inline(always)]
125
    #[must_use]
126
0
    pub const fn clear(self) -> Self {
127
0
        Self::new()
128
0
    }
129
130
    /// Enable or disable the specified effects depending on the passed value.
131
    ///
132
    /// # Examples
133
    ///
134
    /// ```rust
135
    /// let effects = anstyle::Effects::new().set(anstyle::Effects::BOLD, true);
136
    /// assert!(effects.contains(anstyle::Effects::BOLD));
137
    /// ```
138
    #[inline]
139
    #[must_use]
140
0
    pub const fn set(self, other: Self, enable: bool) -> Self {
141
0
        if enable {
142
0
            self.insert(other)
143
        } else {
144
0
            self.remove(other)
145
        }
146
0
    }
147
148
    /// Iterate over enabled effects
149
    #[inline(always)]
150
0
    pub fn iter(self) -> EffectIter {
151
0
        EffectIter {
152
0
            index: 0,
153
0
            effects: self,
154
0
        }
155
0
    }
156
157
    /// Iterate over enabled effect indices
158
    #[inline(always)]
159
0
    pub(crate) fn index_iter(self) -> EffectIndexIter {
160
0
        EffectIndexIter {
161
0
            index: 0,
162
0
            effects: self,
163
0
        }
164
0
    }
165
166
    /// Render the ANSI code
167
    #[inline]
168
0
    pub fn render(self) -> impl core::fmt::Display + Copy {
169
0
        EffectsDisplay(self)
170
0
    }
171
172
    #[inline]
173
    #[cfg(feature = "std")]
174
0
    pub(crate) fn write_to(self, write: &mut dyn std::io::Write) -> std::io::Result<()> {
175
0
        for index in self.index_iter() {
176
0
            write.write_all(METADATA[index].escape.as_bytes())?;
177
        }
178
0
        Ok(())
179
0
    }
180
}
181
182
/// # Examples
183
///
184
/// ```rust
185
/// let effects = anstyle::Effects::new();
186
/// assert_eq!(format!("{:?}", effects), "Effects()");
187
///
188
/// let effects = anstyle::Effects::BOLD | anstyle::Effects::UNDERLINE;
189
/// assert_eq!(format!("{:?}", effects), "Effects(BOLD | UNDERLINE)");
190
/// ```
191
impl core::fmt::Debug for Effects {
192
0
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
193
0
        write!(f, "Effects(")?;
194
0
        for (i, index) in self.index_iter().enumerate() {
195
0
            if i != 0 {
196
0
                write!(f, " | ")?;
197
0
            }
198
0
            write!(f, "{}", METADATA[index].name)?;
199
        }
200
0
        write!(f, ")")?;
201
0
        Ok(())
202
0
    }
203
}
204
205
/// # Examples
206
///
207
/// ```rust
208
/// let effects = anstyle::Effects::BOLD | anstyle::Effects::UNDERLINE;
209
/// assert_eq!(format!("{:?}", effects), "Effects(BOLD | UNDERLINE)");
210
/// ```
211
impl core::ops::BitOr for Effects {
212
    type Output = Self;
213
214
    #[inline(always)]
215
0
    fn bitor(self, rhs: Self) -> Self {
216
0
        self.insert(rhs)
217
0
    }
218
}
219
220
/// # Examples
221
///
222
/// ```rust
223
/// let mut effects = anstyle::Effects::BOLD;
224
/// effects |= anstyle::Effects::UNDERLINE;
225
/// assert_eq!(format!("{:?}", effects), "Effects(BOLD | UNDERLINE)");
226
/// ```
227
impl core::ops::BitOrAssign for Effects {
228
    #[inline]
229
0
    fn bitor_assign(&mut self, other: Self) {
230
0
        *self = self.insert(other);
231
0
    }
Unexecuted instantiation: <anstyle::effect::Effects as core::ops::bit::BitOrAssign>::bitor_assign
Unexecuted instantiation: <anstyle::effect::Effects as core::ops::bit::BitOrAssign>::bitor_assign
232
}
233
234
/// # Examples
235
///
236
/// ```rust
237
/// let effects = (anstyle::Effects::BOLD | anstyle::Effects::UNDERLINE) - anstyle::Effects::BOLD;
238
/// assert_eq!(format!("{:?}", effects), "Effects(UNDERLINE)");
239
/// ```
240
impl core::ops::Sub for Effects {
241
    type Output = Self;
242
243
    #[inline]
244
0
    fn sub(self, other: Self) -> Self {
245
0
        self.remove(other)
246
0
    }
247
}
248
249
/// # Examples
250
///
251
/// ```rust
252
/// let mut effects = anstyle::Effects::BOLD | anstyle::Effects::UNDERLINE;
253
/// effects -= anstyle::Effects::BOLD;
254
/// assert_eq!(format!("{:?}", effects), "Effects(UNDERLINE)");
255
/// ```
256
impl core::ops::SubAssign for Effects {
257
    #[inline]
258
0
    fn sub_assign(&mut self, other: Self) {
259
0
        *self = self.remove(other);
260
0
    }
261
}
262
263
pub(crate) struct Metadata {
264
    pub(crate) name: &'static str,
265
    pub(crate) escape: &'static str,
266
}
267
268
pub(crate) const METADATA: [Metadata; 12] = [
269
    Metadata {
270
        name: "BOLD",
271
        escape: escape!("1"),
272
    },
273
    Metadata {
274
        name: "DIMMED",
275
        escape: escape!("2"),
276
    },
277
    Metadata {
278
        name: "ITALIC",
279
        escape: escape!("3"),
280
    },
281
    Metadata {
282
        name: "UNDERLINE",
283
        escape: escape!("4"),
284
    },
285
    Metadata {
286
        name: "DOUBLE_UNDERLINE",
287
        escape: escape!("21"),
288
    },
289
    Metadata {
290
        name: "CURLY_UNDERLINE",
291
        escape: escape!("4:3"),
292
    },
293
    Metadata {
294
        name: "DOTTED_UNDERLINE",
295
        escape: escape!("4:4"),
296
    },
297
    Metadata {
298
        name: "DASHED_UNDERLINE",
299
        escape: escape!("4:5"),
300
    },
301
    Metadata {
302
        name: "BLINK",
303
        escape: escape!("5"),
304
    },
305
    Metadata {
306
        name: "INVERT",
307
        escape: escape!("7"),
308
    },
309
    Metadata {
310
        name: "HIDDEN",
311
        escape: escape!("8"),
312
    },
313
    Metadata {
314
        name: "STRIKETHROUGH",
315
        escape: escape!("9"),
316
    },
317
];
318
319
#[derive(Copy, Clone, Default, Debug)]
320
struct EffectsDisplay(Effects);
321
322
impl core::fmt::Display for EffectsDisplay {
323
    #[inline]
324
0
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
325
0
        for index in self.0.index_iter() {
326
0
            f.write_str(METADATA[index].escape)?;
327
        }
328
0
        Ok(())
329
0
    }
330
}
331
332
/// Enumerate each enabled value in [`Effects`]
333
#[derive(Clone, Debug, PartialEq, Eq)]
334
pub struct EffectIter {
335
    index: usize,
336
    effects: Effects,
337
}
338
339
impl Iterator for EffectIter {
340
    type Item = Effects;
341
342
0
    fn next(&mut self) -> Option<Self::Item> {
343
0
        while self.index < METADATA.len() {
344
0
            let index = self.index;
345
0
            self.index += 1;
346
347
0
            let effect = Effects(1 << index);
348
0
            if self.effects.contains(effect) {
349
0
                return Some(effect);
350
0
            }
351
        }
352
353
0
        None
354
0
    }
355
}
356
357
#[derive(Clone, Debug, PartialEq, Eq)]
358
pub(crate) struct EffectIndexIter {
359
    index: usize,
360
    effects: Effects,
361
}
362
363
impl Iterator for EffectIndexIter {
364
    type Item = usize;
365
366
0
    fn next(&mut self) -> Option<Self::Item> {
367
0
        while self.index < METADATA.len() {
368
0
            let index = self.index;
369
0
            self.index += 1;
370
371
0
            let effect = Effects(1 << index);
372
0
            if self.effects.contains(effect) {
373
0
                return Some(index);
374
0
            }
375
        }
376
377
0
        None
378
0
    }
379
}
380
381
#[cfg(test)]
382
#[cfg(feature = "std")]
383
mod test {
384
    use super::*;
385
386
    #[test]
387
    fn print_size_of() {
388
        use core::mem::size_of;
389
        dbg!(size_of::<Effects>());
390
        dbg!(size_of::<EffectsDisplay>());
391
    }
392
393
    #[test]
394
    fn no_align() {
395
        #[track_caller]
396
        fn assert_no_align(d: impl core::fmt::Display) {
397
            let expected = format!("{d}");
398
            let actual = format!("{d:<10}");
399
            assert_eq!(expected, actual);
400
        }
401
402
        assert_no_align(Effects::BOLD.render());
403
    }
404
}