Skip to content

Commit

Permalink
Add some Go codegen
Browse files Browse the repository at this point in the history
  • Loading branch information
aumetra committed Dec 2, 2024
1 parent 6801e88 commit de4cacb
Show file tree
Hide file tree
Showing 10 changed files with 291 additions and 96 deletions.
159 changes: 159 additions & 0 deletions packages/cw-schema-codegen/src/go/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,160 @@
use self::template::{
EnumTemplate, EnumVariantTemplate, FieldTemplate, StructTemplate, TypeTemplate,
};
use heck::ToPascalCase;
use std::{borrow::Cow, io};

pub mod template;

fn expand_node_name<'a>(
schema: &'a cw_schema::SchemaV1,
node: &'a cw_schema::Node,
) -> Cow<'a, str> {
match node.value {
cw_schema::NodeType::Array { items } => {
let items = &schema.definitions[items];
format!("[]{}", expand_node_name(schema, items)).into()
}
cw_schema::NodeType::Float => "float32".into(),
cw_schema::NodeType::Double => "float64".into(),
cw_schema::NodeType::Boolean => "bool".into(),
cw_schema::NodeType::String => "string".into(),
cw_schema::NodeType::Integer { signed, precision } => {
let ty = if signed { "int" } else { "uint" };
format!("{ty}{precision}").into()
}
cw_schema::NodeType::Binary => "[]byte".into(),
cw_schema::NodeType::Optional { inner } => {
let inner = &schema.definitions[inner];
format!("{}", expand_node_name(schema, inner)).into()
}
cw_schema::NodeType::Struct(..) => node.name.as_ref().into(),
cw_schema::NodeType::Tuple { items: _ } => {
/*let items = items
.iter()
.map(|item| expand_node_name(schema, &schema.definitions[*item]))
.collect::<Vec<_>>()
.join(", ");
format!("({})", items).into()*/
"[]interface{}".into()
}
cw_schema::NodeType::Enum { .. } => node.name.as_ref().into(),

cw_schema::NodeType::Decimal {
precision: _,
signed: _,
} => {
// ToDo: Actually use a decimal type here
"string".into()
}
cw_schema::NodeType::Address => "cosmrs::AccountId".into(),
cw_schema::NodeType::Checksum => "cosmrs::tendermint::Hash".into(),
cw_schema::NodeType::HexBinary => {
// ToDo: Actually use a hex-encoded binary type here
"string".into()
}
cw_schema::NodeType::Timestamp => "cosmrs::tendermint::Time".into(),
cw_schema::NodeType::Unit => "struct{}".into(),
}
}

fn prepare_docs(desc: Option<&str>) -> Cow<'_, [Cow<'_, str>]> {
desc.map(|desc| {
desc.lines()
.map(|line| line.replace('"', "\\\"").into())
.collect()
})
.unwrap_or(Cow::Borrowed(&[]))
}

