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 assignation. This statement includes the semicolon and a new line.
174#[derive(Clone, Debug)]
175pub struct AssignStmt<Variable, Expr>(pub Variable, pub Expr);
176
177/// An item attached to an associated container, via "::".
178/// The output will look like `Cont::Item`.
179#[derive(Clone, Debug)]
180pub struct AssociatedItem<Cont, Item>(pub Cont, pub Item);
181
182/// A question mark following another expression.
183#[derive(Clone, Debug)]
184pub struct QuestionMarkAfter<Expr>(pub Expr);
185
186/// Wraps an expression in `Ok(EXPR)`.
187#[derive(Clone, Debug)]
188pub struct OkResultOf<Expr>(pub Expr);
189
190/// Uses the `as` expression to perform a qualified trait cast (ready for a method call).
191/// I.e., this will render as `<Type as Trait>`.
192#[derive(Clone, Debug)]
193pub struct TypeAsTrait<Type, Trait>(pub Type, pub Trait);
194
195/// Declaration of an extern block, i.e. for FFI.
196/// In Rust 2024 and later, the unsafe keyword must be added for extern blocks. Thus, this struct
197/// requires that the context satisfies [ContextProvides] for [Edition].
198#[derive(Clone, Debug)]
199pub struct ExternBlock<Abi, Body> {
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
206impl<Abi, Body> CanHaveAttributes for ExternBlock<Abi, Body> {
207    fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
208        WithAttributes {
209            attr,
210            separator: "\n",
211            value: self,
212        }
213    }
214}
215
216/// Places the expression inside an unsafe block.
217/// Adds new lines inside the brackets, wrapping the inner expression.
218#[derive(Clone, Debug)]
219pub struct UnsafeBlock<Expr>(pub Expr);
220
221/// Writes a closure.
222/// Adds new lines inside the brackets, wrapping the inner expression.
223#[derive(Clone, Debug)]
224pub struct Closure<InputVars, Expr> {
225    /// The input variables.
226    /// Should be a sequence. They will be comma separated and placed within the pipes.
227    /// To use no input variables, use [NoOpSeq].
228    pub input_vars: InputVars,
229    /// The expression inside the closure block.
230    pub inside_block: Expr,
231}
232
233/// Performs a call to a function inside code.
234#[derive(Clone, Debug)]
235pub struct FunctionCall<Recv, Name, Args> {
236    /// The function receiver
237    pub receiver: Recv,
238    /// Whether the function is associated, false if it's a method
239    pub is_assoc: bool,
240    /// The function name
241    pub name: Name,
242    /// The arguments. Must be a sequence
243    pub args: Args,
244}
245
246/// A function declaration
247#[derive(Clone, Debug)]
248pub struct FunctionDef<Mods, Name, Args, Return, Where, Body> {
249    /// The modifiers. Must be a sequence.
250    pub mods: Mods,
251    /// The function name. Type variables can be declared here via [Parameterized]
252    pub name: Name,
253    /// The arguments. Must be a sequence
254    pub args: Args,
255    /// The return type, i.e. after the `->` arrow
256    pub return_type: Return,
257    /// The "where" conditions. Must be a sequence. Set to [NoOp] to disable.
258    /// Will render as `where C1, C2, C3, ...` where CX is a value in the sequence.
259    pub where_conds: Where,
260    /// The function body.
261    /// To only declare the function, this must be `;` so use [FunctionBodyDeclare]
262    /// To implement the function, use [FunctionBodyImplement]
263    pub body: Body,
264}
265
266impl<Mods, Name, Args, Return, Where, Body> CanHaveAttributes
267    for FunctionDef<Mods, Name, Args, Return, Where, Body>
268{
269    fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
270        WithAttributes {
271            attr,
272            separator: "\n",
273            value: self,
274        }
275    }
276}
277
278/// Declares a function body. This is equivalent to just a semicolon.
279#[derive(Clone, Debug)]
280pub struct FunctionBodyDeclare;
281
282/// Implements a function body. Places the contents inside brackets
283#[derive(Clone, Debug)]
284pub struct FunctionBodyImplement<Inner>(pub Inner);
285
286/// A function pointer. Can be used for `fn`, `Fn`, `FnMut`, and `FnOnce`.
287///
288/// Example:
289/// ```
290/// # use async_codegen::common::{SingularSeq, Str};
291/// # use async_codegen::context::EmptyContext;
292/// # use async_codegen::rust::{FunctionPtr, FunctionPtrKind};
293/// # use async_codegen::util::InMemoryOutput;
294/// let function_ptr = FunctionPtr {
295///   kind: FunctionPtrKind::FnMut,
296///   args: SingularSeq(Str("String")),
297///   return_type: Str("bool")
298/// };
299/// let string = InMemoryOutput::print_output(EmptyContext, &function_ptr);
300/// assert_eq!("FnMut(String) -> bool", string);
301/// ```
302#[derive(Clone, Debug)]
303pub struct FunctionPtr<Args, Return> {
304    /// The function pointer kind
305    pub kind: FunctionPtrKind,
306    /// The arguments. Must be a sequence
307    pub args: Args,
308    /// The return type, i.e. after the `->` arrow
309    pub return_type: Return,
310}
311
312/// The kind of function type
313#[derive(Clone, Debug)]
314pub enum FunctionPtrKind {
315    /// An `fn` pointer. E.g. `fn(String) -> bool`.
316    FnPtr,
317    /// Represents [Fn]
318    Fn,
319    /// Represents [FnMut]
320    FnMut,
321    /// Represents [FnOnce]
322    FnOnce,
323}
324
325/// Renders as `Type=Value`. Intended to be used as a type argument, to specify associated types.
326#[derive(Clone, Debug)]
327pub struct AssociatedTypeEquals<Type, Value>(pub Type, pub Value);
328
329/// Adds a "dyn " before a type expression.
330#[derive(Clone, Debug)]
331pub struct DynOf<Type>(pub Type);
332
333/// Adds a "&" before a type expression
334#[derive(Clone, Debug)]
335pub struct RefOf<Type>(pub Type);
336
337/// Adds an "impl " before a type expression
338pub struct ImplOf<Type>(pub Type);
339
340/// Adds a reference with a lifetime before a type expression, i.e. `&'<lifetime> <type>`
341#[derive(Clone, Debug)]
342pub struct LifetimedRefOf<'l, Type>(pub &'l str, pub Type);
343
344/// Declares an associated type, rendering as `type VarName = Value;`.
345/// Adds new lines before and after.
346#[derive(Clone, Debug)]
347pub struct AssociatedTypeDef<VarName, Value>(pub VarName, pub Value);
348
349/// The declaration of a trait
350#[derive(Clone, Debug)]
351pub struct TraitDef<Mods, Name, TypeVars, SuperTraits, Body> {
352    /// The trait modifiers, e.g. visibility. Must be a sequence.
353    pub mods: Mods,
354    /// The name of the trait
355    pub name: Name,
356    /// The type variables. Must be a sequence
357    pub type_variables: TypeVars,
358    /// The super traits. Must be a sequence
359    pub super_traits: SuperTraits,
360    /// The trait definition's body. Use [NoOp] if none exists.
361    pub body: Body,
362}
363
364impl<Mods, Name, TypeVars, SuperTraits, Body> CanHaveAttributes
365    for TraitDef<Mods, Name, TypeVars, SuperTraits, Body>
366{
367    fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
368        WithAttributes {
369            attr,
370            separator: "\n",
371            value: self,
372        }
373    }
374}
375
376/// The implementation declaration for a trait, applying to a certain receiver.
377#[derive(Clone, Debug)]
378pub struct TraitImpl<TypeVars, Trait, Recv, Where, Body> {
379    /// The type variables to use for the impl block itself. All type variables that appear later
380    /// on the trait or the receiver must be declared here, per Rust language rules.
381    ///
382    /// This field must be a sequence.
383    pub type_variables: TypeVars,
384    /// The trait being implemented
385    pub the_trait: Trait,
386    /// The receiver for which it is implemented
387    pub receiver: Recv,
388    /// The "where" conditions. Must be a sequence. Set to [NoOpSeq] to disable.
389    /// Will render as `where C1, C2, C3, ...` where CX is a value in the sequence.
390    pub where_conds: Where,
391    /// The body. Use [NoOp] if none exists.
392    pub body: Body,
393}
394
395impl<TypeVars, Trait, Recv, Where, Body> CanHaveAttributes
396    for TraitImpl<TypeVars, Trait, Recv, Where, Body>
397{
398    fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
399        WithAttributes {
400            attr,
401            separator: "\n",
402            value: self,
403        }
404    }
405}
406
407/// The declaration of a struct.
408#[derive(Clone, Debug)]
409pub struct StructDef<Mods, Name, Elements> {
410    /// The struct modifiers. Must be a sequence.
411    pub mods: Mods,
412    /// The kind of the struct.
413    ///
414    /// It is suggested to use either a [NamedTuple] or [StructCall]. A semicolon will be
415    /// automatically added afterward, as is needed for tuple structs, and this semicolon will not
416    /// affect structs with named fields.
417    pub kind: StructKind<Name, Elements>,
418}
419
420impl<Mods, Name, Elements> CanHaveAttributes for StructDef<Mods, Name, Elements> {
421    fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
422        WithAttributes {
423            attr,
424            separator: "\n",
425            value: self,
426        }
427    }
428}
429
430/// Completes the struct definition as either a named tuple or a struct with named fields.
431#[derive(Clone, Debug)]
432pub enum StructKind<Name, Elements> {
433    /// A named tuple. This will function similarly to [NamedTuple], except a semicolon will
434    /// be added afterward.
435    ///
436    /// `Name` must be writable, and `Elements` must be a writable sequence for the tuple arguments.
437    Tuple(Name, Elements),
438    /// A struct with named fields. This will function similarly to [StructCall].
439    ///
440    /// `Name` must be writable, and `Elements` must be writable sequence for the struct fields.
441    NamedFields(Name, Elements),
442}
443
444/// The construction or deconstruction of a struct.
445///
446/// When rendered, will use the format `Name { Body }`. Spaces will be added automatically.
447///
448/// This should **not** be used for tuple structs, for that see [NamedTuple].
449#[derive(Clone, Debug)]
450pub struct StructCall<Name, Body> {
451    /// The struct name. Must be writable.
452    ///
453    /// If you are declaring a struct for the first time, you can use [Parameterized] in order
454    /// to declare type variables.
455    pub name: Name,
456    /// The body. Must be writable.
457    ///
458    /// It is suggested to use [StructFields] for multiple fields, or [DeclareField] for just one.
459    pub body: Body,
460}
461
462/// Named struct fields. This will place every field on a new line with a comma afterward.
463/// It is recommended that the sequence should pass [DeclareField].
464///
465/// If you have a single field, you can skip using a sequence and just use [DeclareField] directly.
466pub struct StructFields<Fields>(pub Fields);
467
468/// Declares a single field within a struct. Renders as `Name: Value`.
469///
470/// Does not add attributes. If you want to use attributes for declaration purposes, you can use
471/// [CanHaveAttributes::with_attributes] on this field.
472pub struct DeclareField<Name, Value>(pub Name, pub Value);
473
474impl<Name, Value> CanHaveAttributes for DeclareField<Name, Value> {
475    fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
476        WithAttributes {
477            attr,
478            separator: "\n",
479            value: self,
480        }
481    }
482}
483
484/// A named tuple type.
485///
486/// Renders as `Name(A1, A2, A3, ...)` where AX is part of the argument sequence.
487/// If no arguments exist, will render only as `Name` (i.e., a unit struct).
488pub struct NamedTuple<Name, Args> {
489    pub name: Name,
490    pub args: Args,
491}
492
493/// An anonymous tuple type. This struct's tuple value must be a sequence.
494///
495/// Renders as `(A1, A2, A3, ...)` where AX is part of the argument sequence.
496#[derive(Clone, Debug)]
497pub struct AnonTuple<Args>(pub Args);
498
499/// The unit type, i.e. `()`
500pub type UnitType = AnonTuple<NoOpSeq>;
501
502impl AnonTuple<NoOpSeq> {
503    /// Creates
504    pub fn unit() -> Self {
505        Self(NoOpSeq)
506    }
507}
508
509/// Adds attributes to ANY item.
510///
511/// The first tuple value must be a sequence. The second must be a writable value. This struct
512/// is typically constructed via [CanHaveAttributes::with_attributes].
513///
514/// Rust attributes can be put in many places, so this enables you to add attributes to any
515/// writable item. For example, adding attributes to function parameters can be done like so:
516///
517/// ```rust
518/// # use async_codegen::common::{SingularSeq, Str};
519/// # use async_codegen::context::EmptyContext;
520/// # use async_codegen::rust::{Cfg, FunctionParam, MustUse, Target, WithAttributes, CanHaveAttributes};
521/// # use async_codegen::util::InMemoryOutput;
522///
523/// let function_param = FunctionParam(Str("conditional_param"), Str("Fd")).with_attributes(
524///   SingularSeq(Cfg(Target::Os(Str("linux"))))
525/// );
526/// let string = InMemoryOutput::print_output(EmptyContext, &function_param);
527/// assert_eq!("#[cfg(target_os = \"linux\")] conditional_param: Fd", string);
528/// ```
529#[derive(Clone, Debug)]
530pub struct WithAttributes<Attr, Value> {
531    pub attr: Attr,
532    /// The separator. Usually a space or a new line, depending on what the target value is
533    pub separator: &'static str,
534    /// The value
535    pub value: Value,
536}
537
538/// A writable that can have attributes attached to it
539pub trait CanHaveAttributes: Sized {
540    /// Adds attributes to this writable
541    fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self>;
542}
543
544/// Defines an enum.
545///
546/// In order to use or refer to an enum, you can use [AssociatedItem] together with [NamedTuple]
547/// or [StructCall].
548pub struct EnumDef<Mods, Name, Entries> {
549    /// The modifiers on the type. Must be a sequence.
550    pub mods: Mods,
551    /// The name of the enum
552    pub name: Name,
553    /// The enum entries. Must be a sequence, each entry will be written on a new line with a comma
554    ///
555    /// As for the entries themselves, it is suggested to use [NamedTuple] or [StructCall]
556    /// depending on which kind of enum entry you want to create.
557    pub entries: Entries,
558}
559
560impl<Mods, Name, Entries> CanHaveAttributes for EnumDef<Mods, Name, Entries> {
561    fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
562        WithAttributes {
563            attr,
564            separator: "\n",
565            value: self,
566        }
567    }
568}
569
570/// A type argument-parameterized expression. Used in relation to parameterized names and their
571/// arguments. Examples: `function_name<args>`, `TypeName<'lifetime, args>`, `MyType<Assoc=Value>`.
572///
573/// If no type args exist, [NoOpSeq] should be used.
574#[derive(Clone, Debug)]
575pub struct Parameterized<Name, TypeArgs> {
576    name: Name,
577    type_args: TypeArgs,
578}
579
580impl<Name, TypeArgs> Parameterized<Name, TypeArgs> {
581    /// Initializes an instance
582    pub fn new(name: Name, type_args: TypeArgs) -> Self {
583        Self { name, type_args }
584    }
585}
586
587/// A type variable with a sequence of bounds.
588/// Will render as `TypeVar: B1 + B2 + ...`
589#[derive(Clone, Debug)]
590pub struct BoundedTypeVar<TypeVar, Bounds>(pub TypeVar, pub Bounds);
591
592/// A standalone lifetime, intended to be used as a type argument or variable
593#[derive(Clone, Debug)]
594pub struct Lifetime<'l>(pub &'l str);
595
596/// Renders an individual function parameter, `Name: Type`
597#[derive(Clone, Debug)]
598pub struct FunctionParam<Name, Type>(pub Name, pub Type);
599
600impl<Name, Type> CanHaveAttributes for FunctionParam<Name, Type> {
601    fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
602        WithAttributes {
603            attr,
604            separator: " ",
605            value: self,
606        }
607    }
608}
609
610/// A sequence acceptor that writes attributes. Every attribute will be surrounded with "#[]"
611#[derive(Debug)]
612pub struct AttributesAccept<'o, O, Sep> {
613    inner: SurroundingSeqAccept<'o, O, Str<&'static str>, Combined<Str<&'static str>, Sep>>,
614}
615
616impl<'o, O> AttributesAccept<'o, O, Str<&'static str>> {
617    pub fn multiline(output: &'o mut O) -> Self {
618        Self::with_separator(output, "\n")
619    }
620}
621
622impl<'o, O> AttributesAccept<'o, O, Str<&'static str>> {
623    pub fn with_separator(output: &'o mut O, separator: &'static str) -> Self {
624        Self {
625            inner: SurroundingSeqAccept::new(output, Str("#["), Combined(Str("]"), Str(separator))),
626        }
627    }
628}
629
630impl<'o, O, Sep> SequenceAccept<O> for AttributesAccept<'o, O, Sep>
631where
632    O: Output,
633    Sep: Writable<O>,
634{
635    async fn accept<W: Writable<O>>(&mut self, writable: &W) -> Result<(), O::Error> {
636        self.inner.accept(writable).await
637    }
638}