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