async_codegen/rust/mod.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//! Rust syntax elements.
19//!
20//! Note that no checking exists to make sure the elements are used correctly, i.e. the correct
21//! combination of structs. Instead, the library user is expected to have basic knowledge of how
22//! Rust syntax is composed, and to combine the structs in this module likewise.
23//!
24//! Example:
25//!
26//! ```
27//! use async_codegen::common::{CombinedSeq, SingularSeq, Str};
28//! use async_codegen::{Output, Writable};
29//!
30//! use async_codegen::rust::{CfgAttr, Deprecated, Function, FunctionDef, FunctionParam, ModPub, MustUse, NoMangle, Parameterized};
31//!
32//! async fn write_function<O>(output: &mut O) -> Result<(), O::Error> where O: Output {
33//! // For more advanced usage, you can replace Str("") by other Writable implementations
34//! let function_def = FunctionDef {
35//! attr: SingularSeq(Deprecated::with_message(Str("because we all love deprecation"))),
36//! mods: SingularSeq(ModPub),
37//! decl: Function {
38//! name: Str("my_func"),
39//! args: CombinedSeq(
40//! SingularSeq(FunctionParam(Str("var1"), Str("Type"))),
41//! SingularSeq(FunctionParam(Str("var2"), Parameterized::new(Str("Option"), SingularSeq(Str("bool")))))
42//! )
43//! },
44//! return_type: Parameterized::new(Str("Box"), SingularSeq(Str("str"))),
45//! body: Str("\ntodo!()\n")
46//! };
47//! function_def.write_to(output).await
48//! // Will render as:
49//! /*
50//! #[deprecated = "because we all love deprecation"]
51//! pub fn my_func(var1: Type, var2: Option<bool>) -> Box<str> {
52//! todo!()
53//! }
54//! */
55//! }
56//! ```
57//!
58
59use crate::common::{NoOp, NoOpSeq, Str, SurroundingSeqAccept};
60use crate::{Output, SequenceAccept, Writable};
61use std::fmt::Debug;
62
63mod syntax;
64#[cfg(test)]
65mod tests;
66
67/// All possible Rust editions.
68/// This is the only type in this module meant to be used as context, and not as a writable itself.
69#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
70#[non_exhaustive]
71pub enum Edition {
72 /// This Rust edition is declared for usability purposes. However, not all [crate::Writable]
73 /// implementations are guaranteed to work with it.
74 Rust2015,
75 Rust2018,
76 Rust2021,
77 Rust2024,
78}
79
80/// An attribute enabled conditionally, i.e. `#[cfg_attr(Cond, Attr)]`
81#[derive(Clone, Debug)]
82pub struct CfgAttr<Cond, Attr>(pub Cond, pub Attr);
83
84/// A cfg attribute. Renders as `cfg(Cond)`.
85#[derive(Clone, Debug)]
86pub struct Cfg<Cond>(pub Cond);
87
88/// A cfg condition for targeting an OS, OS family, or architecture. For example:
89/// ```
90/// # use async_codegen::common::{NoOpSeq, SingularSeq, Str};
91/// # use async_codegen::rust::{BodyDeclare, Cfg, Function, FunctionDef, Target};
92/// let function = FunctionDef {
93/// attr: SingularSeq(Cfg(Target::Os("linux"))),
94/// mods: NoOpSeq,
95/// decl: Function {
96/// name: Str("conditional_func"),
97/// args: NoOpSeq
98/// },
99/// return_type: Str("()"),
100/// body: BodyDeclare
101/// };
102/// ```
103/// Will render as
104///
105/// ```ignore
106/// #[cfg(target_os = "linux")]
107/// fn conditional_func() -> ();
108/// ```
109#[derive(Clone, Debug)]
110pub enum Target<Value> {
111 Os(Value),
112 Family(Value),
113 Arch(Value),
114}
115
116/// The no mangle attribute.
117///
118/// Requires that the context satisfies [ContextProvides] for [Edition], because in Rust 2024 and
119/// beyond, the no-mangle attribute is an unsafe attribute.
120#[derive(Clone, Debug)]
121pub struct NoMangle;
122
123/// The attribute content for `allow(...)`. The tuple value must be a sequence.
124#[derive(Clone, Debug)]
125pub struct AllowLints<Lints>(pub Lints);
126
127/// The deprecated attribute. The three variants of this enum correspond to the deprecated
128/// attribute's multiple ways of being specified. See:
129/// https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-deprecated-attribute
130#[derive(Clone, Debug)]
131pub enum Deprecated<Msg, Since = NoOp> {
132 Basic,
133 Message(Msg),
134 Full { since: Since, note: Msg },
135}
136
137impl Default for Deprecated<NoOp, NoOp> {
138 fn default() -> Self {
139 Self::Basic
140 }
141}
142
143impl Deprecated<NoOp, NoOp> {
144 pub fn basic() -> Self {
145 Self::Basic
146 }
147}
148
149impl<Msg> Deprecated<Msg> {
150 pub fn with_message(msg: Msg) -> Self {
151 Self::Message(msg)
152 }
153}
154
155/// The must_use attribute
156#[derive(Clone, Debug)]
157pub struct MustUse;
158
159/// The public modifier
160#[derive(Clone, Debug)]
161pub struct ModPub;
162
163/// The extern modifier, with the ABI selected as the tuple value.
164///
165/// This struct includes `unsafe`. Since Rust 2024, the unsafe keyword is required for extern
166/// functions, and before Rust 2024 it is optional. To make it easy to generate code targeting
167/// multiple editions, we unconditionally emit the "unsafe" keyword alongside "extern".
168#[derive(Clone, Debug)]
169pub struct ModUnsafeExtern<Abi>(pub Abi);
170
171/// A let statement. This statement includes the semicolon and a new line.
172#[derive(Clone, Debug)]
173pub struct LetStmt<Variable, Expr>(pub Variable, pub Expr);
174
175/// An item attached to an associated container, via "::".
176/// The output will look like `Cont::Item`.
177#[derive(Clone, Debug)]
178pub struct AssociatedItem<Cont, Item>(pub Cont, pub Item);
179
180/// A question mark following another expression.
181#[derive(Clone, Debug)]
182pub struct QuestionMarkAfter<Expr>(pub Expr);
183
184/// Wraps an expression in `Ok(EXPR)`.
185#[derive(Clone, Debug)]
186pub struct OkResultOf<Expr>(pub Expr);
187
188/// Uses the `as` expression to perform a qualified trait cast (ready for a method call).
189/// I.e., this will render as `<Type as Trait>`.
190#[derive(Clone, Debug)]
191pub struct TypeAsTrait<Type, Trait>(pub Type, pub Trait);
192
193/// Declaration of an extern block, i.e. for FFI.
194/// In Rust 2024 and later, the unsafe keyword must be added for extern blocks. Thus, this struct
195/// requires that the context satisfies [ContextProvides] for [Edition].
196#[derive(Clone, Debug)]
197pub struct ExternBlock<Attr, Abi, Body> {
198 /// The attributes. Must be a sequence, and each value will be placed inside `#[]`.
199 pub attr: Attr,
200 /// The ABI chosen. Must be writable
201 pub abi: Abi,
202 /// The body of the extern block. Must be writable
203 pub body: Body,
204}
205
206/// Places the expression inside an unsafe block.
207/// Adds new lines inside the brackets, wrapping the inner expression.
208#[derive(Clone, Debug)]
209pub struct UnsafeBlock<Expr>(pub Expr);
210
211/// Writes a closure.
212/// Adds new lines inside the brackets, wrapping the inner expression.
213#[derive(Clone, Debug)]
214pub struct Closure<InputVars, Expr> {
215 /// The input variables.
216 /// Should be a sequence. They will be comma separated and placed within the pipes.
217 /// To use no input variables, use [crate::common::NoOpSeq].
218 pub input_vars: InputVars,
219 /// The expression inside the closure block.
220 pub inside_block: Expr,
221}
222
223/// Performs a call to a function inside code.
224#[derive(Clone, Debug)]
225pub struct FunctionCall<Recv, FuncName, Args> {
226 /// The function receiver
227 pub receiver: Recv,
228 /// Whether the function is associated, false if it's a method
229 pub is_assoc: bool,
230 /// The function being called
231 pub function: Function<FuncName, Args>,
232}
233
234/// The base struct for a function. Includes name and arguments.
235/// This function is re-used in other places and is likely not helpful by itself.
236#[derive(Clone, Debug)]
237pub struct Function<Name, Args> {
238 /// The function name. Must be writable.
239 pub name: Name,
240 /// The function arguments. Must be a sequence.
241 pub args: Args,
242}
243
244/// A function declaration
245#[derive(Clone, Debug)]
246pub struct FunctionDef<Attr, Mods, Name, Args, Return, Body> {
247 /// The attributes. Must be a sequence, and each value will be placed inside `#[]`.
248 pub attr: Attr,
249 /// The modifiers. Must be a sequence.
250 pub mods: Mods,
251 /// The function itself
252 pub decl: Function<Name, Args>,
253 /// The return type, i.e. after the `->` arrow
254 pub return_type: Return,
255 /// The function body. At the minimum, this must be `;` (see [`BodyDeclare`])
256 pub body: Body,
257}
258
259/// Declares a function body. This is equivalent to just a semicolon.
260#[derive(Clone, Debug)]
261pub struct BodyDeclare;
262
263/// Renders as `Type=Value`. Intended to be used as a type argument, to specify associated types.
264#[derive(Clone, Debug)]
265pub struct AssociatedTypeEquals<Type, Value>(pub Type, pub Value);
266
267/// Adds a "dyn " before a type expression.
268#[derive(Clone, Debug)]
269pub struct DynOf<Type>(pub Type);
270
271/// Adds a "&" before a type expression
272#[derive(Clone, Debug)]
273pub struct RefOf<Type>(pub Type);
274
275/// Adds an "impl " before a type expression
276pub struct ImplOf<Type>(pub Type);
277
278/// Adds a reference with a lifetime before a type expression, i.e. `&'<lifetime> <type>`
279#[derive(Clone, Debug)]
280pub struct LifetimedRefOf<'l, Type>(pub &'l str, pub Type);
281
282/// Declares an associated type, rendering as `type VarName = Value;`.
283/// Adds new lines before and after.
284#[derive(Clone, Debug)]
285pub struct AssociatedTypeDef<VarName, Value>(pub VarName, pub Value);
286
287/// The declaration of a trait
288#[derive(Clone, Debug)]
289pub struct TraitDef<Attr, Mods, Name, TypeVars, SuperTraits, Body> {
290 /// The trait attributes. Must be a sequence, and each value will be placed inside `#[]`.
291 pub attr: Attr,
292 /// The trait modifiers, e.g. visibility. Must be a sequence.
293 pub mods: Mods,
294 /// The name of the trait
295 pub name: Name,
296 /// The type variables. Must be a sequence
297 pub type_variables: TypeVars,
298 /// The super traits. Must be a sequence
299 pub super_traits: SuperTraits,
300 /// The trait definition's body. Use [NoOp] if none exists.
301 pub body: Body,
302}
303
304/// The implementation declaration for a trait, applying to a certain receiver.
305#[derive(Clone, Debug)]
306pub struct TraitImpl<TypeVars, Trait, Recv, Body> {
307 /// The type variables to use for the impl block itself. All type variables that appear later
308 /// on the trait or the receiver must be declared here, per Rust language rules.
309 ///
310 /// This field must be a sequence.
311 pub type_variables: TypeVars,
312 /// The trait being implemented
313 pub the_trait: Trait,
314 /// The receiver for which it is implemented
315 pub receiver: Recv,
316 /// The body. Use [NoOp] if none exists.
317 pub body: Body,
318}
319
320/// The declaration of a struct.
321#[derive(Clone, Debug)]
322pub struct StructDef<Attr, Mods, Name, Elements> {
323 /// The struct attributes. Must be a sequence, and each value will be placed inside `#[]`.
324 pub attr: Attr,
325 /// The struct modifiers. Must be a sequence.
326 pub mods: Mods,
327 /// The kind of the struct.
328 ///
329 /// It is suggested to use either a [NamedTuple] or [StructCall]. A semicolon will be
330 /// automatically added afterward, as is needed for tuple structs, and this semicolon will not
331 /// affect structs with named fields.
332 pub kind: StructKind<Name, Elements>,
333}
334
335/// Completes the struct definition as either a named tuple or a struct with named fields.
336#[derive(Clone, Debug)]
337pub enum StructKind<Name, Elements> {
338 /// A named tuple. This will function similarly to [NamedTuple], except a semicolon will
339 /// be added afterward.
340 ///
341 /// `Name` must be writable, and `Elements` must be a writable sequence for the tuple arguments.
342 Tuple(Name, Elements),
343 /// A struct with named fields. This will function similarly to [StructCall].
344 ///
345 /// `Name` must be writable, and `Elements` must be writable sequence for the struct fields.
346 NamedFields(Name, Elements),
347}
348
349/// The construction or deconstruction of a struct.
350///
351/// When rendered, will use the format `Name { Body }`. Spaces will be added automatically.
352///
353/// This should **not** be used for tuple structs, for that see [NamedTuple].
354#[derive(Clone, Debug)]
355pub struct StructCall<Name, Body> {
356 /// The struct name. Must be writable.
357 ///
358 /// If you are declaring a struct for the first time, you can use [Parameterized] in order
359 /// to declare type variables.
360 pub name: Name,
361 /// The body. Must be writable.
362 ///
363 /// It is suggested to use [StructFields] for multiple fields, or [DeclareField] for just one.
364 pub body: Body,
365}
366
367/// Named struct fields. This will place every field on a new line with a comma afterward.
368/// It is recommended that the sequence should pass [DeclareField].
369///
370/// If you have a single field, you can skip using a sequence and just use [DeclareField] directly.
371pub struct StructFields<Fields>(pub Fields);
372
373/// Declares a single field within a struct. Renders as `Name: Value`.
374///
375/// Does not add attributes. If you want to use attributes for declaration purposes, you can use
376/// [WithAttributes] which works in any context.
377pub struct DeclareField<Name, Value>(pub Name, pub Value);
378
379/// A named tuple type.
380///
381/// Renders as `Name(A1, A2, A3, ...)` where AX is part of the argument sequence.
382/// If no arguments exist, will render only as `Name` (i.e., a unit struct).
383pub struct NamedTuple<Name, Args> {
384 pub name: Name,
385 pub args: Args,
386}
387
388/// An anonymous tuple type. This struct's tuple value must be a sequence.
389///
390/// Renders as `(A1, A2, A3, ...)` where AX is part of the argument sequence.
391#[derive(Clone, Debug)]
392pub struct AnonTuple<Args>(pub Args);
393
394/// The unit type, i.e. `()`
395pub type UnitType = AnonTuple<NoOpSeq>;
396
397impl AnonTuple<NoOpSeq> {
398 /// Creates
399 pub fn unit() -> Self {
400 Self(NoOpSeq)
401 }
402}
403
404/// Adds attributes to ANY item.
405///
406/// The first tuple value must be a sequence. The second must be a writable value.
407///
408/// Rust attributes can be put in many places, so this enables you to add attributes to any
409/// writable item. For example, adding attributes to function parameters can be done like so:
410///
411/// ```rust
412/// # use async_codegen::common::{SingularSeq, Str};
413/// # use async_codegen::rust::{Cfg, FunctionParam, MustUse, Target, WithAttributes};
414///
415/// let function_param = WithAttributes(
416/// SingularSeq(Cfg(Target::Os("linux"))),
417/// FunctionParam(Str("conditional_param"), Str("Fd"))
418/// );
419/// ```
420///
421/// Will render as:
422///
423/// ```ignore
424/// #[cfg(target_os = "linux")] conditional_param: Fd
425/// ```
426///
427pub struct WithAttributes<Attr, Value>(pub Attr, pub Value);
428
429/// Defines an enum.
430///
431/// In order to use or refer to an enum, you can use [AssociatedItem] together with [NamedTuple]
432/// or [StructCall].
433pub struct EnumDef<Attr, Mods, Name, Entries> {
434 /// The attributes. Must be a sequence.
435 pub attr: Attr,
436 /// The modifiers on the type. Must be a sequence.
437 pub mods: Mods,
438 /// The name of the enum
439 pub name: Name,
440 /// The enum entries. Must be a sequence, each entry will be written on a new line with a comma
441 ///
442 /// As for the entries themselves, it is suggested to use [NamedTuple] or [StructCall]
443 /// depending on which kind of enum entry you want to create.
444 pub entries: Entries,
445}
446
447/// A type argument-parameterized expression. Used in relation to parameterized names and their
448/// arguments. Examples: `function_name<args>`, `TypeName<'lifetime, args>`, `MyType<Assoc=Value>`.
449///
450/// If no type args exist, [crate::common::NoOpSeq] should be used.
451#[derive(Clone, Debug)]
452pub struct Parameterized<Name, TypeArgs> {
453 name: Name,
454 type_args: TypeArgs,
455}
456
457impl<Name, TypeArgs> Parameterized<Name, TypeArgs> {
458 /// Initializes an instance
459 pub fn new(name: Name, type_args: TypeArgs) -> Self {
460 Self { name, type_args }
461 }
462}
463
464/// A type variable with a sequence of bounds.
465/// Will render as `TypeVar: B1 + B2 + ...`
466#[derive(Clone, Debug)]
467pub struct BoundedTypeVar<TypeVar, Bounds>(pub TypeVar, pub Bounds);
468
469/// A standalone lifetime, intended to be used as a type argument or variable
470#[derive(Clone, Debug)]
471pub struct Lifetime<'l>(pub &'l str);
472
473/// Renders an individual function parameter, `Name: Type`
474#[derive(Clone, Debug)]
475pub struct FunctionParam<Name, Type>(pub Name, pub Type);
476
477/// A sequence acceptor that writes attributes. Every attribute will be placed on a new line
478/// and automatically be surrounded with "#[]"
479#[derive(Debug)]
480pub struct AttributesAccept<'o, O> {
481 inner: SurroundingSeqAccept<'o, O, Str<&'static str>, Str<&'static str>>,
482}
483
484impl<'o, O> AttributesAccept<'o, O> {
485 pub fn new(output: &'o mut O) -> Self {
486 Self {
487 inner: SurroundingSeqAccept::new(output, Str("#["), Str("]\n")),
488 }
489 }
490}
491
492impl<'o, O: Output> SequenceAccept<O> for AttributesAccept<'o, O> {
493 async fn accept<W: Writable<O>>(&mut self, writable: &W) -> Result<(), O::Error> {
494 self.inner.accept(writable).await
495 }
496}