generating sql methods, reading/writing associative containers

This commit is contained in:
Pavel Merzlyakov 2023-06-06 14:37:34 +03:00
parent 7f92d11514
commit c1128ec7c4
5 changed files with 1557 additions and 130 deletions

View File

@ -1,6 +1,18 @@
<?php
namespace metagen_go;
use Exception;
use mtgMetaInfo;
use mtgMetaInfoUnit;
use mtgMetaEnum;
use mtgMetaStruct;
use mtgMetaField;
use mtgMetaRPC;
use mtgType;
use mtgTypeRef;
use mtgBuiltinType;
use mtgArrType;
use Twig\{TwigTest, TwigFilter, TwigFunction};
function get_twig(array $inc_path = [])
{
@ -8,13 +20,15 @@ function get_twig(array $inc_path = [])
$loader = new \Twig\Loader\FilesystemLoader($inc_path);
$twig = new \Twig\Environment($loader, [
'debug' => true,
'autoescape' => false,
'strict_variables' => true]
);
'debug' => true,
'autoescape' => false,
'strict_variables' => true,
]);
$twig->addExtension(new \Twig\Extension\DebugExtension());
_add_twig_support($twig);
addTwigTests($twig);
addTwigFilters($twig);
addTwigFunctions($twig);
return $twig;
}
@ -22,117 +36,317 @@ function get_twig(array $inc_path = [])
function supported_tokens()
{
return [
'POD',
'table',
'table_pkey',
'table_json_kv',
'root',
'bitfields',
'diffable',
'diff_removed',
'alias',
'default',
'optional',
'bitfields',
'cloneable',
'virtual',
'table',
'id',
'owner',
'pkey',
'statist',
'statist_skip',
'statist_alias',
];
}
function _add_twig_support(\Twig\Environment $twig)
function addTwigTests(\Twig\Environment $twig)
{
$twig->addTest(new \Twig\TwigTest('instanceof',
function($obj, $class)
{
return (new \ReflectionClass($class))->isInstance($obj);
$twig->addTest(new TwigTest(
'metaenum',
fn(mtgMetaInfoUnit $u): bool => $u->object instanceof mtgMetaEnum,
));
$twig->addTest(new TwigTest(
'metastruct',
fn(mtgMetaInfoUnit $u): bool => $u->object instanceof mtgMetaStruct,
));
$twig->addTest(new TwigTest(
'metarpc',
fn(mtgMetaInfoUnit $u): bool => $u->object instanceof mtgMetaRPC,
));
$twig->addTest(new TwigTest(
'enum',
fn(mtgType $t): bool => $t instanceof mtgMetaEnum,
));
$twig->addTest(new TwigTest(
'struct',
fn(mtgType $t): bool => $t instanceof mtgMetaStruct,
));
$twig->addTest(new TwigTest(
'array',
fn(mtgType $t): bool => $t instanceof mtgArrType,
));
$twig->addTest(new TwigTest(
'builtin',
fn(mtgType $t): bool => $t instanceof mtgBuiltinType,
));
$twig->addTest(new TwigTest(
'numeric',
fn(mtgType $t): bool => $t instanceof mtgBuiltinType && $t->isNumeric(),
));
$twig->addTest(new TwigTest(
'int',
fn(mtgType $t): bool => $t instanceof mtgBuiltinType && $t->isInt(),
));
$twig->addTest(new TwigTest(
'uint',
fn(mtgType $t): bool => $t instanceof mtgBuiltinType && $t->isUint(),
));
$twig->addTest(new TwigTest(
'bool',
fn(mtgType $t): bool => $t instanceof mtgBuiltinType && $t->isBool(),
));
$twig->addTest(new TwigTest(
'float',
fn(mtgType $t): bool => $t instanceof mtgBuiltinType && $t->isFloat(),
));
$twig->addTest(new TwigTest(
'double',
fn(mtgType $t): bool => $t instanceof mtgBuiltinType && $t->isDouble(),
));
$twig->addTest(new TwigTest(
'string',
fn(mtgType $t): bool => $t instanceof mtgBuiltinType && $t->isString(),
));
$twig->addTest(new TwigTest(
'blob',
fn(mtgType $t): bool => $t instanceof mtgBuiltinType && $t->isBlob(),
));
$twig->addTest(new TwigTest(
'instanceof',
fn($obj, $class): bool => (new \ReflectionClass($class))->isInstance($obj),
));
}
function addTwigFilters(\Twig\Environment $twig)
{
$twig->addFilter(new TwigFilter(
'go_type',
fn(mtgType $t): string => goType($t),
));
$twig->addFilter(new TwigFilter(
'ucfirst',
fn(string $str): string => ucfirst($str),
));
$twig->addFilter(new TwigFilter(
'lcfirst',
fn(string $str): string => lcfirst($str),
));
$twig->addFilter(new TwigFilter(
'camel',
fn(string $str): string => snake2camel($str),
));
$twig->addFilter(new TwigFilter(
'quote',
fn(string $str, string $char = '`'): string => "{$char}{$str}{$char}"
));
$twig->addFilter(new TwigFilter(
'sql_where',
function(array $fields): string {
$exprs = [];
foreach ($fields as $field) {
$fieldName = $field->getName();
$exprs[] = "`{$fieldName}` = ?";
}
return implode(' AND ', $exprs);
}
));
$twig->addFunction(new \Twig\TwigFunction('Error',
function($e)
{
$twig->addFilter(new TwigFilter(
'alias',
function(mtgMetaField $field): string {
if ($field->hasToken('alias')) {
return $field->getToken('alias');
}
return $field->getName();
}
));
$twig->addFilter(new TwigFilter(
'fname',
fn(mtgMetaField $field): string => snake2camel($field->getName())
));
$twig->addFilter(new TwigFilter(
'varname',
fn(mtgMetaField $field): string => lcfirst(snake2camel($field->getName()))
));
$twig->addFilter(new TwigFilter(
'builtin_type_suffix',
fn (mtgBuiltinType $type): string => builtinTypeMethodSuffix($type),
));
$twig->addFilter(new TwigFilter(
'default_val',
fn(mtgMetaField $field) => defaultValue($field)
));
$twig->addFilter(new TwigFilter(
'rpc_invert',
fn(string $name): string => rpc_invert($name),
));
}
function addTwigFunctions(\Twig\Environment $twig)
{
$twig->addFunction(new TwigFunction(
'Error',
function(string $e) {
throw new Exception($e);
}
));
$twig->addFunction(new \Twig\TwigFunction('has_token',
function($o, $token)
{
return $o->hasToken($token);
}
$twig->addFunction(new TwigFunction(
'has_token',
fn($o, string $token): bool => $o->hasToken($token),
));
$twig->addFunction(new \Twig\TwigFunction('has_token_in_parent',
function($o, $token)
{
return $o->hasTokenInParent($token);
}
$twig->addFunction(new TwigFunction(
'has_token_in_parent',
fn(mtgMetaStruct $s, string $token): bool => $s->hasTokenInParent($token),
));
$twig->addFunction(new \Twig\TwigFunction('token',
function($o, $name)
{
return $o->getToken($name);
}
$twig->addFunction(new TwigFunction(
'token',
fn($o, string $name) => $o->getToken($name),
));
$twig->addFunction(new \Twig\TwigFunction('token_or',
function($o, $name, $v)
{
if($o->hasToken($name))
return $o->getToken($name);
else
return $v;
}
$twig->addFunction(new TwigFunction(
'token_or',
fn($o, string $name, $v) => $o->hasToken($name) ? $o->getToken($name) : $v,
));
$twig->addFunction(new \Twig\TwigFunction('get_all_fields',
function($o)
{
return \mtg_get_all_fields($o);
}
$twig->addFunction(new TwigFunction(
'get_all_fields',
fn(mtgMetaStruct $s): array => \mtg_get_all_fields($s),
));
$twig->addFunction(new \Twig\TwigFunction('count_optional',
function($os)
{
$twig->addFunction(new TwigFunction(
'count_optional',
function($os) {
$opts = 0;
foreach($os as $o)
if($o->hasToken('optional'))
++$opts;
return $opts;
}
));
$twig->addFunction(new TwigFunction(
'arr_fill',
fn($value, int $count): array => array_fill(0, $count, $value)
));
$twig->addFunction(new \Twig\TwigFunction('field_reset',
$twig->addFunction(new TwigFunction(
'table_pkey',
function(mtgMetaStruct $struct): array {
$pkey = explode(',', $struct->getToken('table_pkey'));
$fields = [];
foreach ($pkey as $fieldName) {
$fields[] = $struct->getField($fieldName);
}
return $fields;
}
));
$twig->addFunction(new TwigFunction(
'table_fields',
function(mtgMetaStruct $struct): array {
$pkey = explode(',', $struct->getToken('table_pkey'));
return array_filter(
$struct->getFields(),
fn(mtgMetaField $field): bool => !in_array($field->getName(), $pkey),
);
}
));
$twig->addFunction(new TwigFunction(
'meta_field',
function (string $str) use ($twig): mtgMetaField {
$meta = $twig->getGlobals()['meta'];
return parseMetaField($str, $meta);
}
));
$twig->addFunction(new TwigFunction('field_reset',
function($name, $type, $tokens)
{
return field_reset($name, $type, $tokens);
}
));
$twig->addFunction(new \Twig\TwigFunction('buf2var',
$twig->addFunction(new TwigFunction('buf2var',
function($name, $fname, $type, $buf, $tokens, $is_ptr)
{
return buf2var($name, $fname, $type, $buf, $tokens, $is_ptr);
}
));
$twig->addFunction(new \Twig\TwigFunction('var2buf',
$twig->addFunction(new TwigFunction('var2buf',
function($name, $fname, $type, $buf, $tokens, $is_ptr)
{
return var2buf($name, $fname, $type, $buf, $tokens, $is_ptr);
}
));
$twig->addFilter(new \Twig\TwigFilter('rpc_invert',
function($name)
{
return rpc_invert($name);
}
function snake2camel(string $str): string
{
return str_replace('_', '', ucwords($str, '_'));
}
function goType(mtgType $type, array $tokens = []): string
{
if ($type instanceof mtgMetaEnum) {
return $type->getName();
} else if ($type instanceof mtgMetaStruct) {
return $type->getName();
} else if ($type instanceof mtgBuiltinType) {
if ($type->isFloat()) {
return 'float32';
} else if ($type->isDouble()) {
return 'float64';
} else if ($type->isBlob()) {
return '[]byte';
} else {
return $type->getName();
}
));
$twig->addFilter(new \Twig\TwigFilter('go_type',
function($type, $tokens)
{
return go_type($type, $tokens);
} else if ($type instanceof mtgArrType) {
$native = goType($type->getValue());
return "[]$native";
} else {
throw new Exception("Unknown type '$type'");
}
}
function builtinTypeMethodSuffix(mtgBuiltinType $type): string
{
if ($type->isBlob()) {
return 'Bytes';
}
return ucfirst(goType($type));
}
function defaultValue(mtgMetaField $field)
{
$type = $field->getType();
$tokens = $field->getTokens();
$default = $field->getToken('default');
if ($type instanceof mtgBuiltinType) {
if ($type->isNumeric()) {
return $default ?? 0;
} else if ($type->isString()) {
return $default ?? '""';
} else if($type->isBool()) {
return $default ?? 'false';
} else if($type->isBlob()) {
return $default ?? 'nil';
} else {
throw new Exception("Unknown type '$type'");
}
));
$twig->addFilter(new \Twig\TwigFilter('ucfirst',
function($str)
{
return ucfirst($str);
}
));
} else if($type instanceof mtgMetaEnum) {
return $default ? goType($type, $tokens)."_".trim($tokens['default'], '"') : 0;
} else {
throw new Exception("Unknown type '$type'");
}
}
function parseMetaField(string $str, mtgMetaInfo $meta): mtgMetaField
{
list($name, $type) = explode('|', $str);
return new mtgMetaField($name, new mtgTypeRef(new mtgBuiltinType($type), $meta));
}
function go_type(\mtgType $type, array $tokens = array())
@ -177,7 +391,7 @@ function go_type(\mtgType $type, array $tokens = array())
throw new Exception("Unknown type '$type'");
}
function builtin_type_prefix(\mtgBuiltinType $type)
function builtin_type_prefix(mtgBuiltinType $type)
{
switch($type->getName())
{
@ -214,11 +428,11 @@ function builtin_type_prefix(\mtgBuiltinType $type)
}
}
function field_reset($name, \mtgType $type, array $tokens)
function field_reset($name, mtgType $type, array $tokens)
{
$str = '';
if($type instanceof \mtgBuiltinType)
if($type instanceof mtgBuiltinType)
{
if($type->isNumeric())
{
@ -251,23 +465,23 @@ function field_reset($name, \mtgType $type, array $tokens)
else
throw new Exception("Unknown type '$type'");
}
else if($type instanceof \mtgArrType)
else if($type instanceof mtgArrType)
{
$str = "if self.$name == nil { \nself.$name = make(".go_type($type, $tokens).",0) \n}\n ";
$str = "if self.$name == nil { \nself.$name = make(".goType($type, $tokens).",0) \n}\n ";
$str .= "self.$name = self.{$name}[0:0]";
}
else if($type instanceof \mtgMetaEnum)
else if($type instanceof mtgMetaEnum)
{
if(array_key_exists('default', $tokens))
$str = "self.$name = ".go_type($type, $tokens)."_".trim($tokens['default'], '"');
$str = "self.$name = ".goType($type, $tokens)."_".trim($tokens['default'], '"');
else
$str = "self.$name = 0";
}
else if($type instanceof \mtgMetaStruct)
else if($type instanceof mtgMetaStruct)
{
$is_virtual = array_key_exists("virtual", $tokens);
if($is_virtual)
$str .= "self.$name = New".ltrim(go_type($type, $tokens),'I')."() ";
$str .= "self.$name = New".ltrim(goType($type, $tokens),'I')."() ";
else
$str .= "self.$name.Reset()";
}
@ -276,30 +490,30 @@ function field_reset($name, \mtgType $type, array $tokens)
return $str;
}
function buf2var($name, $fname, \mtgType $type, $buf, array $tokens = array(), $is_ptr = false)
function buf2var($name, $fname, mtgType $type, $buf, array $tokens = array(), $is_ptr = false)
{
$str = '';
if($type instanceof \mtgBuiltinType)
if($type instanceof mtgBuiltinType)
{
$str .= _read_op($tokens, $buf.'.Read'.builtin_type_prefix($type).'(&'.$fname.', "'.$name.'")');
}
else if($type instanceof \mtgMetaEnum)
else if($type instanceof mtgMetaEnum)
{
$str .= _read_op($tokens, "{$buf}.ReadI32((*int32)(&{$fname}), \"$name\")");
$str .= "\n if !{$fname}.IsValid() { return errors.Errorf(\"Bad enum value %d for $name\", $fname) }";
}
else if($type instanceof \mtgMetaStruct)
else if($type instanceof mtgMetaStruct)
{
if(array_key_exists('virtual', $tokens))
$str .= "if v, err := meta.ReadStructGeneric($buf, CreateById, \"{$name}\"); err != nil { return err } else { {$fname} = v.(I{$type}) }";
else
$str .= _read_op($tokens, "meta.ReadStruct($buf, ".($is_ptr?"":"&")."$fname, \"$name\")");
}
else if($type instanceof \mtgArrType)
else if($type instanceof mtgArrType)
{
$is_virtual = array_key_exists("virtual", $tokens);
$native_type = go_type($type->getValue(), $tokens);
$native_type = goType($type->getValue(), $tokens);
$offset = "\n ";
$str .= "/*[]{$name}*/";
$str .= $offset . _read_op($tokens, "{$buf}.BeginContainer(\"$name\")");
@ -308,14 +522,14 @@ function buf2var($name, $fname, \mtgType $type, $buf, array $tokens = array(), $
$str .= $offset . "_{$name}_size, err := {$buf}.GetContainerSize()";
$str .= $offset . "if err != nil { return err }";
$need_new = !$is_virtual && $type->getValue() instanceof \mtgMetaStruct;
$need_new = !$is_virtual && $type->getValue() instanceof mtgMetaStruct;
$str .= $offset . "for ; _{$name}_size > 0; _{$name}_size-- {";
$offset = "\n ";
$str .= $offset . "var tmp_{$name} {$native_type}";
$str .= $offset . buf2var("", "tmp_{$name}", $type->getValue(), $buf, $tokens, $is_virtual);
$str .= $offset . "{$fname} = append({$fname}, ".($need_new?"&":"")."tmp_{$name})";
$str .= $offset . "{$fname} = append({$fname}, tmp_{$name})";
$offset = "\n ";
$str .= $offset . "}";
@ -328,26 +542,26 @@ function buf2var($name, $fname, \mtgType $type, $buf, array $tokens = array(), $
return $str;
}
function var2buf($name, $fname, \mtgType $type, $buf, array $tokens = array(), $is_ptr = false)
function var2buf($name, $fname, mtgType $type, $buf, array $tokens = array(), $is_ptr = false)
{
$str = '';
if($type instanceof \mtgBuiltinType)
if($type instanceof mtgBuiltinType)
{
$str .= _write_op("{$buf}.Write".builtin_type_prefix($type)."($fname, \"$name\")")."\n";
}
else if($type instanceof \mtgMetaEnum)
else if($type instanceof mtgMetaEnum)
{
$str .= _write_op("{$buf}.WriteI32(int32($fname), \"$name\")");
}
else if($type instanceof \mtgMetaStruct)
else if($type instanceof mtgMetaStruct)
{
if(array_key_exists('virtual', $tokens))
$str .= _write_op("meta.WriteStructGeneric($buf, ".($is_ptr?"":"&")."$fname, \"$name\")");
else
$str .= _write_op("meta.WriteStruct($buf, ".($is_ptr?"":"&")."$fname, \"$name\")");
$str .= _write_op("meta.WriteStruct($buf, &$fname, \"$name\")");
}
else if($type instanceof \mtgArrType)
else if($type instanceof mtgArrType)
{
$str .= "{$buf}.BeginContainer(\"{$name}\")\n";
$str .= " for _, v := range({$fname}) {\n";

View File

@ -1,54 +1,90 @@
package {{package}}
package {{ package }}
//THIS FILE IS GENERATED AUTOMATICALLY, DO NOT TOUCH IT!
import (
"fmt"
"sort"
"github.com/pkg/errors"
"git.bit5.ru/backend/meta"
"context"
"database/sql"
"sort"
"git.bit5.ru/backend/meta"
"git.bit5.ru/gomodules/metadb"
"github.com/doug-martin/goqu/v9"
"github.com/doug-martin/goqu/v9/exp"
"github.com/pkg/errors"
)
//supress *imported but not used* warnings
var _ = fmt.Printf
var _ = sort.SearchInts
{% import "macros_enum.twig" as enum_macros %}
{% import "macros_struct.twig" as struct_macros %}
{% import "macros_rpc.twig" as rpc_macros %}
{%- import "macro.twig" as macro -%}
{% set enums = meta.getunits|filter(u => u is metaenum) %}
{% set structs = meta.getunits|filter(u => u is metastruct) %}
{% set rpcs = meta.getunits|filter(u => u is metarpc) %}
{{ macro.decl_units(meta) }}
{% for u in enums %}
{{ enum_macros.enum(u.object) }}
{% endfor %}
func CreateById(classId uint32) (meta.IMetaStruct, error) {
{% for u in structs %}
{{ struct_macros.struct(u.object) }}
{% endfor %}
func CreateById(classId uint32) (meta.Struct, error) {
switch classId {
{%- for u in meta.getunits ~%}
{%- if u.object is instanceof('\\mtgMetaStruct')~%}
case {{u.object.classid}}: { return New{{u.object.name}}(), nil }
{%- endif ~%}
{%- endfor ~%}
default : return nil, errors.Errorf("Can't find struct for class id %d", classId)
{% for u in structs %}
case {{ u.object.classid }}:
return New{{ u.object.name }}(), nil
{% endfor %}
default:
return nil, errors.Errorf("Can't find struct for class id %d", classId)
}
}
func CreateByName(name string) (meta.IMetaStruct, error) {
func CreateByName(name string) (meta.Struct, error) {
switch name {
{%- for u in meta.getunits ~%}
{%- if u.object is instanceof('\\mtgMetaStruct')~%}
case "{{u.object.name}}": { return New{{u.object.name}}(), nil }
{%- endif ~%}
{%- endfor ~%}
default : return nil, errors.Errorf("Can't find struct for name %s", name)
{% for u in structs %}
case "{{ u.object.name }}":
return New{{ u.object.name }}(), nil
{% endfor %}
default:
return nil, errors.Errorf("Can't find struct for name %s", name)
}
}
func CreateRPC(code uint32)(meta.IRPC, error) {
{% for u in rpcs %}
{{ rpc_macros.rpc(u.object) }}
{% endfor %}
func CreateRPC(code uint32) (Rpc, error) {
switch code {
{%- for u in meta.getunits ~%}
{%- if u.object is instanceof('\\mtgMetaRPC')~%}
case {{u.object.code}}: { return New{{u.object.name}}(), nil }
{%- endif ~%}
{%- endfor ~%}
default: return nil, errors.Errorf("Can't find rpc for code %d", code)
{%~ for u in rpcs %}
{%- set name = u.object.name|lower|camel|replace({'Rpc': ''}) ~ 'Rpc' %}
case {{ u.object.code }}:
return &{{ name }}{}, nil
{%~ endfor %}
default:
return nil, errors.Errorf("Can't find rpc for code %d", code)
}
}
type RpcHandler interface {
{%~ for u in rpcs %}
{%- set name = u.object.name|lower|camel|replace({'Rpc': ''}) %}
{{ name }}({{ name ~ 'Rpc' }}) error
{%~ endfor %}
}
type Rpc interface {
Code() uint32
Name() string
Error() (int32, string)
SetError(int32, string)
Execute(RpcHandler) error
ReadRequest(meta.Reader) error
WriteResponse(meta.Writer) error
}
type CreateRpcFunc func(uint32) (Rpc, error)

59
tpl/macros_enum.twig Normal file
View File

@ -0,0 +1,59 @@
{% macro enum(o) %}
{% set values_var = '_' ~ o.name ~ '_values' %}
{% set map_var = '_' ~ o.name ~ '_map' %}
type {{o.name}} int32
const (
{%~ for k,v in o.values %}
{{o.name}}_{{k}} {{o.name}} = {{v}}
{%~ endfor %}
)
var {{ values_var }} = []int{
{%- for v in o.values|sort -%}
{{v}},
{%- endfor -%}
}
var {{ map_var }} map[string]{{o.name}}
func init() {
{{ map_var }} = map[string]{{o.name}}{
{%- for k,v in o.values -%}
"{{k}}": {{v}},
{%- endfor -%}
}
}
func (*{{o.name}}) CLASS_ID() uint32 {
return {{o.classid}}
}
func (*{{o.name}}) CLASS_NAME() string {
return "{{o.name}}"
}
func (*{{o.name}}) DEFAULT_VALUE() int32 {
return {{o.values|first}}
}
func (enum *{{o.name}}) IsValid() bool {
return sort.SearchInts({{ values_var }}, int(*enum)) != -1
}
func {{o.name}}_GetNameByValue(value int) string {
for name, num := range {{ map_var }} {
if value == int(num) {
return name
}
}
return ""
}
func New{{o.name}}ByName(name string) ({{o.name}}, error) {
if v, ok := {{ map_var }}[name]; ok {
return v, nil
}
return 0, errors.Errorf("Wrong name of {{o.name}}: '%s'", name)
}
{% endmacro enum %}

70
tpl/macros_rpc.twig Normal file
View File

@ -0,0 +1,70 @@
{% macro rpc(r) %}
{% import "macros_struct.twig" as struct_macros %}
{% set prefix = r.name|lower|camel|replace({'Rpc': ''}) %}
{% set name = prefix ~ 'Rpc' %}
{% set req_name = prefix ~ 'Request' %}
{% set rsp_name = prefix ~ 'Response' %}
type {{ name }} struct {
req {{ req_name }}
rsp {{ rsp_name }}
errCode int32
errMsg string
}
func (rpc {{ name }}) Name() string {
return "{{ name }}"
}
func (rpc {{ name }}) Code() uint32 {
return {{ r.code }}
}
func (rpc *{{ name }}) SetError(code int32, msg string) {
rpc.errCode = code
rpc.errMsg = msg
}
func (rpc {{ name }}) Error() (int32, string) {
return rpc.errCode, rpc.errMsg
}
func (rpc {{ name }}) Execute(h RpcHandler) error {
return h.{{ prefix }}(rpc)
}
func (rpc {{ name }}) Request() {{ req_name }} {
return rpc.req
}
func (rpc *{{ name }}) SetResponse(rsp {{ rsp_name }}) {
rpc.rsp = rsp
}
func (rpc *{{ name }}) ReadRequest(reader meta.Reader) error {
return rpc.req.Read(reader)
}
func (rpc *{{ name }}) WriteResponse(writer meta.Writer) error {
return rpc.rsp.Write(writer)
}
type {{ req_name }} struct {
{%~ for f in r.req.fields %}
{{ f|fname }} {{ f.type|go_type }} `json:"{{ f|alias }}" msgpack:"{{ f|alias }}"`
{%~ endfor %}
}
{{ struct_macros.struct_required_fields(req_name, r.req.fields)}}
{{ struct_macros.meta_read(r.req, req_name) }}
type {{ rsp_name }} struct {
{%~ for f in r.rsp.fields %}
{{ f|fname }} {{ f.type|go_type }} `json:"{{ f|alias }}" msgpack:"{{ f|alias }}"`
{%~ endfor %}
}
{{ struct_macros.meta_write(r.rsp, rsp_name) }}
{% endmacro rpc %}

1048
tpl/macros_struct.twig Normal file

File diff suppressed because it is too large Load Diff