pub fn process_node<O>(
output: &mut O,
schema: &cw_schema::SchemaV1,
node: &cw_schema::Node,
add_package: bool,
) -> io::Result<()>
where
O: io::Write,
{
match node.value {
cw_schema::NodeType::Struct(ref sty) => {
let structt = StructTemplate {
add_package,
name: node.name.clone(),
docs: prepare_docs(node.description.as_deref()),
ty: match sty {
cw_schema::StructType::Unit => TypeTemplate::Unit,
cw_schema::StructType::Named { ref properties } => TypeTemplate::Named {
fields: properties
.iter()
.map(|(name, prop)| FieldTemplate {
name: Cow::Owned(name.to_pascal_case()),
rename: Cow::Borrowed(name),
docs: prepare_docs(prop.description.as_deref()),
ty: expand_node_name(schema, &schema.definitions[prop.value]),
})
.collect(),
},
cw_schema::StructType::Tuple { ref items } => TypeTemplate::Tuple(
items
.iter()
.map(|item| expand_node_name(schema, &schema.definitions[*item]))
.collect(),
),
},
};

writeln!(output, "{structt}")?;
}
cw_schema::NodeType::Enum { ref cases, .. } => {
let enumm = EnumTemplate {
add_package,
name: node.name.clone(),
docs: prepare_docs(node.description.as_deref()),
variants: cases
.iter()
.map(|(name, case)| EnumVariantTemplate {
name: name.to_pascal_case().into(),
rename: Cow::Borrowed(name),
docs: prepare_docs(case.description.as_deref()),
ty: match case.value {
cw_schema::EnumValue::Unit => TypeTemplate::Unit,
cw_schema::EnumValue::Tuple { ref items } => {
let items = items
.iter()
.map(|item| {
expand_node_name(schema, &schema.definitions[*item])
})
.collect();

TypeTemplate::Tuple(items)
}
cw_schema::EnumValue::Named { ref properties, .. } => {
TypeTemplate::Named {
fields: properties
.iter()
.map(|(name, prop)| FieldTemplate {
name: Cow::Owned(name.to_pascal_case()),
rename: Cow::Borrowed(name),
docs: prepare_docs(prop.description.as_deref()),
ty: expand_node_name(
schema,
&schema.definitions[prop.value],
),
})
.collect(),
}
}
},
})
.collect(),
};

writeln!(output, "{enumm}")?;
}
_ => (),
}

Ok(())
}
4 changes: 4 additions & 0 deletions packages/cw-schema-codegen/src/go/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ use std::borrow::Cow;
#[derive(Clone)]
pub struct EnumVariantTemplate<'a> {
pub name: Cow<'a, str>,
pub rename: Cow<'a, str>,
pub docs: Cow<'a, [Cow<'a, str>]>,
pub ty: TypeTemplate<'a>,
}

#[derive(Template)]
#[template(escape = "none", path = "go/enum.tpl.go")]
pub struct EnumTemplate<'a> {
pub add_package: bool,
pub name: Cow<'a, str>,
pub docs: Cow<'a, [Cow<'a, str>]>,
pub variants: Cow<'a, [EnumVariantTemplate<'a>]>,
Expand All @@ -19,6 +21,7 @@ pub struct EnumTemplate<'a> {
#[derive(Clone)]
pub struct FieldTemplate<'a> {
pub name: Cow<'a, str>,
pub rename: Cow<'a, str>,
pub docs: Cow<'a, [Cow<'a, str>]>,
pub ty: Cow<'a, str>,
}
Expand All @@ -35,6 +38,7 @@ pub enum TypeTemplate<'a> {
#[derive(Template)]
#[template(escape = "none", path = "go/struct.tpl.go")]
pub struct StructTemplate<'a> {
pub add_package: bool,
pub name: Cow<'a, str>,
pub docs: Cow<'a, [Cow<'a, str>]>,
pub ty: TypeTemplate<'a>,
Expand Down
6 changes: 3 additions & 3 deletions packages/cw-schema-codegen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ fn generate_defs<W>(
output: &mut W,
language: Language,
schema: &cw_schema::Schema,
add_imports: bool,
add_imports_or_package: bool,
) -> anyhow::Result<()>
where
W: io::Write,
Expand All @@ -72,10 +72,10 @@ where
match language {
Language::Rust => cw_schema_codegen::rust::process_node(output, schema, node),
Language::Typescript => {
cw_schema_codegen::typescript::process_node(output, schema, node, add_imports)
cw_schema_codegen::typescript::process_node(output, schema, node, add_imports_or_package)
}
Language::Python => cw_schema_codegen::python::process_node(output, schema, node),
Language::Go => todo!(),
Language::Go => cw_schema_codegen::go::process_node(output, schema, node, add_imports_or_package),
}
})?;

Expand Down
3 changes: 0 additions & 3 deletions packages/cw-schema-codegen/src/python/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ fn expand_node_name<'a>(
cw_schema::NodeType::HexBinary => todo!(),
cw_schema::NodeType::Timestamp => todo!(),
cw_schema::NodeType::Unit => "None".into(),
_ => todo!(),
}
}

Expand Down Expand Up @@ -82,7 +81,6 @@ where
.map(|item| expand_node_name(schema, &schema.definitions[*item]))
.collect(),
),
_ => todo!(),
},
};

Expand Down Expand Up @@ -124,7 +122,6 @@ where
.collect(),
}
}
_ => todo!(),
},
})
.collect(),
Expand Down
33 changes: 33 additions & 0 deletions packages/cw-schema-codegen/templates/go/enum.tpl.go
Original file line number Diff line number Diff line change
@@ -1,2 +1,35 @@
// This code is @generated by cw-schema-codegen. Do not modify this manually.

