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/// An assignation. This statement includes the semicolon and a new line.
222#[derive(Clone, Debug)]
223pub struct AssignStmt<Variable, Expr>(pub Variable, pub Expr);
224
225/// A return statement. Renders as `return Expr;` with a new line at the end.
226#[derive(Clone, Debug)]
227pub struct ReturnStmt<Expr>(pub Expr);
228
229/// A let expression.
230/// This can be used, for example, as the condition of [IfBlock] in order to create an "if-let" block.
231#[derive(Clone, Debug)]
232pub struct LetExpr<Pattern, Expr>(pub Pattern, pub Expr);
233
234/// A raw string literal expression, i.e. r#"Content"#. Example:
235/// ```
236/// # use async_codegen::common::Str;
237/// # use async_codegen::context::EmptyContext;
238/// # use async_codegen::rust::RawStringLiteral;
239/// # use async_codegen::util::InMemoryOutput;
240/// let string_lit = RawStringLiteral(Str("hello_world"));
241///
242/// assert_eq!("r#\"hello_world\"#", InMemoryOutput::print_output(EmptyContext, &string_lit));
243/// ```
244#[derive(Clone, Debug)]
245pub struct RawStringLiteral<Content>(pub Content);
246
247/// An array literal with predefined elements written out.
248/// Renders as `[E1, E2, E3, ...]` where EX is in the element sequence.
249#[derive(Clone, Debug)]
250pub struct ArrayFromElements<Elements>(pub Elements);
251
252/// An item attached to an associated container, via "::".
253/// The output will look like `Cont::Item`.
254#[derive(Clone, Debug)]
255pub struct AssociatedItem<Cont, Item>(pub Cont, pub Item);
256
257/// A question mark following another expression.
258#[derive(Clone, Debug)]
259pub struct QuestionMarkAfter<Expr>(pub Expr);
260
261/// Uses the `as` expression to perform a qualified trait cast (e.g. ready for a method call).
262/// This will render as `<Type as Trait>`.
263#[derive(Clone, Debug)]
264pub struct TypeAsTrait<Type, Trait>(pub Type, pub Trait);
265
266/// Uses the `as` expression to coerce one type to another.
267/// This will render as `<Type1 as Type2>`.
268#[derive(Clone, Debug)]
269pub struct TypeAsType<Type1, Type2>(pub Type1, pub Type2);
270
271/// Declaration of an extern block, i.e. for FFI.
272/// In Rust 2024 and later, the unsafe keyword must be added for extern blocks. Thus, this struct
273/// requires that the context satisfies [ContextProvides] for [Edition].
274#[derive(Clone, Debug)]
275pub struct ExternBlock<Abi, Body> {
276 /// The ABI chosen. Must be writable
277 pub abi: Abi,
278 /// The body of the extern block. Must be writable
279 pub body: Body,
280}
281
282impl<Abi, Body> CanHaveAttributes for ExternBlock<Abi, Body> {
283 fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
284 WithAttributes {
285 attr,
286 separator: AttributeSeparator::NewLine,
287 value: self,
288 }
289 }
290}
291
292/// Declaration of a module block. Renders as `mod Name {Body}`.
293#[derive(Clone, Debug)]
294pub struct ModBlock<Name, Body> {
295 /// The module name
296 pub name: Name,
297 /// The body. Must be writable
298 pub body: Body,
299}
300
301/// An if block. The condition and body must both be writable.
302#[derive(Clone, Debug)]
303pub struct IfBlock<Cond, Body>(pub Cond, pub Body);
304
305/// Represents "else" syntactically. Renders as `Before else After`.
306///
307/// This struct requires you to specify what comes before and after the else. For example:
308/// ```
309/// # use async_codegen::common::Str;
310/// # use async_codegen::context::EmptyContext;
311/// # use async_codegen::rust::{Block, Else, IfBlock};
312/// # use async_codegen::util::InMemoryOutput;
313///
314/// let if_block = IfBlock(Str("true"), Str("log::info(\"Hello\")"));
315/// let else_block = Block(Str("panic!()"));
316/// let if_else = Else(if_block, else_block);
317///
318/// let string = InMemoryOutput::print_output(EmptyContext, &if_else);
319/// assert_eq!("if true {\nlog::info(\"Hello\")\n} else {\npanic!()\n}", string)
320/// ```
321#[derive(Clone, Debug)]
322pub struct Else<Before, After>(pub Before, pub After);
323
324/// An unlabeled block.
325/// This can be used in many contexts, including merely organizing the code.
326#[derive(Clone, Debug)]
327pub struct Block<Body>(pub Body);
328
329/// Places the expression inside an unsafe block.
330/// Adds new lines inside the brackets, wrapping the inner expression.
331#[derive(Clone, Debug)]
332pub struct UnsafeBlock<Expr>(pub Expr);
333
334/// Writes a closure.
335/// Adds new lines inside the brackets, wrapping the inner expression.
336#[derive(Clone, Debug)]
337pub struct Closure<InputVars, Expr> {
338 /// The input variables.
339 /// Should be a sequence. They will be comma separated and placed within the pipes.
340 /// To use no input variables, use [NoOpSeq].
341 pub input_vars: InputVars,
342 /// The expression inside the closure block.
343 pub inside_block: Expr,
344}
345
346/// Performs a call to a function inside code.
347#[derive(Clone, Debug)]
348pub struct FunctionCall<Recv, Name, Args> {
349 /// The function receiver
350 pub receiver: Recv,
351 /// Whether the function is associated, false if it's a method
352 pub is_assoc: bool,
353 /// The function name
354 pub name: Name,
355 /// The arguments. Must be a sequence
356 pub args: Args,
357}
358
359/// Provides access to the "turbofish" syntax, i.e. `Name::<Args>`.
360/// The first tuple value must be writable, and the second must be a sequence.
361///
362/// Note that if the sequence outputs nothing, this struct will behave as if no args were
363/// specified. I.e. `Turbofish(Name, NoOpSeq)` is equivalent to just `Name`.
364#[derive(Clone, Debug)]
365pub struct Turbofish<Name, Args>(pub Name, pub Args);
366
367/// Accesses a struct field by name. Can be used for named fields or tuple fields.
368/// Renders as `Owner.Field`. For example:
369/// ```
370/// # use async_codegen::common::Str;
371/// # use async_codegen::context::EmptyContext;
372/// # use async_codegen::rust::{FieldAccess, LetStmt, RefOf};
373/// # use async_codegen::util::InMemoryOutput;
374/// let string = InMemoryOutput::print_output(EmptyContext, &LetStmt(
375/// Str("borrowed_field"), RefOf(FieldAccess(Str("my_var"), Str("my_field")))
376/// ));
377/// assert_eq!(string, "let borrowed_field = &my_var.my_field;\n");
378/// ```
379#[derive(Clone, Debug)]
380pub struct FieldAccess<Owner, Field>(pub Owner, pub Field);
381
382/// A function declaration
383#[derive(Clone, Debug)]
384pub struct FunctionDef<Mods, Name, Args, Return, Where, Body> {
385 /// The modifiers. Must be a sequence.
386 pub mods: Mods,
387 /// The function name. Type variables can be declared here via [Parameterized]
388 pub name: Name,
389 /// The arguments. Must be a sequence
390 pub args: Args,
391 /// The return type, i.e. after the `->` arrow
392 pub return_type: Return,
393 /// The "where" conditions. Must be a sequence. Set to [NoOp] to disable.
394 /// Will render as `where C1, C2, C3, ...` where CX is a value in the sequence.
395 pub where_conds: Where,
396 /// The function body.
397 /// To only declare the function, this must be `;` so use [FunctionBodyDeclare]
398 /// To implement the function, use [FunctionBodyImplement]
399 pub body: Body,
400}
401
402impl<Mods, Name, Args, Return, Where, Body> CanHaveAttributes
403 for FunctionDef<Mods, Name, Args, Return, Where, Body>
404{
405 fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
406 WithAttributes {
407 attr,
408 separator: AttributeSeparator::NewLine,
409 value: self,
410 }
411 }
412}
413
414/// Declares a function body. This is equivalent to just a semicolon.
415#[derive(Clone, Debug)]
416pub struct FunctionBodyDeclare;
417
418/// Implements a function body. Places the contents inside brackets
419#[derive(Clone, Debug)]
420pub struct FunctionBodyImplement<Inner>(pub Inner);
421
422/// A function pointer. Can be used for `fn`, `Fn`, `FnMut`, and `FnOnce`.
423///
424/// Example:
425/// ```
426/// # use async_codegen::common::{SingularSeq, Str};
427/// # use async_codegen::context::EmptyContext;
428/// # use async_codegen::rust::{FunctionPtr, FunctionPtrKind};
429/// # use async_codegen::util::InMemoryOutput;
430/// let function_ptr = FunctionPtr {
431/// kind: FunctionPtrKind::FnMut,
432/// args: SingularSeq(Str("String")),
433/// return_type: Str("bool")
434/// };
435/// let string = InMemoryOutput::print_output(EmptyContext, &function_ptr);
436/// assert_eq!("FnMut(String) -> bool", string);
437/// ```
438#[derive(Clone, Debug)]
439pub struct FunctionPtr<Args, Return> {
440 /// The function pointer kind
441 pub kind: FunctionPtrKind,
442 /// The arguments. Must be a sequence
443 pub args: Args,
444 /// The return type, i.e. after the `->` arrow
445 pub return_type: Return,
446}
447
448/// The kind of function type
449#[derive(Clone, Debug)]
450pub enum FunctionPtrKind {
451 /// An `fn` pointer. E.g. `fn(String) -> bool`.
452 FnPtr,
453 /// Represents [Fn]
454 Fn,
455 /// Represents [FnMut]
456 FnMut,
457 /// Represents [FnOnce]
458 FnOnce,
459}
460
461/// Renders as `Type=Value`. Intended to be used as a type argument, to specify associated types.
462#[derive(Clone, Debug)]
463pub struct AssociatedTypeEquals<Type, Value>(pub Type, pub Value);
464
465/// Adds a "dyn " before a type expression.
466#[derive(Clone, Debug)]
467pub struct DynOf<Type>(pub Type);
468
469/// Adds a "&" before a type expression
470#[derive(Clone, Debug)]
471pub struct RefOf<Expr>(pub Expr);
472
473/// Dereferences an expression using `*`
474#[derive(Clone, Debug)]
475pub struct Dereference<Expr>(pub Expr);
476
477/// Surrounds an expression with parentheses, rendering as `(Expr)`.
478/// Even if the expression is empty, the parentheses will still be rendered.
479#[derive(Clone, Debug)]
480pub struct ParenthesesAround<Expr>(pub Expr);
481
482/// Adds an "impl " before a type expression
483pub struct ImplOf<Type>(pub Type);
484
485/// Adds a reference with a lifetime before a type expression, i.e. `&'<lifetime> <type>`
486#[derive(Clone, Debug)]
487pub struct LifetimedRefOf<'l, Type>(pub &'l str, pub Type);
488
489/// Uses the `&raw const` syntax to get a pointer from another pointer. For example:
490/// ```
491/// # use async_codegen::common::Str;
492/// # use async_codegen::context::EmptyContext;
493/// # use async_codegen::rust::{FieldAccess, LetStmt, RawConstOf};
494/// # use async_codegen::util::InMemoryOutput;
495/// let pointer_var = Str("ptr");
496/// let let_stmt = LetStmt(pointer_var, RawConstOf(FieldAccess(Str("packed"), Str("field1"))));
497/// let string = InMemoryOutput::print_output(EmptyContext, &let_stmt);
498/// assert_eq!("let ptr = &raw const packed.field1;\n", string);
499/// ```
500#[derive(Clone, Debug)]
501pub struct RawConstOf<Expr>(pub Expr);
502
503/// Uses the `&raw must` syntax to get a pointer from another pointer. For example:
504/// ```
505/// # use async_codegen::common::Str;
506/// # use async_codegen::context::EmptyContext;
507/// # use async_codegen::rust::{FieldAccess, LetStmt, RawMutOf};
508/// # use async_codegen::util::InMemoryOutput;
509/// let pointer_var = Str("ptr");
510/// let let_stmt = LetStmt(pointer_var, RawMutOf(FieldAccess(Str("packed"), Str("field1"))));
511/// let string = InMemoryOutput::print_output(EmptyContext, &let_stmt);
512/// assert_eq!("let ptr = &raw mut packed.field1;\n", string);
513/// ```
514#[derive(Clone, Debug)]
515pub struct RawMutOf<Expr>(pub Expr);
516
517/// A `*const Type` for some arbitrary type
518#[derive(Clone, Debug)]
519pub struct ConstPtr<Type>(pub Type);
520
521/// A `*mut Type` for some arbitrary type.
522#[derive(Clone, Debug)]
523pub struct MutPtr<Type>(pub Type);
524
525/// Declares an associated type, rendering as `type VarName = Value;`.
526/// Adds new lines before and after.
527#[derive(Clone, Debug)]
528pub struct AssociatedTypeDef<VarName, Value>(pub VarName, pub Value);
529
530/// The declaration of a trait
531#[derive(Clone, Debug)]
532pub struct TraitDef<Mods, Name, TypeVars, SuperTraits, Body> {
533 /// The trait modifiers, e.g. visibility. Must be a sequence.
534 pub mods: Mods,
535 /// The name of the trait
536 pub name: Name,
537 /// The type variables. Must be a sequence
538 pub type_variables: TypeVars,
539 /// The super traits. Must be a sequence
540 pub super_traits: SuperTraits,
541 /// The trait definition's body. Use [NoOp] if none exists.
542 pub body: Body,
543}
544
545impl<Mods, Name, TypeVars, SuperTraits, Body> CanHaveAttributes
546 for TraitDef<Mods, Name, TypeVars, SuperTraits, Body>
547{
548 fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
549 WithAttributes {
550 attr,
551 separator: AttributeSeparator::NewLine,
552 value: self,
553 }
554 }
555}
556
557/// The implementation declaration for a trait, applying to a certain receiver.
558#[derive(Clone, Debug)]
559pub struct TraitImpl<Mods, TypeVars, Trait, Recv, Where, Body> {
560 /// The modifiers on the `impl` block.
561 /// Set to [NoOpSeq] for none, or use `SingularSeq(ModUnsafe)` to generate an `unsafe impl`.
562 pub mods: Mods,
563 /// The type variables to use for the impl block itself. All type variables that appear later
564 /// on the trait or the receiver must be declared here, per Rust language rules.
565 ///
566 /// This field must be a sequence.
567 pub type_variables: TypeVars,
568 /// The trait being implemented
569 pub the_trait: Trait,
570 /// The receiver for which it is implemented
571 pub receiver: Recv,
572 /// The "where" conditions. Must be a sequence. Set to [NoOpSeq] to disable.
573 /// Will render as `where C1, C2, C3, ...` where CX is a value in the sequence.
574 pub where_conds: Where,
575 /// The body. Use [NoOp] if none exists.
576 pub body: Body,
577}
578
579impl<Mods, TypeVars, Trait, Recv, Where, Body> CanHaveAttributes
580 for TraitImpl<Mods, TypeVars, Trait, Recv, Where, Body>
581{
582 fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
583 WithAttributes {
584 attr,
585 separator: AttributeSeparator::NewLine,
586 value: self,
587 }
588 }
589}
590
591/// The declaration of a struct.
592#[derive(Clone, Debug)]
593pub struct StructDef<Mods, Name, Elements> {
594 /// The struct modifiers. Must be a sequence.
595 pub mods: Mods,
596 /// The kind of the struct.
597 ///
598 /// It is suggested to use either a [NamedTuple] or [StructCall]. A semicolon will be
599 /// automatically added afterward, as is needed for tuple structs, and this semicolon will not
600 /// affect structs with named fields.
601 pub kind: StructKind<Name, Elements>,
602}
603
604impl<Mods, Name, Elements> CanHaveAttributes for StructDef<Mods, Name, Elements> {
605 fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
606 WithAttributes {
607 attr,
608 separator: AttributeSeparator::NewLine,
609 value: self,
610 }
611 }
612}
613
614/// Completes the struct definition as either a named tuple or a struct with named fields.
615#[derive(Clone, Debug)]
616pub enum StructKind<Name, Elements> {
617 /// A named tuple. This will function similarly to [NamedTuple], except a semicolon will
618 /// be added afterward.
619 ///
620 /// `Name` must be writable, and `Elements` must be a writable sequence for the tuple arguments.
621 Tuple(Name, Elements),
622 /// A struct with named fields. This will function similarly to [StructCall].
623 ///
624 /// `Name` must be writable, and `Elements` must be writable sequence for the struct fields.
625 NamedFields(Name, Elements),
626}
627
628/// The construction or deconstruction of a struct.
629///
630/// When rendered, will use the format `Name { Body }`. Spaces will be added automatically.
631///
632/// This should **not** be used for tuple structs, for that see [NamedTuple].
633#[derive(Clone, Debug)]
634pub struct StructCall<Name, Body> {
635 /// The struct name. Must be writable.
636 ///
637 /// If you are declaring a struct for the first time, you can use [Parameterized] in order
638 /// to declare type variables.
639 pub name: Name,
640 /// The body. Must be writable.
641 ///
642 /// It is suggested to use [StructFields] for multiple fields, or [DeclareField] or
643 /// [FillOutField] for just one.
644 pub body: Body,
645}
646
647/// Named struct fields. This will place every field on a new line with a comma afterward.
648/// It is recommended that the sequence should pass [DeclareField] or [FillOutField] depending
649/// upon whether the struct is being
650///
651/// If you have a single field, you can skip using a sequence and just use [DeclareField] or
652/// [FillOutField] directly.
653#[derive(Clone, Debug)]
654pub struct StructFields<Fields>(pub Fields);
655
656/// Declares a single field within a struct.
657///
658/// Does not add attributes. If you want to use attributes for declaration purposes, you can use
659/// [CanHaveAttributes::with_attributes] on this field.
660#[derive(Clone, Debug)]
661pub struct DeclareField<Mods, Name, Value> {
662 /// The field modifiers. Must be a sequence.
663 pub mods: Mods,
664 /// The name. Must be writable
665 pub name: Name,
666 /// The value. Must be writable
667 pub value: Value,
668}
669
670impl<Mods, Name, Value> CanHaveAttributes for DeclareField<Mods, Name, Value> {
671 fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
672 WithAttributes {
673 attr,
674 separator: AttributeSeparator::NewLine,
675 value: self,
676 }
677 }
678}
679
680/// Provides a field upon struct creation. Renders as `Name: Value`
681#[derive(Clone, Debug)]
682pub struct FillOutField<Name, Value>(pub Name, pub Value);
683
684/// A named tuple type.
685///
686/// Renders as `Name(A1, A2, A3, ...)` where AX is part of the argument sequence.
687/// If no arguments exist, will render only as `Name` (i.e., a unit struct).
688#[derive(Clone, Debug)]
689pub struct NamedTuple<Name, Args> {
690 pub name: Name,
691 pub args: Args,
692}
693
694/// An anonymous tuple type. This struct's tuple value must be a sequence.
695///
696/// Renders as `(A1, A2, A3, ...)` where AX is part of the argument sequence.
697#[derive(Clone, Debug)]
698pub struct AnonTuple<Args>(pub Args);
699
700/// The unit type, i.e. `()`
701pub type UnitType = AnonTuple<NoOpSeq>;
702
703impl AnonTuple<NoOpSeq> {
704 /// Creates
705 pub fn unit() -> Self {
706 Self(NoOpSeq)
707 }
708}
709
710/// Adds attributes to ANY item.
711///
712/// The first tuple value must be a sequence. The second must be a writable value. This struct
713/// is typically constructed via [CanHaveAttributes::with_attributes].
714///
715/// Rust attributes can be put in many places, so this enables you to add attributes to any
716/// writable item. For example, adding attributes to function parameters can be done like so:
717///
718/// ```rust
719/// # use async_codegen::common::{SingularSeq, Str};
720/// # use async_codegen::context::EmptyContext;
721/// # use async_codegen::rust::{Cfg, FunctionParam, MustUse, Target, WithAttributes, CanHaveAttributes};
722/// # use async_codegen::util::InMemoryOutput;
723///
724/// let function_param = FunctionParam(Str("conditional_param"), Str("Fd")).with_attributes(
725/// SingularSeq(Cfg(Target::Os(Str("linux"))))
726/// );
727/// let string = InMemoryOutput::print_output(EmptyContext, &function_param);
728/// assert_eq!("#[cfg(target_os = \"linux\")] conditional_param: Fd", string);
729/// ```
730#[derive(Clone, Debug)]
731pub struct WithAttributes<Attr, Value> {
732 /// The attributes. Must be a sequence.
733 pub attr: Attr,
734 /// The separator between each attribute
735 pub separator: AttributeSeparator,
736 /// The value
737 pub value: Value,
738}
739
740#[derive(Copy, Clone, Debug)]
741pub enum AttributeSeparator {
742 Space,
743 NewLine,
744}
745
746/// A writable that can have attributes attached to it
747pub trait CanHaveAttributes: Sized {
748 /// Adds attributes to this writable
749 fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self>;
750}
751
752/// Defines an enum.
753///
754/// In order to use or refer to an enum, you can use [AssociatedItem] together with [NamedTuple]
755/// or [StructCall].
756#[derive(Clone, Debug)]
757pub struct EnumDef<Mods, Name, Entries> {
758 /// The modifiers on the type. Must be a sequence.
759 pub mods: Mods,
760 /// The name of the enum
761 pub name: Name,
762 /// The enum entries. Must be a sequence, each entry will be written on a new line with a comma
763 ///
764 /// As for the entries themselves, it is suggested to use [NamedTuple] or [StructCall]
765 /// depending on which kind of enum entry you want to create.
766 pub entries: Entries,
767}
768
769impl<Mods, Name, Entries> CanHaveAttributes for EnumDef<Mods, Name, Entries> {
770 fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
771 WithAttributes {
772 attr,
773 separator: AttributeSeparator::NewLine,
774 value: self,
775 }
776 }
777}
778
779/// A type argument-parameterized expression. Used in relation to parameterized names and their
780/// arguments. Examples: `function_name<args>`, `TypeName<'lifetime, args>`, `MyType<Assoc=Value>`.
781///
782/// If no type args exist, [NoOpSeq] should be used. In any case, the second tuple value of this
783/// struct must be a sequence.
784#[derive(Clone, Debug)]
785pub struct Parameterized<Name, TypeArgs>(pub Name, pub TypeArgs);
786
787/// A type variable with a sequence of bounds.
788/// Will render as `TypeVar: B1 + B2 + ...`
789#[derive(Clone, Debug)]
790pub struct BoundedTypeVar<TypeVar, Bounds>(pub TypeVar, pub Bounds);
791
792/// A standalone lifetime, intended to be used as a type argument or variable
793#[derive(Clone, Debug)]
794pub struct Lifetime<'l>(pub &'l str);
795
796/// Renders an individual function parameter, `Name: Type`
797#[derive(Clone, Debug)]
798pub struct FunctionParam<Name, Type>(pub Name, pub Type);
799
800impl<Name, Type> CanHaveAttributes for FunctionParam<Name, Type> {
801 fn with_attributes<Attr>(self, attr: Attr) -> WithAttributes<Attr, Self> {
802 WithAttributes {
803 attr,
804 separator: AttributeSeparator::Space,
805 value: self,
806 }
807 }
808}
809
810/// A sequence acceptor that writes attributes. Every attribute will be surrounded with "#[]"
811#[derive(Debug)]
812pub struct AttributesAccept<'o, O, Sep> {
813 inner: SurroundingSeqAccept<'o, O, Str<&'static str>, Combined<Str<&'static str>, Sep>>,
814}
815
816impl<'o, O, Sep> AttributesAccept<'o, O, Sep> {
817 pub fn with_separator(output: &'o mut O, separator: Sep) -> Self {
818 Self {
819 inner: SurroundingSeqAccept::new(output, Str("#["), Combined(Str("]"), separator)),
820 }
821 }
822}
823
824impl<'o, O, Sep> SequenceAccept<O> for AttributesAccept<'o, O, Sep>
825where
826 O: Output,
827 Sep: Writable<O>,
828{
829 async fn accept<W: Writable<O>>(&mut self, writable: &W) -> Result<(), O::Error> {
830 self.inner.accept(writable).await
831 }
832}