Skip to main content

air_pass/
lib.rs

1//! This crate is pulled in from the [Firefly](https://github.com/GetFirefly/firefly) compiler, licensed under Apache 2.0
2
3/// This trait represents anything that can be run as a pass.
4///
5/// Passes operate on an input value, and return either the same type, or a new type, depending on the nature of the pass.
6///
7/// Implementations may represent a single pass, or an arbitrary number of passes that will be run as a single unit.
8///
9/// Functions are valid implementations of `Pass` as long as their signature is `fn<I, O, E>(I) -> Result<O, E>`.
10pub trait Pass {
11    type Input<'a>;
12    type Output<'a>;
13    type Error;
14
15    /// Runs the pass on the given input
16    ///
17    /// Errors should be reported via the registered error handler,
18    /// Passes should return `Err` to signal that the pass has failed
19    /// and compilation should be aborted
20    fn run<'a>(&mut self, input: Self::Input<'a>) -> Result<Self::Output<'a>, Self::Error>;
21
22    /// Chains two passes together to form a new, fused pass
23    fn chain<P, E>(self, pass: P) -> Chain<Self, P>
24    where
25        Self: Sized,
26        E: From<Self::Error>,
27        P: for<'a> Pass<Input<'a> = Self::Output<'a>, Error = E>,
28    {
29        Chain::new(self, pass)
30    }
31}
32impl<P, T, U, E> Pass for &mut P
33where
34    P: for<'a> Pass<Input<'a> = T, Output<'a> = U, Error = E>,
35{
36    type Input<'a> = T;
37    type Output<'a> = U;
38    type Error = E;
39
40    fn run<'a>(&mut self, input: Self::Input<'a>) -> Result<Self::Output<'a>, Self::Error> {
41        (*self).run(input)
42    }
43}
44impl<P, T, U, E> Pass for Box<P>
45where
46    P: ?Sized + for<'a> Pass<Input<'a> = T, Output<'a> = U, Error = E>,
47{
48    type Input<'a> = T;
49    type Output<'a> = U;
50    type Error = E;
51
52    fn run<'a>(&mut self, input: Self::Input<'a>) -> Result<Self::Output<'a>, Self::Error> {
53        (**self).run(input)
54    }
55}
56impl<T, U, E> Pass for dyn FnMut(T) -> Result<U, E> {
57    type Input<'a> = T;
58    type Output<'a> = U;
59    type Error = E;
60
61    #[inline]
62    fn run<'a>(&mut self, input: Self::Input<'a>) -> Result<Self::Output<'a>, Self::Error> {
63        self(input)
64    }
65}
66
67/// This struct is not meant to be used directly, but is instead produced
68/// when chaining `Pass` implementations together. `Chain` itself implements `Pass`,
69/// which is what enables us to chain together arbitrarily many passes into a single one.
70pub struct Chain<A, B> {
71    a: A,
72    b: B,
73}
74impl<A, B> Chain<A, B> {
75    fn new(a: A, b: B) -> Self {
76        Self { a, b }
77    }
78}
79impl<A, B> Clone for Chain<A, B>
80where
81    A: Clone,
82    B: Clone,
83{
84    #[inline]
85    fn clone(&self) -> Self {
86        Self::new(self.a.clone(), self.b.clone())
87    }
88}
89impl<A, B, AE, BE> Pass for Chain<A, B>
90where
91    A: for<'a> Pass<Error = AE>,
92    B: for<'a> Pass<Input<'a> = <A as Pass>::Output<'a>, Error = BE>,
93    BE: From<AE>,
94{
95    type Input<'a> = <A as Pass>::Input<'a>;
96    type Output<'a> = <B as Pass>::Output<'a>;
97    type Error = <B as Pass>::Error;
98
99    fn run<'a>(&mut self, input: Self::Input<'a>) -> Result<Self::Output<'a>, Self::Error> {
100        let u = self.a.run(input)?;
101        self.b.run(u)
102    }
103}