async-codegen 0.12.1

Minimalist async-IO code generation framework.
Documentation
/*
 * Copyright © 2025 Anand Beh
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use crate::{Output, SequenceAccept, Writable, WritableSeq};

//
// Structs and macros
//

pub struct Stmt<Expr>(pub Expr);

pub struct AssignStmt<Variable, Expr>(pub Variable, pub Expr);

pub struct ReturnStmt<Expr>(pub Expr);

pub struct AssignExpr<Variable, Expr>(pub Variable, pub Expr);

pub struct IfBlock<Cond, Body>(pub Cond, pub Body);

pub struct Else<Before, After>(pub Before, pub After);

pub struct Block<Body>(pub Body);

pub struct MemberAccess<Owner, Member>(pub Owner, pub Member);

pub struct Quoted<A>(pub A);

pub struct Parameterized<Name, TypeArgs>(pub Name, pub TypeArgs);

macro_rules! delegate_tuple_w {
    ($element:ident) => {
        impl<O, Part> Writable<O> for $element<Part>
        where
            O: Output,
            Part: Writable<O>,
        {
            async fn write_to(&self, output: &mut O) -> Result<(), O::Error> {
                $crate::cstyle_common::$element(&self.0)
                    .write_to(output)
                    .await
            }
        }
    };
}

pub(crate) use delegate_tuple_w;

macro_rules! delegate_tuple_ww {
    ($element:ident) => {
        impl<O, Part1, Part2> Writable<O> for $element<Part1, Part2>
        where
            O: Output,
            Part1: Writable<O>,
            Part2: Writable<O>,
        {
            async fn write_to(&self, output: &mut O) -> Result<(), O::Error> {
                $crate::cstyle_common::$element(&self.0, &self.1)
                    .write_to(output)
                    .await
            }
        }
    };
}

pub(crate) use delegate_tuple_ww;

macro_rules! delegate_tuple_ws {
    ($element:ident) => {
        impl<O, Part1, Part2> Writable<O> for $element<Part1, Part2>
        where
            O: Output,
            Part1: Writable<O>,
            Part2: WritableSeq<O>,
        {
            async fn write_to(&self, output: &mut O) -> Result<(), O::Error> {
                $crate::cstyle_common::$element(&self.0, &self.1)
                    .write_to(output)
                    .await
            }
        }
    };
}

pub(crate) use delegate_tuple_ws;

//
// Syntax implementation
//

use crate::common::{SeparatedSeqAccept, Str};

impl<O, Expr> Writable<O> for Stmt<Expr>
where
    O: Output,
    Expr: Writable<O>,
{
    async fn write_to(&self, output: &mut O) -> Result<(), O::Error> {
        self.0.write_to(output).await?;
        output.write(";\n").await
    }
}

impl<O: Output, Variable, Expr> Writable<O> for AssignStmt<Variable, Expr>
where
    Variable: Writable<O>,
    Expr: Writable<O>,
{
    async fn write_to(&self, o: &mut O) -> Result<(), O::Error> {
        Stmt(AssignExpr(&self.0, &self.1)).write_to(o).await
    }
}

impl<O, Expr> Writable<O> for ReturnStmt<Expr>
where
    O: Output,
    Expr: Writable<O>,
{
    async fn write_to(&self, o: &mut O) -> Result<(), O::Error> {
        o.write("return ").await?;
        self.0.write_to(o).await?;
        o.write(";\n").await
    }
}

impl<O, Variable, Expr> Writable<O> for AssignExpr<Variable, Expr>
where
    O: Output,
    Variable: Writable<O>,
    Expr: Writable<O>,
{
    async fn write_to(&self, o: &mut O) -> Result<(), O::Error> {
        self.0.write_to(o).await?;
        o.write(" = ").await?;
        self.1.write_to(o).await
    }
}

impl<O, Cond, Body> Writable<O> for IfBlock<Cond, Body>
where
    O: Output,
    Cond: Writable<O>,
    Body: Writable<O>,
{
    async fn write_to(&self, output: &mut O) -> Result<(), O::Error> {
        output.write("if ").await?;
        self.0.write_to(output).await?;
        output.write(" {\n").await?;
        self.1.write_to(output).await?;
        output.write("\n}").await
    }
}

impl<O, Before, After> Writable<O> for Else<Before, After>
where
    O: Output,
    Before: Writable<O>,
    After: Writable<O>,
{
    async fn write_to(&self, output: &mut O) -> Result<(), O::Error> {
        self.0.write_to(output).await?;
        output.write(" else ").await?;
        self.1.write_to(output).await
    }
}

impl<O, Body> Writable<O> for Block<Body>
where
    O: Output,
    Body: Writable<O>,
{
    async fn write_to(&self, output: &mut O) -> Result<(), O::Error> {
        output.write("{\n").await?;
        self.0.write_to(output).await?;
        output.write("\n}").await
    }
}

impl<O, Owner, Member> Writable<O> for MemberAccess<Owner, Member>
where
    O: Output,
    Owner: Writable<O>,
    Member: Writable<O>,
{
    async fn write_to(&self, output: &mut O) -> Result<(), O::Error> {
        self.0.write_to(output).await?;
        output.write(".").await?;
        self.1.write_to(output).await
    }
}

impl<O, A> Writable<O> for Quoted<A>
where
    O: Output,
    A: Writable<O>,
{
    async fn write_to(&self, output: &mut O) -> Result<(), O::Error> {
        output.write("\"").await?;
        self.0.write_to(output).await?;
        output.write("\"").await
    }
}

impl<O, Name, TypeArgs> Writable<O> for Parameterized<Name, TypeArgs>
where
    O: Output,
    Name: Writable<O>,
    TypeArgs: WritableSeq<O>,
{
    async fn write_to(&self, o: &mut O) -> Result<(), O::Error> {
        self.0.write_to(o).await?;
        TypeArgAccept::new(o).write_in_diamond(&self.1).await
    }
}

//
// Sequence acceptors
//

pub struct TypeArgAccept<'o, O> {
    inner: SeparatedSeqAccept<'o, O, Str<&'static str>, Str<&'static str>>,
}

impl<'o, O> TypeArgAccept<'o, O> {
    pub fn new(output: &'o mut O) -> Self {
        Self {
            inner: SeparatedSeqAccept::new(output, Str("<"), Str(", ")),
        }
    }
}

impl<'o, O> TypeArgAccept<'o, O>
where
    O: Output,
{
    pub async fn write_in_diamond<TypeArgs>(&mut self, type_args: &TypeArgs) -> Result<(), O::Error>
    where
        TypeArgs: WritableSeq<O>,
    {
        self.write_with_suffix(type_args, ">").await
    }

    pub async fn write_in_diamond_with_space_after<TypeArgs>(
        &mut self,
        type_args: &TypeArgs,
    ) -> Result<(), O::Error>
    where
        TypeArgs: WritableSeq<O>,
    {
        self.write_with_suffix(type_args, "> ").await
    }

    async fn write_with_suffix<TypeArgs>(
        &mut self,
        type_args: &TypeArgs,
        suffix: &str,
    ) -> Result<(), O::Error>
    where
        TypeArgs: WritableSeq<O>,
    {
        type_args.for_each(&mut self.inner).await?;
        if self.inner.wrote_any {
            self.inner.output.write(suffix).await?;
        }
        Ok(())
    }
}

pub struct ModsAccept<'o, O>(pub &'o mut O);

impl<'o, O: Output> SequenceAccept<O> for ModsAccept<'o, O> {
    async fn accept<W>(&mut self, writable: &W) -> Result<(), O::Error>
    where
        W: Writable<O>,
    {
        writable.write_to(&mut self.0).await?;
        self.0.write(" ").await
    }
}