Skip to main content

cucumber/writer/
or.rs

1// Copyright (c) 2018-2026  Brendan Molloy <brendan@bbqsrc.net>,
2//                          Ilya Solovyiov <ilya.solovyiov@gmail.com>,
3//                          Kai Ren <tyranron@gmail.com>
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! Passing events to one of two [`Writer`]s based on a predicate.
12
13use crate::{Event, World, Writer, cli, event, parser, writer};
14
15/// Wrapper for passing events to one of two [`Writer`]s based on a predicate.
16#[derive(Clone, Copy, Debug)]
17pub struct Or<L, R, F> {
18    /// Left [`Writer`].
19    left: L,
20
21    /// Right [`Writer`].
22    right: R,
23
24    /// Predicate indicating which [`Writer`] should be used.
25    /// `left` is used on [`true`] and `right` on [`false`].
26    predicate: F,
27}
28
29impl<L, R, F> Or<L, R, F> {
30    /// Creates a new [`Or`] [`Writer`] passing events to the `left` and `right`
31    /// [`Writer`]s based on the specified `predicate`.
32    ///
33    /// In case `predicate` returns [`true`], the `left` [`Writer`] is used,
34    /// otherwise the `right` [`Writer`] is used on [`false`].
35    #[must_use]
36    pub const fn new(left: L, right: R, predicate: F) -> Self {
37        Self { left, right, predicate }
38    }
39
40    /// Returns the left [`Writer`] of this [`Or`] one.
41    #[must_use]
42    pub const fn left_writer(&self) -> &L {
43        &self.left
44    }
45
46    /// Returns the right [`Writer`] of this [`Or`] one.
47    #[must_use]
48    pub const fn right_writer(&self) -> &R {
49        &self.right
50    }
51}
52
53#[warn(clippy::missing_trait_methods)]
54impl<W, L, R, F> Writer<W> for Or<L, R, F>
55where
56    W: World,
57    L: Writer<W>,
58    R: Writer<W>,
59    F: FnMut(
60        &parser::Result<Event<event::Cucumber<W>>>,
61        &cli::Compose<L::Cli, R::Cli>,
62    ) -> bool,
63{
64    type Cli = cli::Compose<L::Cli, R::Cli>;
65
66    async fn handle_event(
67        &mut self,
68        event: parser::Result<Event<event::Cucumber<W>>>,
69        cli: &Self::Cli,
70    ) {
71        if (self.predicate)(&event, cli) {
72            self.left.handle_event(event, &cli.left).await;
73        } else {
74            self.right.handle_event(event, &cli.right).await;
75        }
76    }
77}
78
79impl<W, L, R, F> writer::Stats<W> for Or<L, R, F>
80where
81    L: writer::Stats<W>,
82    R: writer::Stats<W>,
83    F: FnMut(
84        &parser::Result<Event<event::Cucumber<W>>>,
85        &cli::Compose<L::Cli, R::Cli>,
86    ) -> bool,
87    Self: Writer<W>,
88{
89    fn passed_steps(&self) -> usize {
90        self.left.passed_steps() + self.right.passed_steps()
91    }
92
93    fn skipped_steps(&self) -> usize {
94        self.left.skipped_steps() + self.right.skipped_steps()
95    }
96
97    fn failed_steps(&self) -> usize {
98        self.left.failed_steps() + self.right.failed_steps()
99    }
100
101    fn retried_steps(&self) -> usize {
102        self.left.retried_steps() + self.right.retried_steps()
103    }
104
105    fn parsing_errors(&self) -> usize {
106        self.left.parsing_errors() + self.right.parsing_errors()
107    }
108
109    fn hook_errors(&self) -> usize {
110        self.left.hook_errors() + self.right.hook_errors()
111    }
112}
113
114#[warn(clippy::missing_trait_methods)]
115impl<L, R, F> writer::Normalized for Or<L, R, F>
116where
117    L: writer::Normalized,
118    R: writer::Normalized,
119{
120}
121
122#[warn(clippy::missing_trait_methods)]
123impl<L, R, F> writer::NonTransforming for Or<L, R, F>
124where
125    L: writer::NonTransforming,
126    R: writer::NonTransforming,
127{
128}