{% if add_package %}
package cwcodegen
{% endif %}

{% for variant in variants %}
{% match variant.ty %}
{% when TypeTemplate::Unit %}
type {{ name }}{{ variant.name }} struct{}
{% when TypeTemplate::Tuple(types) %}
type {{ name }}{{ variant.name }} []interface{}
{% when TypeTemplate::Named { fields } %}
type {{ name }}{{ variant.name }} struct {
{% for field in fields %}
{% for doc in docs %}
// {{ doc }}
{% endfor %}
{{ field.name }} {{ field.ty }} `json:"{{ field.rename }}"`
{% endfor %}
}
{% endmatch %}
{% endfor %}

{% for doc in docs %}
// {{ doc }}
{% endfor %}
type {{ name }} struct {
{% for variant in variants %}
{% for doc in docs %}
// {{ doc }}
{% endfor %}
{{ variant.name}} {{ name }}{{ variant.name }} `json:"{{ variant.rename }}"`
{% endfor %}
}
27 changes: 15 additions & 12 deletions packages/cw-schema-codegen/templates/go/struct.tpl.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
// This code is @generated by cw-schema-codegen. Do not modify this manually.

{% if add_package %}
package cwcodegen
{% endif %}

{% for doc in docs %}
// {{ doc }}
{% endfor %}
{% match ty %}
{% when TypeTemplate::Unit %}
type {{ name }} struct{}
{% when TypeTemplate::Tuple with (types) %}
type {{ name }} []interface{} /* todo: replace with true tuples if i can think of it */
{% when TypeTemplate::Named with { fields } %}
type {{ name }} struct {
{% match ty %}
{% when TypeTemplate::Unit %}
{% when TypeTemplate::Tuple with (types) %}
{{ todo!() }}
{% when TypeTemplate::Named with { fields } %}
{% for field in fields %}
{% for doc in docs %}
// {{ doc }}
{% endfor %}
{{ field.name|capitalize }} {{ field.ty }} `json:"{{ field.name }}"`
{% endfor %}
{% endmatch %}
{% for field in fields %}
{% for doc in docs %}
// {{ doc }}
{% endfor %}
{{ field.name }} {{ field.ty }} `json:"{{ field.rename }}"`
{% endfor %}
}
{% endmatch %}
55 changes: 27 additions & 28 deletions packages/cw-schema-codegen/templates/rust/enum.tpl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,34 @@

#[cosmwasm_schema::cw_serde]
pub enum {{ name }} {
{% for variant in variants %}
{% for doc in variant.docs %}
#[doc = "{{ doc }}"]
{% endfor %}

{% match variant.serde_rename %}
{% when Some with (rename) %}
#[serde(rename = "{{ rename }}")]
{% when None %}
{% endmatch %}
{% for variant in variants %}
{% for doc in variant.docs %}
#[doc = "{{ doc }}"]
{% endfor %}

{{ variant.name }}
{% match variant.ty %}
{% when TypeTemplate::Unit %}
{% when TypeTemplate::Tuple with (types) %}
(
{{ types|join(", ") }}
)
{% when TypeTemplate::Named with { fields } %}
{
{% for field in fields %}
{% for doc in field.docs %}
#[doc = "{{ doc }}"]
{% endfor %}
{% match variant.serde_rename %}
{% when Some with (rename) %}
#[serde(rename = "{{ rename }}")]
{% when None %}
{% endmatch %}

{{ field.name }}: {{ field.ty }},
{% endfor %}
}
{% endmatch %}
{{ variant.name }}
{% match variant.ty %}
{% when TypeTemplate::Unit %}
{% when TypeTemplate::Tuple with (types) %}
(
{{ types|join(", ") }}
)
{% when TypeTemplate::Named with { fields } %}
{
{% for field in fields %}
{% for doc in field.docs %}
#[doc = "{{ doc }}"]
{% endfor %}
{{ field.name }}: {{ field.ty }},
{% endfor %}
}
{% endmatch %}
,
{% endfor %}
{% endfor %}
}
Loading

0 comments on commit de4cacb

Please sign in to comment.