From d769b625f6b0bd664c23d3e86fabe0e198323c01 Mon Sep 17 00:00:00 2001 From: diamondburned Date: Mon, 13 Feb 2023 04:03:53 -0800 Subject: [PATCH] Generate Go interfaces for discriminators This commit implements jsontypedef/json-typedef-codegen/issues/67. --- crates/target_go/src/lib.rs | 68 ++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/crates/target_go/src/lib.rs b/crates/target_go/src/lib.rs index 3c934b86..ad8f4e55 100644 --- a/crates/target_go/src/lib.rs +++ b/crates/target_go/src/lib.rs @@ -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:\"{}\"` }}", @@ -293,21 +312,22 @@ 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)?; @@ -315,7 +335,7 @@ impl jtd_codegen::target::Target for Target { 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, "}}")?;