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(Str("Option"), SingularSeq(Str("bool")))))
39//!     ),
40//!     return_type: Parameterized(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 [Writable]
69    /// implementations are guaranteed to work with it.
70    Rust2015,
71    Rust2018,
72    Rust2021,
73    Rust2024,
74}
75
76/// Imports a single type so that it can be used later.
77/// Renders as `use Type;`. Adds a new line after the semicolon.
78#[derive(Clone, Debug)]
79pub struct UseType<Type>(pub Type);
80
81/// An attribute enabled conditionally, i.e. `#[cfg_attr(Cond, Attr)]`
82#[derive(Clone, Debug)]
83pub struct CfgAttr<Cond, Attr>(pub Cond, pub Attr);
84
85/// A cfg attribute. Renders as `cfg(Cond)`.
86#[derive(Clone, Debug)]
87pub struct Cfg<Cond>(pub Cond);
88
89/// A doc attribute on an item.
90///
91/// The generic argument of this enum is not used in all variants. Consider using the constructor
92/// functions [Self::hidden], [Self::inline], and [Self::no_inline] if applicable
93#[derive(Clone, Debug)]
94pub enum Doc<Value> {
95    /// The `#[doc(hidden)]` attribute
96    Hidden,
97    /// The `#[doc(inline)]` attribute
98    Inline,
99    /// The `#[doc(no_inline)]` attribute
100    NoInline,
101    /// Creates an alias to another item with `#[doc(alias = "Value")]`
102    Alias(Value),
103    /// Creates a documentation test attribute with `#[doc(test(Value))]`
104    Test(Value),
105}
106
107impl Doc<NoOp> {
108    /// The `#[doc(hidden)]` attribute
109    pub fn hidden() -> Doc<NoOp> {
110        Doc::Hidden
111    }
112
113    /// The `#[doc(inline)]` attribute
114    pub fn inline() -> Doc<NoOp> {
115        Doc::Inline
116    }
117
118    /// The `#[doc(no_inline)]` attribute
119    pub fn no_inline() -> Doc<NoOp> {
120        Doc::NoInline
121    }
122}
123
124/// A cfg condition for targeting an OS, OS family, or architecture. For example:
125/// ```
126/// # use async_codegen::common::{NoOpSeq, SingularSeq, Str};
127/// # use async_codegen::context::EmptyContext;
128/// # use async_codegen::rust::{FunctionBodyDeclare, Cfg, FunctionDef, Target, CanHaveAttributes};
129/// # use async_codegen::util::InMemoryOutput;
130/// let function = FunctionDef {
131///   mods: NoOpSeq,
132///   name: Str("conditional_func"),
133///   args: NoOpSeq,
134///   return_type: Str("()"),
135///   where_conds: NoOpSeq,
136///   body: FunctionBodyDeclare
137/// }.with_attributes(
138///   SingularSeq(Cfg(Target::Os(Str("linux"))))
139/// );
140/// let string = InMemoryOutput::print_output(EmptyContext, &function);
141/// assert_eq!("#[cfg(target_os = \"linux\")]\nfn conditional_func() -> ();\n\n", string);
142/// ```
143#[derive(Clone, Debug)]
144pub enum Target<Value> {
145    Os(Value),
146    Family(Value),
147    Arch(Value),
148}
149
150/// The link attribute.
151#[derive(Clone, Debug)]
152pub struct Link<Arg>(pub Arg);
153
154/// The no mangle attribute.
155///
156/// Requires that the context satisfies [ContextProvides] for [Edition], because in Rust 2024 and
157/// beyond, the no-mangle attribute is an unsafe attribute.
158#[derive(Clone, Debug)]
159pub struct NoMangle;
160
161/// The attribute content for `allow(...)`. The tuple value must be a sequence.
162#[derive(Clone, Debug)]
163pub struct AllowLints<Lints>(pub Lints);
164
165/// The deprecated attribute. The three variants of this enum correspond to the deprecated
166/// attribute's multiple ways of being specified. See:
167/// https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-deprecated-attribute
168#[derive(Clone, Debug)]
169pub enum Deprecated<Msg, Since = NoOp> {
170    Basic,
171    Message(Msg),
172    Full { since: Since, note: Msg },
173}
174
175impl Default for Deprecated<NoOp, NoOp> {
176    fn default() -> Self {
177        Self::Basic
178    }
179}
180
181impl Deprecated<NoOp, NoOp> {
182    pub fn basic() -> Self {
183        Self::Basic
184    }
185}
186
187impl<Msg> Deprecated<Msg> {
188    pub fn with_message(msg: Msg) -> Self {
189        Self::Message(msg)
190    }
191}
192
193/// The must_use attribute
194#[derive(Clone, Debug)]
195pub struct MustUse;
196
197/// The public modifier
198#[derive(Clone, Debug)]
199pub struct ModPub;
200
201/// The unsafe modifier
202#[derive(Clone, Debug)]
203pub struct ModUnsafe;
204
205/// The extern modifier, with the ABI selected as the tuple value.
206///
207/// This struct includes `unsafe`. Since Rust 2024, the unsafe keyword is required for extern
208/// functions, and before Rust 2024 it is optional. To make it easy to generate code targeting
209/// multiple editions, we unconditionally emit the "unsafe" keyword alongside "extern".
210#[derive(Clone, Debug)]
211pub struct ModUnsafeExtern<Abi>(pub Abi);
212
213/// A standalone statement. Renders the expression and adds a semicolon and a new line.
214#[derive(Clone, Debug)]
215pub struct Stmt<Expr>(pub Expr);
216
217/// A let statement. This statement includes the semicolon and a new line.
218#[derive(Clone, Debug)]
219pub struct LetStmt<Variable, Expr>(pub Variable, pub Expr);
220
221/// A mutable let statement.  This statement includes the semicolon and a new line.
222#[derive(Clone, Debug)]
223pub struct LetMutStmt<Variable, Expr>(pub Variable, pub Expr);
224
225/// An assignation. This statement includes the semicolon and a new line.
226#[derive(Clone, Debug)]
227pub struct AssignStmt<Variable, Expr>(pub Variable, pub Expr);
228
229/// An assignation, as an expression
230#[derive(Clone, Debug)]
231pub struct AssignExpr<Variable, Expr>(pub Variable, pub Expr);
232
233/// A return statement. Renders as `return Expr;` with a new line at the end.
234#[derive(Clone, Debug)]
235pub struct ReturnStmt<Expr>(pub Expr);
236
237/// A let expression.
238/// This can be used, for example, as the condition of [IfBlock] in order to create an "if-let" block.
239#[derive(Clone, Debug)]
240pub struct LetExpr<Pattern, Expr>(pub Pattern, pub Expr);
241
242/// A raw string literal expression, i.e. r#"Content"#. Example:
243/// ```
244/// # use async_codegen::common::Str;
245/// # use async_codegen::context::EmptyContext;
246/// # use async_codegen::rust::RawStringLiteral;
247/// # use async_codegen::util::InMemoryOutput;
248/// let string_lit = RawStringLiteral(Str("hello_world"));
249///
250/// assert_eq!("r#\"hello_world\"#", InMemoryOutput::print_output(EmptyContext, &string_lit));
251/// ```
252#[derive(Clone, Debug)]
253pub struct RawStringLiteral<Content>(pub Content);
254
255/// An array literal with predefined elements written out.
256/// Renders as `[E1, E2, E3, ...]` where EX is in the element sequence.
257#[derive(Clone, Debug)]
258pub struct ArrayFromElements<Elements>(pub Elements);
259
260/// An array initialization literal with a default element and size.
261/// Renders as `[Default; Count]`.
262#[derive(Clone, Debug)]
263pub struct ArrayInit<Default, Count>(pub Default, pub Count);
264
265/// An item attached to an associated container, via "::".
266/// The output will look like `Cont::Item`.
267#[derive(Clone, Debug)]
268pub struct AssociatedItem<Cont, Item>(pub Cont, pub Item);
269
270/// A question mark following another expression.
271#[derive(Clone, Debug)]
272pub struct QuestionMarkAfter<Expr>(pub Expr);
273
274/// Uses the `as` expression to perform a qualified trait cast (e.g. ready for a method call).
275/// This will render as `<Type as Trait>`.
276#[derive(Clone, Debug)]
277pub struct TypeAsTrait<Type, Trait>(pub Type, pub Trait);
278
279/// Uses the `as` expression to coerce one type to another.
280/// This will render as `<Type1 as Type2>`.
281#[derive(Clone, Debug)]
282pub struct TypeAsType<Type1, Type2>(pub Type1, pub Type2);
283
284/// Declaration of an extern block, i.e. for FFI.
285/// In Rust 2024 and later, the unsafe keyword must be added for extern blocks. Thus, this struct
286/// requires that the context satisfies [ContextProvides] for [Edition].
287#[derive(Clone, Debug)]
288pub struct ExternBlock<Abi, Body> {
289    /// The ABI chosen. Must be writable
290    pub abi: Abi,
291    /// The body of the extern block. Must be writable
292    pub body: Body,
293}
294
295impl<Abi, Body> CanHaveAttributes for ExternBlock<Abi, Body> {
296    fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
297        WithAttributes {
298            attr,
299            separator: AttributeSeparator::NewLine,
300            value: self,
301        }
302    }
303}
304
305/// Declaration of a module block. Renders as `mod Name {Body}`.
306#[derive(Clone, Debug)]
307pub struct ModBlock<Name, Body> {
308    /// The module name
309    pub name: Name,
310    /// The body. Must be writable
311    pub body: Body,
312}
313
314/// An if block. The condition and body must both be writable.
315#[derive(Clone, Debug)]
316pub struct IfBlock<Cond, Body>(pub Cond, pub Body);
317
318/// Represents "else" syntactically. Renders as `Before else After`.
319///
320/// This struct requires you to specify what comes before and after the else. For example:
321/// ```
322/// # use async_codegen::common::Str;
323/// # use async_codegen::context::EmptyContext;
324/// # use async_codegen::rust::{Block, Else, IfBlock};
325/// # use async_codegen::util::InMemoryOutput;
326///
327/// let if_block = IfBlock(Str("true"), Str("log::info(\"Hello\")"));
328/// let else_block = Block(Str("panic!()"));
329/// let if_else = Else(if_block, else_block);
330///
331/// let string = InMemoryOutput::print_output(EmptyContext, &if_else);
332/// assert_eq!("if true {\nlog::info(\"Hello\")\n} else {\npanic!()\n}", string)
333/// ```
334#[derive(Clone, Debug)]
335pub struct Else<Before, After>(pub Before, pub After);
336
337/// An unlabeled block.
338/// This can be used in many contexts, including merely organizing the code.
339#[derive(Clone, Debug)]
340pub struct Block<Body>(pub Body);
341
342/// Places the expression inside an unsafe block.
343/// Adds new lines inside the brackets, wrapping the inner expression.
344#[derive(Clone, Debug)]
345pub struct UnsafeBlock<Expr>(pub Expr);
346
347/// Writes a closure.
348/// Adds new lines inside the brackets, wrapping the inner expression.
349#[derive(Clone, Debug)]
350pub struct Closure<InputVars, Expr> {
351    /// The input variables.
352    /// Should be a sequence. They will be comma separated and placed within the pipes.
353    /// To use no input variables, use [NoOpSeq].
354    pub input_vars: InputVars,
355    /// The expression inside the closure block.
356    pub inside_block: Expr,
357}
358
359/// Performs a call to a function inside code.
360#[derive(Clone, Debug)]
361pub struct FunctionCall<Recv, Name, Args> {
362    /// The function receiver
363    pub receiver: Recv,
364    /// Whether the function is associated, false if it's a method
365    pub is_assoc: bool,
366    /// The function name
367    pub name: Name,
368    /// The arguments. Must be a sequence
369    pub args: Args,
370}
371
372/// Provides access to the "turbofish" syntax, i.e. `Name::<Args>`.
373/// The first tuple value must be writable, and the second must be a sequence.
374///
375/// Note that if the sequence outputs nothing, this struct will behave as if no args were
376/// specified. I.e. `Turbofish(Name, NoOpSeq)` is equivalent to just `Name`.
377#[derive(Clone, Debug)]
378pub struct Turbofish<Name, Args>(pub Name, pub Args);
379
380/// Accesses a member by name. Renders as `Owner.Member`.
381///
382/// This can be used for named fields or tuple fields. for example:
383/// ```
384/// # use async_codegen::common::Str;
385/// # use async_codegen::context::EmptyContext;
386/// # use async_codegen::rust::{MemberAccess, LetStmt, RefOf};
387/// # use async_codegen::util::InMemoryOutput;
388/// let string = InMemoryOutput::print_output(EmptyContext, &LetStmt(
389///   Str("borrowed_field"), RefOf(MemberAccess(Str("my_var"), Str("my_field")))
390/// ));
391/// assert_eq!(string, "let borrowed_field = &my_var.my_field;\n");
392/// ```
393#[derive(Clone, Debug)]
394pub struct MemberAccess<Owner, Member>(pub Owner, pub Member);
395
396/// A function declaration
397#[derive(Clone, Debug)]
398pub struct FunctionDef<Mods, Name, Args, Return, Where, Body> {
399    /// The modifiers. Must be a sequence.
400    pub mods: Mods,
401    /// The function name. Type variables can be declared here via [Parameterized]
402    pub name: Name,
403    /// The arguments. Must be a sequence
404    pub args: Args,
405    /// The return type, i.e. after the `->` arrow
406    pub return_type: Return,
407    /// The "where" conditions. Must be a sequence. Set to [NoOp] to disable.
408    /// Will render as `where C1, C2, C3, ...` where CX is a value in the sequence.
409    pub where_conds: Where,
410    /// The function body.
411    /// To only declare the function, this must be `;` so use [FunctionBodyDeclare]
412    /// To implement the function, use [FunctionBodyImplement]
413    pub body: Body,
414}
415
416impl<Mods, Name, Args, Return, Where, Body> CanHaveAttributes
417    for FunctionDef<Mods, Name, Args, Return, Where, Body>
418{
419    fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
420        WithAttributes {
421            attr,
422            separator: AttributeSeparator::NewLine,
423            value: self,
424        }
425    }
426}
427
428/// Declares a function body. This is equivalent to just a semicolon.
429#[derive(Clone, Debug)]
430pub struct FunctionBodyDeclare;
431
432/// Implements a function body. Places the contents inside brackets
433#[derive(Clone, Debug)]
434pub struct FunctionBodyImplement<Inner>(pub Inner);
435
436/// A function pointer. Can be used for `fn`, `Fn`, `FnMut`, and `FnOnce`.
437///
438/// Example:
439/// ```
440/// # use async_codegen::common::{SingularSeq, Str};
441/// # use async_codegen::context::EmptyContext;
442/// # use async_codegen::rust::{FunctionPtr, FunctionPtrKind};
443/// # use async_codegen::util::InMemoryOutput;
444/// let function_ptr = FunctionPtr {
445///   kind: FunctionPtrKind::FnMut,
446///   args: SingularSeq(Str("String")),
447///   return_type: Str("bool")
448/// };
449/// let string = InMemoryOutput::print_output(EmptyContext, &function_ptr);
450/// assert_eq!("FnMut(String) -> bool", string);
451/// ```
452#[derive(Clone, Debug)]
453pub struct FunctionPtr<Args, Return> {
454    /// The function pointer kind
455    pub kind: FunctionPtrKind,
456    /// The arguments. Must be a sequence
457    pub args: Args,
458    /// The return type, i.e. after the `->` arrow
459    pub return_type: Return,
460}
461
462/// The kind of function type
463#[derive(Clone, Debug)]
464pub enum FunctionPtrKind {
465    /// An `fn` pointer. E.g. `fn(String) -> bool`.
466    FnPtr,
467    /// Represents [Fn]
468    Fn,
469    /// Represents [FnMut]
470    FnMut,
471    /// Represents [FnOnce]
472    FnOnce,
473}
474
475/// Renders as `Type=Value`. Intended to be used as a type argument, to specify associated types.
476#[derive(Clone, Debug)]
477pub struct AssociatedTypeEquals<Type, Value>(pub Type, pub Value);
478
479/// Adds a "dyn " before a type expression.
480#[derive(Clone, Debug)]
481pub struct DynOf<Type>(pub Type);
482
483/// Adds a "&" before a type expression
484#[derive(Clone, Debug)]
485pub struct RefOf<Expr>(pub Expr);
486
487/// Adds a "&mut " before a type expression
488#[derive(Clone, Debug)]
489pub struct RefMutOf<Expr>(pub Expr);
490
491/// Dereferences an expression using `*`
492#[derive(Clone, Debug)]
493pub struct Dereference<Expr>(pub Expr);
494
495/// Surrounds an expression with parentheses, rendering as `(Expr)`.
496/// Even if the expression is empty, the parentheses will still be rendered.
497#[derive(Clone, Debug)]
498pub struct ParenthesesAround<Expr>(pub Expr);
499
500/// Adds an "impl " before a type expression
501pub struct ImplOf<Type>(pub Type);
502
503/// Adds a reference with a lifetime before a type expression, i.e. `&'<lifetime> <type>`
504#[derive(Clone, Debug)]
505pub struct LifetimedRefOf<'l, Type>(pub &'l str, pub Type);
506
507/// Uses the `&raw const` syntax to get a pointer from another pointer. For example:
508/// ```
509/// # use async_codegen::common::Str;
510/// # use async_codegen::context::EmptyContext;
511/// # use async_codegen::rust::{MemberAccess, LetStmt, RawConstOf};
512/// # use async_codegen::util::InMemoryOutput;
513/// let pointer_var = Str("ptr");
514/// let let_stmt = LetStmt(pointer_var, RawConstOf(MemberAccess(Str("packed"), Str("field1"))));
515/// let string = InMemoryOutput::print_output(EmptyContext, &let_stmt);
516/// assert_eq!("let ptr = &raw const packed.field1;\n", string);
517/// ```
518#[derive(Clone, Debug)]
519pub struct RawConstOf<Expr>(pub Expr);
520
521/// Uses the `&raw must` syntax to get a pointer from another pointer. For example:
522/// ```
523/// # use async_codegen::common::Str;
524/// # use async_codegen::context::EmptyContext;
525/// # use async_codegen::rust::{MemberAccess, LetStmt, RawMutOf};
526/// # use async_codegen::util::InMemoryOutput;
527/// let pointer_var = Str("ptr");
528/// let let_stmt = LetStmt(pointer_var, RawMutOf(MemberAccess(Str("packed"), Str("field1"))));
529/// let string = InMemoryOutput::print_output(EmptyContext, &let_stmt);
530/// assert_eq!("let ptr = &raw mut packed.field1;\n", string);
531/// ```
532#[derive(Clone, Debug)]
533pub struct RawMutOf<Expr>(pub Expr);
534
535/// A `*const Type` for some arbitrary type
536#[derive(Clone, Debug)]
537pub struct ConstPtr<Type>(pub Type);
538
539/// A `*mut Type` for some arbitrary type.
540#[derive(Clone, Debug)]
541pub struct MutPtr<Type>(pub Type);
542
543/// Declares a type, rendering as `type Value;` Adds a new line after.
544///
545/// Can be used for multiple purposes:
546/// - Creating a type alias, free-form
547/// - Defining an associated type (use [FillOutField])
548/// - Declaring the value of an associated type (use [AssignExpr])
549///
550/// Example using traits and associated types:
551/// ```
552/// use async_codegen::common::{Combined, NoOpSeq, SingularSeq, Str};
553/// use async_codegen::context::EmptyContext;
554/// use async_codegen::rust::{AssignExpr, FillOutField, Lifetime, LifetimedRefOf, Parameterized, TraitDef, TraitImpl, TypeDeclare};
555/// use async_codegen::util::InMemoryOutput;
556///
557/// let trait_def = TraitDef {
558///   mods: NoOpSeq,
559///   name: Str("MyTrait"),
560///   type_variables: NoOpSeq,
561///   super_traits: NoOpSeq,
562///   body: TypeDeclare(FillOutField(Parameterized(Str("Special"), SingularSeq(Lifetime("s"))), Str("Clone")))
563/// };
564/// let trait_impl = TraitImpl {
565///   mods: NoOpSeq,
566///   type_variables: NoOpSeq,
567///   the_trait: Str("MyTrait"),
568///   receiver: Str("()"),
569///   where_conds: NoOpSeq,
570///   body: TypeDeclare(AssignExpr(Parameterized(Str("Special"), SingularSeq(Lifetime("s"))), LifetimedRefOf("s", Str("str"))))
571/// };
572/// let string = InMemoryOutput::print_output(EmptyContext, &Combined(trait_def, trait_impl));
573/// assert_eq!(r#"trait MyTrait {
574///type Special<'s>: Clone;
575///
576///}
577///
578///impl MyTrait for () {
579///type Special<'s> = &'s str;
580///
581///}
582///
583///"#, string);
584/// ```
585#[derive(Clone, Debug)]
586pub struct TypeDeclare<Value>(pub Value);
587
588/// The declaration of a trait
589#[derive(Clone, Debug)]
590pub struct TraitDef<Mods, Name, TypeVars, SuperTraits, Body> {
591    /// The trait modifiers, e.g. visibility. Must be a sequence.
592    pub mods: Mods,
593    /// The name of the trait
594    pub name: Name,
595    /// The type variables. Must be a sequence
596    pub type_variables: TypeVars,
597    /// The super traits. Must be a sequence
598    pub super_traits: SuperTraits,
599    /// The trait definition's body. Use [NoOp] if none exists.
600    pub body: Body,
601}
602
603impl<Mods, Name, TypeVars, SuperTraits, Body> CanHaveAttributes
604    for TraitDef<Mods, Name, TypeVars, SuperTraits, Body>
605{
606    fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
607        WithAttributes {
608            attr,
609            separator: AttributeSeparator::NewLine,
610            value: self,
611        }
612    }
613}
614
615/// The implementation declaration for a trait, applying to a certain receiver.
616#[derive(Clone, Debug)]
617pub struct TraitImpl<Mods, TypeVars, Trait, Recv, Where, Body> {
618    /// The modifiers on the `impl` block.
619    /// Set to [NoOpSeq] for none, or use `SingularSeq(ModUnsafe)` to generate an `unsafe impl`.
620    pub mods: Mods,
621    /// The type variables to use for the impl block itself. All type variables that appear later
622    /// on the trait or the receiver must be declared here, per Rust language rules.
623    ///
624    /// This field must be a sequence.
625    pub type_variables: TypeVars,
626    /// The trait being implemented
627    pub the_trait: Trait,
628    /// The receiver for which it is implemented
629    pub receiver: Recv,
630    /// The "where" conditions. Must be a sequence. Set to [NoOpSeq] to disable.
631    /// Will render as `where C1, C2, C3, ...` where CX is a value in the sequence.
632    pub where_conds: Where,
633    /// The body. Use [NoOp] if none exists.
634    pub body: Body,
635}
636
637impl<Mods, TypeVars, Trait, Recv, Where, Body> CanHaveAttributes
638    for TraitImpl<Mods, TypeVars, Trait, Recv, Where, Body>
639{
640    fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
641        WithAttributes {
642            attr,
643            separator: AttributeSeparator::NewLine,
644            value: self,
645        }
646    }
647}
648
649/// An impl block.
650///
651/// For impls of a trait for a certain receiver, it is suggested to use [TraitImpl].
652#[derive(Clone, Debug)]
653pub struct Impl<Mods, TypeVars, Recv, Where, Body> {
654    /// The modifiers on the `impl` block.
655    /// Set to [NoOpSeq] for none, or use `SingularSeq(ModUnsafe)` to generate an `unsafe impl`.
656    pub mods: Mods,
657    /// The type variables to use for the impl block itself. All type variables that appear later
658    /// on the trait or the receiver must be declared here, per Rust language rules.
659    ///
660    /// This field must be a sequence.
661    pub type_variables: TypeVars,
662    /// The receiver for which the implementation exists
663    pub receiver: Recv,
664    /// The "where" conditions. Must be a sequence. Set to [NoOpSeq] to disable.
665    /// Will render as `where C1, C2, C3, ...` where CX is a value in the sequence.
666    pub where_conds: Where,
667    /// The body. Use [NoOp] if none exists.
668    pub body: Body,
669}
670
671impl<Mods, TypeVars, Recv, Where, Body> CanHaveAttributes
672    for Impl<Mods, TypeVars, Recv, Where, Body>
673{
674    fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
675        WithAttributes {
676            attr,
677            separator: AttributeSeparator::NewLine,
678            value: self,
679        }
680    }
681}
682
683/// The declaration of a struct.
684#[derive(Clone, Debug)]
685pub struct StructDef<Mods, Name, Elements> {
686    /// The struct modifiers. Must be a sequence.
687    pub mods: Mods,
688    /// The kind of the struct.
689    ///
690    /// It is suggested to use either a [NamedTuple] or [StructCall]. A semicolon will be
691    /// automatically added afterward, as is needed for tuple structs, and this semicolon will not
692    /// affect structs with named fields.
693    pub kind: StructKind<Name, Elements>,
694}
695
696impl<Mods, Name, Elements> CanHaveAttributes for StructDef<Mods, Name, Elements> {
697    fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
698        WithAttributes {
699            attr,
700            separator: AttributeSeparator::NewLine,
701            value: self,
702        }
703    }
704}
705
706/// Completes the struct definition as either a named tuple or a struct with named fields.
707#[derive(Clone, Debug)]
708pub enum StructKind<Name, Elements> {
709    /// A named tuple. This will function similarly to [NamedTuple], except a semicolon will
710    /// be added afterward.
711    ///
712    /// `Name` must be writable, and `Elements` must be a writable sequence for the tuple arguments.
713    Tuple(Name, Elements),
714    /// A struct with named fields. This will function similarly to [StructCall].
715    ///
716    /// `Name` must be writable, and `Elements` must be writable sequence for the struct fields.
717    NamedFields(Name, Elements),
718}
719
720/// The construction or deconstruction of a struct.
721///
722/// When rendered, will use the format `Name { Body }`. Spaces will be added automatically.
723///
724/// This should **not** be used for tuple structs, for that see [NamedTuple].
725#[derive(Clone, Debug)]
726pub struct StructCall<Name, Body> {
727    /// The struct name. Must be writable.
728    ///
729    /// If you are declaring a struct for the first time, you can use [Parameterized] in order
730    /// to declare type variables.
731    pub name: Name,
732    /// The body. Must be writable.
733    ///
734    /// It is suggested to use [StructFields] for multiple fields, or [DeclareField] or
735    /// [FillOutField] for just one.
736    pub body: Body,
737}
738
739/// Named struct fields. This will place every field on a new line with a comma afterward.
740/// It is recommended that the sequence should pass [DeclareField] or [FillOutField] depending
741/// upon whether the struct is being
742///
743/// If you have a single field, you can skip using a sequence and just use [DeclareField] or
744/// [FillOutField] directly.
745#[derive(Clone, Debug)]
746pub struct StructFields<Fields>(pub Fields);
747
748/// Declares a single field within a struct.
749///
750/// Does not add attributes. If you want to use attributes for declaration purposes, you can use
751/// [CanHaveAttributes::with_attributes] on this field.
752#[derive(Clone, Debug)]
753pub struct DeclareField<Mods, Name, FieldType> {
754    /// The field modifiers. Must be a sequence.
755    pub mods: Mods,
756    /// The name. Must be writable
757    pub name: Name,
758    /// The field type. Must be writable
759    pub field_type: FieldType,
760}
761
762impl<Mods, Name, Value> CanHaveAttributes for DeclareField<Mods, Name, Value> {
763    fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
764        WithAttributes {
765            attr,
766            separator: AttributeSeparator::NewLine,
767            value: self,
768        }
769    }
770}
771
772/// Provides a field upon struct creation. Renders as `Name: Value`
773#[derive(Clone, Debug)]
774pub struct FillOutField<Name, Value>(pub Name, pub Value);
775
776/// A named tuple type.
777///
778/// Renders as `Name(A1, A2, A3, ...)` where AX is part of the argument sequence.
779/// If no arguments exist, will render only as `Name` (i.e., a unit struct).
780#[derive(Clone, Debug)]
781pub struct NamedTuple<Name, Args> {
782    pub name: Name,
783    pub args: Args,
784}
785
786/// An anonymous tuple type. This struct's tuple value must be a sequence.
787///
788/// Renders as `(A1, A2, A3, ...)` where AX is part of the argument sequence.
789#[derive(Clone, Debug)]
790pub struct AnonTuple<Args>(pub Args);
791
792/// The unit type, i.e. `()`
793pub type UnitType = AnonTuple<NoOpSeq>;
794
795impl AnonTuple<NoOpSeq> {
796    /// Creates
797    pub fn unit() -> Self {
798        Self(NoOpSeq)
799    }
800}
801
802/// Adds attributes to ANY item.
803///
804/// The first tuple value must be a sequence. The second must be a writable value. This struct
805/// is typically constructed via [CanHaveAttributes::with_attributes].
806///
807/// Rust attributes can be put in many places, so this enables you to add attributes to any
808/// writable item. For example, adding attributes to function parameters can be done like so:
809///
810/// ```rust
811/// # use async_codegen::common::{SingularSeq, Str};
812/// # use async_codegen::context::EmptyContext;
813/// # use async_codegen::rust::{Cfg, FunctionParam, MustUse, Target, WithAttributes, CanHaveAttributes};
814/// # use async_codegen::util::InMemoryOutput;
815///
816/// let function_param = FunctionParam(Str("conditional_param"), Str("Fd")).with_attributes(
817///   SingularSeq(Cfg(Target::Os(Str("linux"))))
818/// );
819/// let string = InMemoryOutput::print_output(EmptyContext, &function_param);
820/// assert_eq!("#[cfg(target_os = \"linux\")] conditional_param: Fd", string);
821/// ```
822#[derive(Clone, Debug)]
823pub struct WithAttributes<Attr, Value> {
824    /// The attributes. Must be a sequence.
825    pub attr: Attr,
826    /// The separator between each attribute
827    pub separator: AttributeSeparator,
828    /// The value
829    pub value: Value,
830}
831
832#[derive(Copy, Clone, Debug)]
833pub enum AttributeSeparator {
834    Space,
835    NewLine,
836}
837
838/// A writable that can have attributes attached to it
839pub trait CanHaveAttributes: Sized {
840    /// Adds attributes to this writable
841    fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self>;
842}
843
844/// Defines an enum.
845///
846/// In order to use or refer to an enum, you can use [AssociatedItem] together with [NamedTuple]
847/// or [StructCall].
848#[derive(Clone, Debug)]
849pub struct EnumDef<Mods, Name, Entries> {
850    /// The modifiers on the type. Must be a sequence.
851    pub mods: Mods,
852    /// The name of the enum
853    pub name: Name,
854    /// The enum entries. Must be a sequence, each entry will be written on a new line with a comma
855    ///
856    /// As for the entries themselves, it is suggested to use [NamedTuple] or [StructCall]
857    /// depending on which kind of enum entry you want to create.
858    pub entries: Entries,
859}
860
861impl<Mods, Name, Entries> CanHaveAttributes for EnumDef<Mods, Name, Entries> {
862    fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
863        WithAttributes {
864            attr,
865            separator: AttributeSeparator::NewLine,
866            value: self,
867        }
868    }
869}
870
871/// A type argument-parameterized expression. Used in relation to parameterized names and their
872/// arguments. Examples: `function_name<args>`, `TypeName<'lifetime, args>`, `MyType<Assoc=Value>`.
873///
874/// If no type args exist, [NoOpSeq] should be used. In any case, the second tuple value of this
875/// struct must be a sequence. If they are empty, only `Name` will be rendered.
876#[derive(Clone, Debug)]
877pub struct Parameterized<Name, TypeArgs>(pub Name, pub TypeArgs);
878
879/// A type variable with a sequence of bounds.
880/// Will render as `TypeVar: B1 + B2 + ...`
881#[derive(Clone, Debug)]
882pub struct BoundedTypeVar<TypeVar, Bounds>(pub TypeVar, pub Bounds);
883
884/// A standalone lifetime, intended to be used as a type argument or variable
885#[derive(Clone, Debug)]
886pub struct Lifetime<'l>(pub &'l str);
887
888/// Renders an individual function parameter, `Name: Type`
889#[derive(Clone, Debug)]
890pub struct FunctionParam<Name, Type>(pub Name, pub Type);
891
892impl<Name, Type> CanHaveAttributes for FunctionParam<Name, Type> {
893    fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
894        WithAttributes {
895            attr,
896            separator: AttributeSeparator::Space,
897            value: self,
898        }
899    }
900}
901
902/// A sequence acceptor that writes attributes. Every attribute will be surrounded with "#[]"
903#[derive(Debug)]
904pub struct AttributesAccept<'o, O, Sep> {
905    inner: SurroundingSeqAccept<'o, O, Str<&'static str>, Combined<Str<&'static str>, Sep>>,
906}
907
908impl<'o, O, Sep> AttributesAccept<'o, O, Sep> {
909    pub fn with_separator(output: &'o mut O, separator: Sep) -> Self {
910        Self {
911            inner: SurroundingSeqAccept::new(output, Str("#["), Combined(Str("]"), separator)),
912        }
913    }
914}
915
916impl<'o, O, Sep> SequenceAccept<O> for AttributesAccept<'o, O, Sep>
917where
918    O: Output,
919    Sep: Writable<O>,
920{
921    async fn accept<W: Writable<O>>(&mut self, writable: &W) -> Result<(), O::Error> {
922        self.inner.accept(writable).await
923    }
924}