Skip to content

Commit

Permalink
Generate Go interfaces for discriminators
Browse files Browse the repository at this point in the history
This commit implements /issues/67.
  • Loading branch information
diamondburned committed Mar 2, 2023
1 parent a42555d commit d769b62
Showing 1 changed file with 44 additions and 24 deletions.
68 changes: 44 additions & 24 deletions crates/target_go/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,32 +258,51 @@ impl jtd_codegen::target::Target for Target {

writeln!(out)?;
write!(out, "{}", description(&metadata, 0))?;
writeln!(out, "type {} struct {{", name)?;
writeln!(out, "\t{} string", tag_field_name)?;
writeln!(out, "type {} interface {{", name)?;
writeln!(out, "\tjson.Marshaler")?;
writeln!(out, "\t{}() string", tag_field_name)?;
writeln!(out, "\tis{}()", name)?;
writeln!(out, "}}")?;
writeln!(out)?;

for variant in &variants {
writeln!(out)?;
writeln!(out, "\t{} {}", &variant.field_name, &variant.type_name)?;
writeln!(out, "func ({}) {}() string {{ return {:?} }}", variant.type_name, tag_field_name, variant.tag_value)?;
}
writeln!(out, "}}")?;
writeln!(out)?;

for variant in &variants {
writeln!(out, "func ({}) is{}() {{}}", variant.type_name, name)?;
}
writeln!(out)?;
writeln!(out, "func (v {}) MarshalJSON() ([]byte, error) {{", name)?;
writeln!(out, "\tswitch v.{} {{", tag_field_name)?;

for variant in &variants {
writeln!(out, "\tcase {:?}:", variant.tag_value)?;
writeln!(out, "\t\treturn json.Marshal(struct {{ T string `json:\"{}\"`; {} }}{{ v.{}, v.{} }})", tag_json_name, variant.type_name, tag_field_name, variant.field_name)?;
writeln!(out, "func (v {}) MarshalJSON() ([]byte, error) {{", variant.type_name)?;
writeln!(out, "\ttype Alias {}", variant.type_name)?;
writeln!(out, "\treturn json.Marshal(struct {{")?;
writeln!(out, "\t\tT string `json:\"{}\"`", tag_json_name)?;
writeln!(out, "\t\tAlias")?;
writeln!(out, "\t}}{{")?;
writeln!(out, "\t\tv.{}(),", tag_field_name)?;
writeln!(out, "\t\tAlias(v),")?;
writeln!(out, "\t}})")?;
writeln!(out, "}}")?;
writeln!(out)?;
}
writeln!(out, "\t}}")?;

writeln!(out)?;
writeln!(
out,
"\treturn nil, fmt.Errorf(\"bad {0} value: %s\", v.{0})",
tag_field_name
)?;
writeln!(out, "// {}JSON wraps the interface that it embeds. It can be", name)?;
writeln!(out, "// the following types:")?;
writeln!(out, "//")?;
for variant in &variants {
writeln!(out, "\t// - [{}] ({})", &variant.type_name, &variant.tag_value)?;
}
writeln!(out, "//")?;
writeln!(out, "type {}JSON struct {{", name)?;
writeln!(out, "\t{}", name)?;
writeln!(out, "}}")?;

writeln!(out)?;
writeln!(out, "func (v *{}) UnmarshalJSON(b []byte) error {{", name)?;
writeln!(out, "func (v *{}JSON) UnmarshalJSON(b []byte) error {{", name)?;
writeln!(
out,
"\tvar t struct {{ T string `json:\"{}\"` }}",
Expand All @@ -293,29 +312,30 @@ impl jtd_codegen::target::Target for Target {
writeln!(out, "\t\treturn err")?;
writeln!(out, "\t}}")?;
writeln!(out)?;
writeln!(out, "\tvar value {}", name)?;
writeln!(out, "\tvar err error")?;
writeln!(out)?;
writeln!(out, "\tswitch t.T {{")?;
for variant in &variants {
writeln!(out, "\tcase {:?}:", variant.tag_value)?;
writeln!(
out,
"\t\terr = json.Unmarshal(b, &v.{})",
variant.field_name
)?;
writeln!(out, "\t\tvar v {}", variant.type_name)?;
writeln!(out, "\t\terr = json.Unmarshal(b, &v)")?;
writeln!(out, "\t\tvalue = v")?;
}
writeln!(out, "\tdefault:")?;
writeln!(
out,
"\t\terr = fmt.Errorf(\"bad {} value: %s\", t.T)",
tag_field_name
"\t\terr = fmt.Errorf(\"{}: bad {} value: %q\", t.T)",
name,
tag_json_name
)?;
writeln!(out, "\t}}")?;
writeln!(out)?;
writeln!(out, "\tif err != nil {{")?;
writeln!(out, "\t\treturn err")?;
writeln!(out, "\t}}")?;
writeln!(out)?;
writeln!(out, "\tv.{} = t.T", tag_field_name)?;
writeln!(out, "\tv.{} = value", name)?;
writeln!(out, "\treturn nil")?;
writeln!(out, "}}")?;

Expand Down

0 comments on commit d769b62

Please sign in to comment.