async_codegen/rust/mod.rs
1/*
2 * Copyright © 2025 Anand Beh
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//!
18//! Rust syntax elements.
19//!
20//! Note that no checking exists to make sure the elements are used correctly, i.e. the correct
21//! combination of structs. Instead, the library user is expected to have basic knowledge of how
22//! Rust syntax is composed, and to combine the structs in this module likewise.
23//!
24//! Example:
25//!
26//! ```
27//! use async_codegen::common::{CombinedSeq, SingularSeq, Str};
28//! use async_codegen::{Output, Writable};
29//!
30//! use async_codegen::rust::{CfgAttr, Deprecated, Function, FunctionDef, FunctionParam, ModPub, MustUse, NoMangle, Parameterized};
31//!
32//! async fn write_function<O>(output: &mut O) -> Result<(), O::Error> where O: Output {
33//! // For more advanced usage, you can replace Str("") by other Writable implementations
34//! let function_def = FunctionDef {
35//! attr: SingularSeq(Deprecated::with_message(Str("because we all love deprecation"))),
36//! mods: SingularSeq(ModPub),
37//! decl: Function {
38//! name: Str("my_func"),
39//! args: CombinedSeq(
40//! SingularSeq(FunctionParam(Str("var1"), Str("Type"))),
41//! SingularSeq(FunctionParam(Str("var2"), Parameterized::new(Str("Option"), SingularSeq(Str("bool")))))
42//! )
43//! },
44//! return_type: Parameterized::new(Str("Box"), SingularSeq(Str("str"))),
45//! body: Str("\ntodo!()\n")
46//! };
47//! function_def.write_to(output).await
48//! // Will render as:
49//! /*
50//! #[deprecated = "because we all love deprecation"]
51//! pub fn my_func(var1: Type, var2: Option<bool>) -> Box<str> {
52//! todo!()
53//! }
54//! */
55//! }
56//! ```
57//!
58
59use crate::common::{NoOp, Str, SurroundingSeqAccept};
60use crate::{Output, SequenceAccept, Writable};
61
62mod syntax;
63
64/// All possible Rust editions.
65/// This is the only type in this module meant to be used as context, and not as a writable itself.
66#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
67#[non_exhaustive]
68pub enum Edition {
69 /// This Rust edition is declared for usability purposes. However, not all [crate::Writable]
70 /// implementations are guaranteed to work with it.
71 Rust2015,
72 Rust2018,
73 Rust2021,
74 Rust2024,
75}
76
77#[cfg(test)]
78mod test_edition {
79 use crate::rust::Edition;
80
81 #[test]
82 fn edition_order() {
83 assert!(Edition::Rust2018 < Edition::Rust2021);
84 assert!(Edition::Rust2018 < Edition::Rust2024);
85 }
86}
87
88/// An attribute enabled conditionally, i.e. `#[cfg_attr(Cond, Attr)]`
89pub struct CfgAttr<Cond, Attr>(pub Cond, pub Attr);
90
91/// The no mangle attribute.
92///
93/// Requires that the context satisfies [ContextProvides] for [Edition], because in Rust 2024 and
94/// beyond, the no-mangle attribute is an unsafe attribute.
95pub struct NoMangle;
96
97/// The attribute content for `allow(...)`. The tuple value must be a sequence.
98pub struct AllowLints<Lints>(pub Lints);
99
100/// The deprecated attribute. The three variants of this enum correspond to the deprecated
101/// attribute's multiple ways of being specified. See:
102/// https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-deprecated-attribute
103pub enum Deprecated<Msg, Since = NoOp> {
104 Basic,
105 Message(Msg),
106 Full { since: Since, note: Msg },
107}
108
109impl Default for Deprecated<NoOp, NoOp> {
110 fn default() -> Self {
111 Self::Basic
112 }
113}
114
115impl Deprecated<NoOp, NoOp> {
116 pub fn basic() -> Self {
117 Self::Basic
118 }
119}
120
121impl<Msg> Deprecated<Msg> {
122 pub fn with_message(msg: Msg) -> Self {
123 Self::Message(msg)
124 }
125}
126
127/// The must_use attribute
128pub struct MustUse;
129
130/// The public modifier
131pub struct ModPub;
132
133/// The extern modifier, with the ABI selected as the tuple value.
134///
135/// This struct includes `unsafe`. Since Rust 2024, the unsafe keyword is required for extern
136/// functions, and before Rust 2024 it is optional. To make it easy to generate code targeting
137/// multiple editions, we unconditionally emit the "unsafe" keyword alongside "extern".
138pub struct ModUnsafeExtern<Abi>(pub Abi);
139
140/// A let statement. This statement includes the semicolon and a new line.
141pub struct LetStmt<Variable, Expr>(pub Variable, pub Expr);
142
143/// An item attached to an associated container, via "::".
144/// The output will look like `Cont::Item`.
145pub struct AssociatedItem<Cont, Item>(pub Cont, pub Item);
146
147/// A question mark following another expression.
148pub struct QuestionMarkAfter<Expr>(pub Expr);
149
150/// Wraps an expression in `Ok(EXPR)`.
151pub struct OkResultOf<Expr>(pub Expr);
152
153/// Uses the `as` expression to perform a qualified trait cast (ready for a method call).
154/// I.e., this will render as `<Type as Trait>`.
155pub struct TypeAsTrait<Type, Trait>(pub Type, pub Trait);
156
157/// Declaration of an extern block, i.e. for FFI.
158/// In Rust 2024 and later, the unsafe keyword must be added for extern blocks. Thus, this struct
159/// requires that the context satisfies [ContextProvides] for [Edition].
160pub struct ExternBlock<Attr, Abi, Body> {
161 /// The attributes. Must be a sequence, and each value will be placed inside `#[]`.
162 pub attr: Attr,
163 /// The ABI chosen. Must be writable
164 pub abi: Abi,
165 /// The body of the extern block. Must be writable
166 pub body: Body,
167}
168
169/// Places the expression inside an unsafe block.
170/// Adds new lines inside the brackets, wrapping the inner expression.
171pub struct UnsafeBlock<Expr>(pub Expr);
172
173/// Writes a closure.
174/// Adds new lines inside the brackets, wrapping the inner expression.
175pub struct Closure<InputVars, Expr> {
176 /// The input variables.
177 /// Should be a sequence. They will be comma separated and placed within the pipes.
178 /// To use no input variables, use [crate::common::NoOpSeq].
179 pub input_vars: InputVars,
180 /// The expression inside the closure block.
181 pub inside_block: Expr,
182}
183
184/// Performs a call to a function inside code.
185pub struct FunctionCall<Recv, FuncName, Args> {
186 /// The function receiver
187 pub receiver: Recv,
188 /// Whether the function is associated, false if it's a method
189 pub is_assoc: bool,
190 /// The function being called
191 pub function: Function<FuncName, Args>,
192}
193
194/// The base struct for a function. Includes name and arguments.
195/// This function is re-used in other places and is likely not helpful by itself.
196pub struct Function<Name, Args> {
197 /// The function name. Must be writable.
198 pub name: Name,
199 /// The function arguments. Must be a sequence.
200 pub args: Args,
201}
202
203/// A function declaration
204pub struct FunctionDef<Attr, Mods, Name, Args, Return, Body> {
205 /// The attributes. Must be a sequence, and each value will be placed inside `#[]`.
206 pub attr: Attr,
207 /// The modifiers. Must be a sequence.
208 pub mods: Mods,
209 /// The function itself
210 pub decl: Function<Name, Args>,
211 /// The return type, i.e. after the `->` arrow
212 pub return_type: Return,
213 /// The function body. At the minimum, this must be `;` (see [`FunctionBodyDeclare`])
214 pub body: Body,
215}
216
217/// Declares a function body. This is equivalent to just a semicolon.
218pub struct FunctionBodyDeclare;
219
220/// Renders as `Type=Value`. Intended to be used as a type argument, to specify associated types.
221pub struct AssociatedTypeEquals<Type, Value>(pub Type, pub Value);
222
223/// Adds a "dyn " before a type expression.
224pub struct DynOf<Type>(pub Type);
225
226/// Adds a "&" before a type expression
227pub struct RefOf<Type>(pub Type);
228
229/// Adds an "impl " before a type expression
230pub struct ImplOf<Type>(pub Type);
231
232/// Adds a reference with a lifetime before a type expression, i.e. `&'<lifetime> <type>`
233pub struct LifetimedRefOf<'l, Type>(pub &'l str, pub Type);
234
235/// Declares an associated type, rendering as `type VarName = Value;`.
236/// Adds new lines before and after.
237pub struct AssociatedTypeDef<VarName, Value>(pub VarName, pub Value);
238
239/// The declaration of a trait
240pub struct TraitDef<Attr, Mods, Name, TypeVars, SuperTraits, Body> {
241 /// The trait attributes. Must be a sequence, and each value will be placed inside `#[]`.
242 pub attr: Attr,
243 /// The trait modifiers, e.g. visibility. Must be a sequence.
244 pub mods: Mods,
245 /// The name of the trait
246 pub name: Name,
247 /// The type variables. Must be a sequence
248 pub type_variables: TypeVars,
249 /// The super traits. Must be a sequence
250 pub super_traits: SuperTraits,
251 /// The trait definition's body. Use [NoOp] if none exists.
252 pub body: Body,
253}
254
255/// The implementation declaration for a trait, applying to a certain receiver.
256pub struct TraitImpl<TypeVars, Trait, Recv, Body> {
257 /// The type variables to use for the impl block itself. All type variables that appear later
258 /// on the trait or the receiver must be declared here, per Rust language rules.
259 ///
260 /// This field must be a sequence.
261 pub type_variables: TypeVars,
262 /// The trait being implemented
263 pub the_trait: Trait,
264 /// The receiver for which it is implemented
265 pub receiver: Recv,
266 /// The body. Use [NoOp] if none exists.
267 pub body: Body,
268}
269
270/// A type argument-parameterized expression. Used in relation to parameterized names and their
271/// arguments. Examples: `function_name<args>`, `TypeName<'lifetime, args>`, `MyType<Assoc=Value>`.
272///
273/// If no type args exist, [`crate::common::NoOpSeq`] should be used.
274pub struct Parameterized<Name, TypeArgs> {
275 name: Name,
276 type_args: TypeArgs,
277}
278
279impl<Name, TypeArgs> Parameterized<Name, TypeArgs> {
280 /// Initializes an instance
281 pub fn new(name: Name, type_args: TypeArgs) -> Self {
282 Self { name, type_args }
283 }
284}
285
286/// A type variable with a sequence of bounds.
287/// Will render as `TypeVar: B1 + B2 + ...`
288pub struct BoundedTypeVar<TypeVar, Bounds>(pub TypeVar, pub Bounds);
289
290/// A standalone lifetime, intended to be used as a type argument or variable
291pub struct Lifetime<'l>(pub &'l str);
292
293/// Renders an individual function parameter, `Name: Type`
294pub struct FunctionParam<Name, Type>(pub Name, pub Type);
295
296/// A sequence acceptor that writes attributes. Every attribute will be placed on a new line
297/// and automatically be surrounded with "#[]"
298pub struct AttributesAccept<'o, O> {
299 inner: SurroundingSeqAccept<'o, O, Str<&'static str>, Str<&'static str>>
300}
301
302impl<'o, O> AttributesAccept<'o, O> {
303 pub fn new(output: &'o mut O) -> Self {
304 Self {
305 inner: SurroundingSeqAccept::new(output, Str("#["), Str("]\n"))
306 }
307 }
308}
309
310impl<'o, O: Output> SequenceAccept<O> for AttributesAccept<'o, O> {
311 async fn accept<W: Writable<O>>(&mut self, writable: &W) -> Result<(), O::Error> {
312 self.inner.accept(writable).await
313 }
314}