async_codegen/
common.rs

1/*
2 * Copyright © 2025 Anand Beh
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//!
18//!
19//! Provides common, re-usable types that work for any code generation purposes
20//!
21//! Some of the types in this module are conceptual and are related to the library itself, like
22//! [NoOp] or [CombinedBody]. Other types are syntax based, but their syntax is so general that
23//! they are useful for code generation in different languages.
24//!
25
26use super::{Output, SequenceAccept, Writable, WritableSeq};
27
28/// Empty writable
29#[derive(Copy, Clone, Debug)]
30pub struct NoOp;
31
32impl<O> Writable<O> for NoOp
33where
34    O: Output,
35{
36    async fn write_to(&self, _: &mut O) -> Result<(), O::Error> {
37        Ok(())
38    }
39}
40
41/// Empty writable sequence
42#[derive(Copy, Clone, Debug)]
43pub struct NoOpSeq;
44
45impl<O> WritableSeq<O> for NoOpSeq
46where
47    O: Output,
48{
49    async fn for_each<S: SequenceAccept<O>>(&self, _: &mut S) -> Result<(), O::Error> {
50        Ok(())
51    }
52}
53
54/// A combined writable that simply writes its tuple values out
55#[derive(Clone, Debug)]
56pub struct Combined<W1, W2>(pub W1, pub W2);
57
58impl<O, W1, W2> Writable<O> for Combined<W1, W2>
59where
60    O: Output,
61    W1: Writable<O>,
62    W2: Writable<O>,
63{
64    async fn write_to(&self, output: &mut O) -> Result<(), O::Error> {
65        self.0.write_to(output).await?;
66        self.1.write_to(output).await
67    }
68}
69
70/// A combined writable sequence that consists of two other sequences
71#[derive(Clone, Debug)]
72pub struct CombinedSeq<S1, S2>(pub S1, pub S2);
73
74impl<O, S1, S2> WritableSeq<O> for CombinedSeq<S1, S2>
75where
76    O: Output,
77    S1: WritableSeq<O>,
78    S2: WritableSeq<O>,
79{
80    async fn for_each<S>(&self, sink: &mut S) -> Result<(), O::Error>
81    where
82        S: SequenceAccept<O>,
83    {
84        self.0.for_each(sink).await?;
85        self.1.for_each(sink).await
86    }
87}
88
89/// A singular converts a [`Writable`] into a single-element [`WritableSeq`]
90/// Its implementation just writes the tuple value.
91#[derive(Clone, Debug)]
92pub struct SingularSeq<W>(pub W);
93
94impl<O, W> WritableSeq<O> for SingularSeq<W>
95where
96    O: Output,
97    W: Writable<O>,
98{
99    async fn for_each<S>(&self, sink: &mut S) -> Result<(), O::Error>
100    where
101        S: SequenceAccept<O>,
102    {
103        sink.accept(&self.0).await
104    }
105}
106
107/// A struct that repeats a value multiple times in order to turn it into a [`WritableSeq`].
108/// This struct is indeed a generalization of [`SingularSeq`] (it is equivalent when `count = 1`).
109#[derive(Clone, Debug)]
110pub struct RepeatSeq<W> {
111    /// The number of repetitions
112    pub count: usize,
113    /// The element to repeat. Must be writable.
114    pub writable: W,
115}
116
117impl<O, W> WritableSeq<O> for RepeatSeq<W>
118where
119    O: Output,
120    W: Writable<O>,
121{
122    async fn for_each<S>(&self, sink: &mut S) -> Result<(), O::Error>
123    where
124        S: SequenceAccept<O>,
125    {
126        for _ in 0..self.count {
127            sink.accept(&self.writable).await?;
128        }
129        Ok(())
130    }
131}
132
133/// A sequence based on an array of writable elements
134#[derive(Debug)]
135pub struct ArrSeq<'a, W>(pub &'a [W]);
136
137impl<'a, W> Clone for ArrSeq<'a, W> {
138    fn clone(&self) -> Self {
139        Self(self.0)
140    }
141}
142
143impl<O, W> WritableSeq<O> for ArrSeq<'_, W>
144where
145    O: Output,
146    W: Writable<O>,
147{
148    async fn for_each<S>(&self, sink: &mut S) -> Result<(), O::Error>
149    where
150        S: SequenceAccept<O>,
151    {
152        for elem in self.0 {
153            sink.accept(elem).await?;
154        }
155        Ok(())
156    }
157}
158
159/// Turns a string or a string reference into a writable value.
160/// Can be used with [str], [String], or any type that implements `AsRef<str>`
161#[derive(Copy, Clone, Debug)]
162pub struct Str<STR>(pub STR);
163
164impl<O, STR> Writable<O> for Str<STR>
165where
166    O: Output,
167    STR: AsRef<str>,
168{
169    async fn write_to(&self, output: &mut O) -> Result<(), O::Error> {
170        output.write(self.0.as_ref()).await
171    }
172}
173
174/// Like [ArrSeq], but specialized for string so that you don't need to wrap each element in [Str]
175#[derive(Clone, Debug)]
176pub struct StrArrSeq<'a>(pub &'a [&'a str]);
177
178impl<O> WritableSeq<O> for StrArrSeq<'_>
179where
180    O: Output,
181{
182    async fn for_each<S>(&self, sink: &mut S) -> Result<(), O::Error>
183    where
184        S: SequenceAccept<O>,
185    {
186        for elem in self.0 {
187            sink.accept(&Str(*elem)).await?;
188        }
189        Ok(())
190    }
191}
192
193/// A general purpose sequence acceptor that tracks whether any element is written and can
194/// write a separator between each element, in addition to an optional intro at the beginning.
195#[derive(Debug)]
196pub struct SeparatedSeqAccept<'o, O, Intro, Sep> {
197    /// The output.
198    pub output: &'o mut O,
199    /// The intro. Must be writable
200    pub intro: Intro,
201    /// The separator. Must be writable
202    pub separator: Sep,
203    /// Whether this instance wrote anything. Should be initially set to false.
204    pub wrote_any: bool,
205}
206
207impl<'o, O, Intro, Sep> SeparatedSeqAccept<'o, O, Intro, Sep> {
208    pub fn new(output: &'o mut O, intro: Intro, separator: Sep) -> Self {
209        Self {
210            output,
211            intro,
212            separator,
213            wrote_any: false,
214        }
215    }
216}
217
218impl<'o, O, Sep> SeparatedSeqAccept<'o, O, NoOp, Sep> {
219    pub fn no_intro(output: &'o mut O, separator: Sep) -> Self {
220        Self::new(output, NoOp, separator)
221    }
222}
223
224impl<'o, O> SeparatedSeqAccept<'o, O, NoOp, Str<&'static str>> {
225    /// Makes a sink for sequences that separates by `, `.
226    pub fn comma_separated(output: &'o mut O) -> Self {
227        Self::new(output, NoOp, Str(", "))
228    }
229}
230
231impl<'o, O, Intro, Sep> SequenceAccept<O> for SeparatedSeqAccept<'o, O, Intro, Sep>
232where
233    O: Output,
234    Intro: Writable<O>,
235    Sep: Writable<O>,
236{
237    async fn accept<W>(&mut self, writable: &W) -> Result<(), O::Error>
238    where
239        W: Writable<O>,
240    {
241        if self.wrote_any {
242            self.separator.write_to(self.output).await?;
243        } else {
244            self.intro.write_to(self.output).await?;
245            self.wrote_any = true;
246        }
247        writable.write_to(self.output).await
248    }
249}
250
251/// A general purpose sequence acceptor that surrounds every element written with the "before"
252/// and "after" writable elements.
253#[derive(Debug)]
254pub struct SurroundingSeqAccept<'o, O, Before, After> {
255    pub output: &'o mut O,
256    pub before: Before,
257    pub after: After,
258}
259
260impl<'o, O, Before, After> SurroundingSeqAccept<'o, O, Before, After> {
261    pub fn new(output: &'o mut O, before: Before, after: After) -> Self {
262        Self {
263            output,
264            before,
265            after,
266        }
267    }
268}
269
270impl<'o, O, Before, After> SequenceAccept<O> for SurroundingSeqAccept<'o, O, Before, After>
271where
272    O: Output,
273    Before: Writable<O>,
274    After: Writable<O>,
275{
276    async fn accept<W>(&mut self, writable: &W) -> Result<(), O::Error>
277    where
278        W: Writable<O>,
279    {
280        self.before.write_to(self.output).await?;
281        writable.write_to(self.output).await?;
282        self.after.write_to(self.output).await
283    }
284}
285
286/// A sequence implementation that takes elements in an array, and writes each element using
287/// the config. The config should implement [SequenceConfig].
288#[derive(Debug)]
289pub struct SequenceViaConfig<'t, T, Config> {
290    pub data: &'t [T],
291    pub config: Config,
292}
293
294impl<'t, T, Config> Clone for SequenceViaConfig<'t, T, Config>
295where
296    Config: Clone,
297{
298    fn clone(&self) -> Self {
299        Self {
300            data: self.data,
301            config: self.config.clone(),
302        }
303    }
304}
305
306/// A helper object that writes other data, and not the object itself, on demand
307pub trait SequenceConfig<T, O>
308where
309    O: Output,
310{
311    /// Writes an individual data point.
312    async fn write_datum(&self, datum: &T, output: &mut O) -> Result<(), O::Error>;
313}
314
315impl<'t, T, Config, O> WritableSeq<O> for SequenceViaConfig<'t, T, Config>
316where
317    O: Output,
318    Config: SequenceConfig<T, O>,
319{
320    async fn for_each<S>(&self, sink: &mut S) -> Result<(), O::Error>
321    where
322        S: SequenceAccept<O>,
323    {
324        struct WriteSingle<'t, T, Config> {
325            datum: &'t T,
326            config: &'t Config,
327        }
328        impl<'t, T, Config, O> Writable<O> for WriteSingle<'t, T, Config>
329        where
330            O: Output,
331            Config: SequenceConfig<T, O>,
332        {
333            async fn write_to(&self, output: &mut O) -> Result<(), O::Error> {
334                self.config.write_datum(self.datum, output).await
335            }
336        }
337        for datum in self.data {
338            sink.accept(&WriteSingle {
339                datum,
340                config: &self.config,
341            })
342            .await?;
343        }
344        Ok(())
345    }
346}