Skip to main content

openapi_nexus_go/ast/
go_expression.rs

1//! Go type expressions
2
3use pretty::RcDoc;
4use serde::{Deserialize, Serialize};
5
6use crate::ast::ty::GoPrimitive;
7use openapi_nexus_core::traits::ToRcDoc;
8
9/// Go type expression
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub enum GoExpression {
12    /// Primitive type
13    Primitive(GoPrimitive),
14    /// Pointer type (*T)
15    Pointer(Box<GoExpression>),
16    /// Slice type ([]T)
17    Slice(Box<GoExpression>),
18    /// Map type (map[K]V)
19    Map {
20        key: Box<GoExpression>,
21        value: Box<GoExpression>,
22    },
23    /// Struct reference
24    Reference(String),
25    /// Interface reference
26    Interface(String),
27    /// Function type
28    Function {
29        params: Vec<GoExpression>,
30        returns: Vec<GoExpression>,
31    },
32    /// Interface{} (any)
33    Any,
34    /// OptionalNullable[T] type
35    OptionalNullable(Box<GoExpression>),
36}
37
38impl ToRcDoc for GoExpression {
39    fn to_rcdoc(&self) -> RcDoc<'static, ()> {
40        match self {
41            GoExpression::Primitive(p) => p.to_rcdoc(),
42            GoExpression::Pointer(inner) => RcDoc::text("*").append(inner.to_rcdoc()),
43            GoExpression::Slice(inner) => RcDoc::text("[]").append(inner.to_rcdoc()),
44            GoExpression::Map { key, value } => RcDoc::text("map[")
45                .append(key.to_rcdoc())
46                .append(RcDoc::text("]"))
47                .append(value.to_rcdoc()),
48            GoExpression::Reference(name) => RcDoc::text(name.clone()),
49            GoExpression::Interface(name) => RcDoc::text(name.clone()),
50            GoExpression::Function { params, returns } => {
51                let param_docs: Vec<_> = params.iter().map(|p| p.to_rcdoc()).collect();
52                let params_doc = if param_docs.is_empty() {
53                    RcDoc::text("()")
54                } else {
55                    RcDoc::text("(")
56                        .append(RcDoc::intersperse(param_docs, RcDoc::text(", ")))
57                        .append(RcDoc::text(")"))
58                };
59
60                let returns_doc = if returns.is_empty() {
61                    RcDoc::nil()
62                } else if returns.len() == 1 {
63                    RcDoc::space()
64                        .append(RcDoc::text("("))
65                        .append(returns[0].to_rcdoc())
66                        .append(RcDoc::text(")"))
67                } else {
68                    let return_docs: Vec<_> = returns.iter().map(|r| r.to_rcdoc()).collect();
69                    RcDoc::space()
70                        .append(RcDoc::text("("))
71                        .append(RcDoc::intersperse(return_docs, RcDoc::text(", ")))
72                        .append(RcDoc::text(")"))
73                };
74
75                RcDoc::text("func")
76                    .append(RcDoc::space())
77                    .append(params_doc)
78                    .append(returns_doc)
79            }
80            GoExpression::Any => RcDoc::text("interface{}"),
81            GoExpression::OptionalNullable(inner) => {
82                RcDoc::text("optionalnullable.OptionalNullable[")
83                    .append(inner.to_rcdoc())
84                    .append(RcDoc::text("]"))
85            }
86        }
87    }
88}
89
90impl GoExpression {
91    /// Create a reference to a type
92    pub fn reference(name: String) -> Self {
93        GoExpression::Reference(name)
94    }
95
96    /// Create a pointer to a type
97    pub fn pointer(inner: GoExpression) -> Self {
98        GoExpression::Pointer(Box::new(inner))
99    }
100
101    /// Create a slice of a type
102    pub fn slice(inner: GoExpression) -> Self {
103        GoExpression::Slice(Box::new(inner))
104    }
105
106    /// Create a map type
107    pub fn map(key: GoExpression, value: GoExpression) -> Self {
108        GoExpression::Map {
109            key: Box::new(key),
110            value: Box::new(value),
111        }
112    }
113
114    /// Create an OptionalNullable type
115    pub fn optional_nullable(inner: GoExpression) -> Self {
116        GoExpression::OptionalNullable(Box::new(inner))
117    }
118}