diff --git a/src/codegen.inc.php b/src/codegen.inc.php index aa398de..a69367d 100644 --- a/src/codegen.inc.php +++ b/src/codegen.inc.php @@ -119,7 +119,7 @@ function add_twig_filters(\Twig\Environment $twig) { $twig->addFilter(new TwigFilter( 'go_type', - fn(\mtgType $t): string => go_type($t), + fn(\mtgType $t, array $tokens = []): string => go_type($t, $tokens), )); $twig->addFilter(new TwigFilter( 'ucfirst', @@ -204,11 +204,6 @@ function add_twig_filters(\Twig\Environment $twig) return $fields; } )); - - $twig->addFilter(new TwigFilter( - 'rpc_invert', - fn(string $name): string => rpc_invert($name), - )); } function add_twig_functions(\Twig\Environment $twig) @@ -271,25 +266,6 @@ function add_twig_functions(\Twig\Environment $twig) return parse_meta_field($str, $meta); } )); - - $twig->addFunction(new TwigFunction('field_reset', - function($name, $type, $tokens) - { - return field_reset($name, $type, $tokens); - } - )); - $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 TwigFunction('var2buf', - function($name, $fname, $type, $buf, $tokens, $is_ptr) - { - return var2buf($name, $fname, $type, $buf, $tokens, $is_ptr); - } - )); } function snake2camel(string $str): string @@ -300,9 +276,16 @@ function snake2camel(string $str): string function go_type(\mtgType $type, array $tokens = []): string { if($type instanceof \mtgMetaEnum) + { return $type->getName(); + } else if($type instanceof \mtgMetaStruct) + { + if(array_key_exists('virtual', $tokens)) { + return 'I'.$type->getName(); + } return $type->getName(); + } else if($type instanceof \mtgBuiltinType) { if($type->isFloat()) @@ -316,9 +299,9 @@ function go_type(\mtgType $type, array $tokens = []): string } else if($type instanceof \mtgArrType) { - $native = go_type($type->getValue()); + $native = go_type($type->getValue(), $tokens); return "[]$native"; - } + } else throw new Exception("Unknown type '{$type->getName()}'"); } @@ -367,204 +350,3 @@ function parse_meta_field(string $str, \mtgMetaInfo $meta): \mtgMetaField list($name, $type) = explode('|', $str); return new \mtgMetaField($name, new \mtgTypeRef(new \mtgBuiltinType($type))); } - -function builtin_type_prefix(\mtgBuiltinType $type) -{ - switch($type->getName()) - { - case "string": - return "String"; - case "bool": - return "Bool"; - case "blob": - return "Blob"; - case "float": - return "Float"; - case "double": - return "Double"; - case "uint64": - return "U64"; - case "int64": - return "I64"; - case "uint": - case "uint32": - return "U32"; - case "uint16": - return "U16"; - case "uint8": - return "U8"; - case "int": - case "int32": - return "I32"; - case "int16": - return "I16"; - case "int8": - return "I8"; - default: - throw new Exception("Unknown type '{$type}'"); - } -} - -function field_reset($name, \mtgType $type, array $tokens) -{ - $str = ''; - - if($type instanceof \mtgBuiltinType) - { - if($type->isNumeric()) - { - if(array_key_exists('default', $tokens) && is_numeric($tokens['default'])) - $str .= "self.$name = ".$tokens['default']; - else - $str .= " self.$name = 0"; - } - else if($type->isString()) - { - if(array_key_exists('default', $tokens)) - $str .= "self.$name = ".$tokens['default']; - else - $str .= "self.$name = \"\""; - } - else if($type->isBool()) - { - if(array_key_exists('default', $tokens)) - $str .= "self.$name = ".$tokens['default']; - else - $str .= "self.$name = false"; - } - else if($type->isBlob()) - { - if(array_key_exists('default', $tokens)) - $str .= "self.$name = ".$tokens['default']; - else - $str .= "self.$name = nil"; - } - else - throw new Exception("Unknown type '$type'"); - } - else if($type instanceof \mtgArrType) - { - $str = "if self.$name == nil { \nself.$name = make(".go_type($type, $tokens).",0) \n}\n "; - $str .= "self.$name = self.{$name}[0:0]"; - } - else if($type instanceof \mtgMetaEnum) - { - if(array_key_exists('default', $tokens)) - $str = "self.$name = ".go_type($type, $tokens)."_".trim($tokens['default'], '"'); - else - $str = "self.$name = 0"; - } - 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')."() "; - else - $str .= "self.$name.Reset()"; - } - else - throw new Exception("Unknown type '{$type->getName()}'"); - return $str; -} - -function buf2var($name, $fname, \mtgType $type, $buf, array $tokens = array(), $is_ptr = false) -{ - $str = ''; - - if($type instanceof \mtgBuiltinType) - { - $str .= _read_op($tokens, $buf.'.Read'.builtin_type_prefix($type).'(&'.$fname.', "'.$name.'")'); - } - 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) - { - 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) - { - $is_virtual = array_key_exists("virtual", $tokens); - $native_type = go_type($type->getValue(), $tokens); - $offset = "\n "; - $str .= "/*[]{$name}*/"; - $str .= $offset . _read_op($tokens, "{$buf}.BeginContainer(\"$name\")"); - $str .= $offset . "_{$name}_size, err := {$buf}.GetContainerSize()"; - $str .= $offset . "if err != nil { return err }"; - - $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}, tmp_{$name})"; - - $offset = "\n "; - $str .= $offset . "}"; - $str .= $offset . _read_op($tokens, "{$buf}.EndContainer()"); - $str .= "\n"; - } - else - throw new Exception("Unknown type '{$type->getName()}'"); - - return $str; -} - -function var2buf($name, $fname, \mtgType $type, $buf, array $tokens = array(), $is_ptr = false) -{ - $str = ''; - - if($type instanceof \mtgBuiltinType) - { - $str .= _write_op("{$buf}.Write".builtin_type_prefix($type)."($fname, \"$name\")")."\n"; - } - else if($type instanceof \mtgMetaEnum) - { - $str .= _write_op("{$buf}.WriteI32(int32($fname), \"$name\")"); - } - 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, &$fname, \"$name\")"); - } - else if($type instanceof \mtgArrType) - { - $str .= "{$buf}.BeginContainer(\"{$name}\")\n"; - $str .= " for _, v := range({$fname}) {\n"; - $str .= " ".var2buf("", "v", $type->getValue(), $buf, $tokens, true)."\n"; - $str .= " }\n"; - $str .= " "._write_op("{$buf}.EndContainer()")."\n"; - } - else - throw new Exception("Unknown type '{$type->getName()}'"); - - return $str; -} - -function _write_op($op) -{ - return "if err := $op; err != nil { return err }"; -} - -function _read_op(array $tokens, $op) -{ - return "if err := $op; err != nil { return err }"; -} - -function rpc_invert($name) -{ - if(strpos($name, '_RSP_') !== false) - return str_replace('_RSP_', '_REQ_', $name); - else - return str_replace('_REQ_', '_RSP_', $name); -} - diff --git a/tpl/codegen_bundle.twig b/tpl/codegen_bundle.twig index c412d6c..4e8bc4f 100644 --- a/tpl/codegen_bundle.twig +++ b/tpl/codegen_bundle.twig @@ -11,7 +11,7 @@ import ( "strconv" "strings" - "git.bit5.ru/backend/meta/v3" + "git.bit5.ru/backend/meta/v4" "git.bit5.ru/backend/versioning" "git.bit5.ru/gomodules/metadb" "github.com/go-logr/logr" @@ -50,6 +50,10 @@ func CreateById(classId uint32) (meta.Struct, error) { } } +func CreateReadableById(classId uint32) (meta.Readable, error) { + return CreateById(classId) +} + func CreateByName(name string) (meta.Struct, error) { switch name { {% for u in structs %} diff --git a/tpl/macro.twig b/tpl/macro.twig deleted file mode 100644 index c7da73b..0000000 --- a/tpl/macro.twig +++ /dev/null @@ -1,464 +0,0 @@ -{% macro decl_units(meta) %} - {%- for u in meta.getunits ~%} - {%- if u.object is instanceof('\\mtgMetaStruct') ~%} - {{ _self.decl_struct(u.object) }} - {%- elseif u.object is instanceof('\\mtgMetaEnum') ~%} - {{ _self.decl_enum(u.object) }} - {%- elseif u.object is instanceof('\\mtgMetaRPC') ~%} - {{ _self.decl_rpc(u.object) }} - {%- endif ~%} - {%- endfor ~%} -{% endmacro %} - -{% macro decl_struct(o) %} -{%- if o.parent and has_token(o, 'POD') -%} -{{Error("@POD structs can't have a parent: " ~ o.name)}} -{%- endif -%} -{%- if o.parent and has_token(o, 'bitfields') -%} -{{Error("@bitfields structs can't have a parent: " ~ o.name)}} -{%- endif ~%} - -//============================== -type {{o.name}} struct { -{% if o.parent %} -{{o.parent.name}} -{% endif %} -{{_self.decl_struct_fields(o)}} -} - -var _{{o.name}}_class_props map[string]string = {{_self.props_map(o.tokens)}} -var _{{o.name}}_class_fields []string = {{_self.struct_fields_names(o)}} -var _{{o.name}}_fields_props meta.ClassFieldsProps = {{_self.struct_fields_props(o)}} - -func {{o.name}}_CLASS_ID() uint32 { - return {{o.classid}} -} - -type I{{o.name}} interface { - meta.IMetaStruct - Ptr{{o.name}}() *{{o.name}} -} - -func (*{{o.name}}) CLASS_ID() uint32 { - return {{o.classid}} -} - -func (*{{o.name}}) CLASS_NAME() string { - return "{{o.name}}" -} - -func (*{{o.name}}) CLASS_PROPS() *map[string]string { - return &_{{o.name}}_class_props -} - -func (*{{o.name}}) CLASS_FIELDS() []string { - return _{{o.name}}_class_fields -} - -func (*{{o.name}}) CLASS_FIELDS_PROPS() *meta.ClassFieldsProps { - return &_{{o.name}}_fields_props -} - -//convenience getter -func Ptr{{o.name}}(m meta.IMetaStruct) *{{o.name}} { - p, ok := m.(I{{o.name}}) - if !ok { - return nil - } - return p.Ptr{{o.name}}() -} - -func (self *{{o.name}}) Ptr{{o.name}}() *{{o.name}} { - return self -} - -func New{{o.name}}() *{{o.name}} { - item := new ({{o.name}}) - item.Reset() - return item -} - -func (self *{{o.name}}) Reset() { - {{_self.struct_reset_fields(o)}} -} - -func (self *{{o.name}}) Read(reader meta.Reader) error { - return meta.ReadStruct(reader, self, "") -} - -func (self *{{o.name}}) ReadFields(reader meta.Reader) error { - self.Reset() - - {{_self.struct_read_fields(o)}} - - return nil -} - -func (self *{{o.name}}) Write(writer meta.Writer) error { - return meta.WriteStruct(writer, self, "") -} - -func (self *{{o.name}}) WriteFields(writer meta.Writer) error { - - {{_self.struct_write_fields(o)}} - - return nil -} - -{% if has_token(o, 'bitfields') %} -{{_self.bitfields_methods(o)}} -{% endif %} - -{% if has_token(o, 'statist') %} -{{_self.stats_methods(o)}} -{% endif %} - -{% if has_token(o, 'POD') and has_token(o, 'id') and has_token(o, 'table') and has_token(o, 'owner') %} -{{_self.db_item_methods(o)}} -{% endif %} - -{% endmacro %} - -{%- macro props_map(tokens) -%} -map[string]string{ -{%- for k,v in tokens -%} - "{{k}}" : "{{v|replace({'"' : '\\"'})}}", -{%- endfor -%} -} -{%- endmacro -%} - -{%- macro struct_fields_names(o) -%} -[]string{ -{%- for f in get_all_fields(o) -%} -"{{f.name}}", -{%- endfor -%} -} -{%- endmacro -%} - -{%- macro struct_fields_props(o) -%} -map[string]map[string]string{ -{%- for f in get_all_fields(o) -%} -"{{f.name|ucfirst}}" : {{_self.props_map(f.tokens)}}, -{%- endfor -%} -} -{%- endmacro -%} - -{%- macro decl_struct_fields(o) -%} -{%- for f in o.fields ~%} -{{f.name|ucfirst}} {{f.type|go_type(f.tokens)}} {{_self.field_annotations(o, f)}} -{%- endfor ~%} -{%if has_token(o, 'bitfields') %} -fieldsMask meta.FieldsMask //@bitfields support -{%- endif ~%} - -{%- endmacro -%} - -{%- macro field_annotations(o, f) -%} -{%- if f.name|first != '_' -%} -`json:"{{f.name}}" {% if has_token(o, 'table') -%} db:"{{f.name}}"{%- endif -%}` -{%- endif -%} -{%- endmacro -%} - -{% macro struct_reset_fields(o) %} - -{%- if o.parent ~%} - self.{{o.parent.name}}.Reset() -{%- endif ~%} - -{%- for f in o.fields ~%} -{{field_reset(f.name|ucfirst, f.type, f.tokens)}} -{%- endfor ~%} - -{% if has_token(o, 'bitfields') ~%} -self.fieldsMask = meta.FieldsMask{} -{%- endif ~%} - -{% endmacro %} - -{% macro struct_read_fields(o) %} - -{%- if has_token(o, 'bitfields') ~%} - use_mask, mask, err := reader.TryReadMask() - if err != nil { - return err - } - self.fieldsMask = mask -{%- endif ~%} - - _cont_size, err := reader.GetContainerSize() - if err != nil { - return err - } - - if _cont_size < {{(o.fields|length)}} { - _cont_size = {{(o.fields|length)}} - } - -{%- if o.parent ~%} - if err := self.{{o.parent.name}}.ReadFields(reader); err != nil { return err } -{%- endif ~%} - -{%- for f in o.fields ~%} - if _cont_size <= 0 { - return nil - } - - {%if has_token(o, 'bitfields') ~%} - if !use_mask { - {%- endif ~%} - - _cont_size-- - - {%if has_token(o, 'bitfields') ~%} - } - if !use_mask || (use_mask && self.HasValue({{loop.index0}})) { - {%- endif ~%} - - {{buf2var(f.name, 'self.' ~ f.name|ucfirst, f.type, 'reader', f.tokens, false)}} - - {%if has_token(o, 'bitfields') ~%} - } - {%- endif -%} - -{%- endfor -%} - -{% endmacro %} - -{% macro struct_write_fields(o) %} - -{%- if o.parent ~%} - if err := self.{{o.parent.name}}.WriteFields(writer); err != nil { return err } -{%- endif ~%} - -{%- for f in o.fields ~%} - {{var2buf(f.name, 'self.' ~ f.name|ucfirst, f.type, "writer", f.tokens, has_token(f, 'virtual'))}} -{%- endfor -%} - -{% endmacro %} - -{% macro bitfields_methods(o) %} -func(self *{{o.name}}) HasValue(index uint64) bool { - return self.fieldsMask.FieldChanged(index) -} - -func(self *{{o.name}}) SetFieldChanged(index uint64) { - self.fieldsMask.SetFieldChanged(index) -} - -func(self *{{o.name}}) IsMaskFilled() bool { - return self.fieldsMask.IsFilled() -} - -func(self *{{o.name}}) GetMask() meta.FieldsMask { - return self.fieldsMask -} -{% endmacro %} - -{% macro stats_methods(o) %} - -func (self *{{o.name}}) Table() string { - return "{{token(o, 'statist')}}" -} - -func (self * {{o.name}}) Columns() []string { - return []string{ - {%- for f in get_all_fields(o) ~%} - {%- if not has_token(f, 'statist_skip') ~%} - "{{token_or(f, 'statist_alias', f.name)}}", - {%- endif ~%} - {%- endfor ~%} - } -} - -func (self *{{o.name}}) Values() []interface{} { - return []interface{}{ - {%- for f in get_all_fields(o) ~%} - {%- if not has_token(f, 'statist_skip') ~%} - self.{{f.name|ucfirst}}, - {%- endif ~%} - {%- endfor ~%} - } -} - -{% endmacro %} - -{% macro db_item_methods(o) %} - -func (self *{{o.name}}) NewInstance() meta.IMetaDataItem { - return New{{o.name}}() -} - -func (self *{{o.name}}) GetDbTableName() string { - return "{{token(o, 'table')}}" -} - -func (self *{{o.name}}) GetDbFields() []string { - return self.CLASS_FIELDS() -} - -func (self *{{o.name}}) GetOwnerFieldName() string { - return "{{token(o, 'owner')}}" -} - -func (self *{{o.name}}) GetIdFieldName() string { - return "{{token(o, 'id')}}" -} - -func (self *{{o.name}}) GetIdValue() uint64 { - return uint64(self.{{token(o, 'id')|ucfirst}}) -} - -func (self *{{o.name}}) Import(data interface{}) { - switch data.(type) { - case {{o.name}}: - { - row := data.({{o.name}}) -{%- for f in get_all_fields(o) ~%} - self.{{f.name|ucfirst}} = row.{{f.name|ucfirst}} -{%- endfor ~%} - break - } - default: - break - } -} - -func (self *{{o.name}}) Export(data []interface{}) { -{%- for f in get_all_fields(o) ~%} - data[{{loop.index0}}] = self.{{f.name|ucfirst}} -{%- endfor ~%} -} -{% endmacro %} - -{% macro decl_enum(o) %} - -//============================== -const ( -{{_self.enum_consts(o)}} -) -type {{o.name}} int32 -var _{{o.name}}_values []int = []int{ {{_self.enum_values_list(o)}} } -var _{{o.name}}_map map[string]{{o.name}} -func init() { -_{{o.name}}_map = map[string]{{o.name}}{ {{_self.enum_values_map(o)}} } -} -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 (self *{{o.name}}) IsValid() bool { - return sort.SearchInts(_{{o.name}}_values, int(*self)) != -1 -} -func {{o.name}}_GetNameByValue(value int) string { - for name, num := range _{{o.name}}_map { - if value == int(num) { - return name - } - } - return "" -} -func New{{o.name}}ByName(name string) ({{o.name}}, error) { - if v, ok := _{{o.name}}_map[name]; ok == true { - return v, nil - } - return 0, errors.Errorf("Wrong name of {{o.name}}: '%s'", name) -} -{% endmacro %} - -{% macro enum_values_list(o) %} -{%- for v in o.values|sort -%} -{{v}}, -{%- endfor ~%} -{% endmacro %} - -{% macro enum_values_map(o) %} -{%- for k,v in o.values -%} -"{{k}}" : {{v}}, -{%- endfor ~%} -{% endmacro %} - -{% macro enum_consts(o) %} -{%- for k,v in o.values ~%} -{{o.name}}_{{k}} {{o.name}} = {{v}} -{%- endfor ~%} -{% endmacro %} - -{% macro decl_rpc(o) %} - -{{_self._decl_rpc_part(o.req, o.code)}} -{{_self._decl_rpc_part(o.rsp, o.code)}} - -func New{{o.name}}() *{{o.name}} { - rpc := {{o.name}}{} - rpc.Req = New{{o.req.name}}() - rpc.Rsp = New{{o.rsp.name}}() - return &rpc -} - -type {{o.name}} struct { - ErrCode int32 - ErrMsg string - Req *{{o.req.name}} - Rsp *{{o.rsp.name}} -} - -func (rpc *{{o.name}}) SetError(code int32, msg string) { - rpc.ErrCode = code - rpc.ErrMsg = msg -} - -func (rpc *{{o.name}}) GetError() (int32, string) { - return rpc.ErrCode, rpc.ErrMsg -} - -func (rpc *{{o.name}}) GetRequest() meta.IMetaStruct { - return rpc.Req -} - -func (rpc *{{o.name}}) GetResponse() meta.IMetaStruct { - return rpc.Rsp -} - -func (rpc *{{o.name}}) GetName() string { - return "{{o.name}}" -} - -func (rpc *{{o.name}}) GetCode() int32 { - return {{o.code}} -} - -type IRPCHandler_{{o.name}} interface { - {{o.name}}(*{{o.name}}) error -} - -func (rpc *{{o.name}}) Execute(h interface{}) error{ - mh, ok := h.(IRPCHandler_{{o.name}}) - if !ok { - return errors.New("RPC '{{o.name}}(*{{o.name}}) error' is not implemented") - } - return mh.{{o.name}}(rpc) -} - -{% endmacro %} - -{% macro _decl_rpc_part(o, code) %} - -{{_self.decl_struct(o)}} - -var {{o.name}}_ func(interface{}, *{{o.name}}, *{{o.name|rpc_invert}}) error - -func (self *{{o.name}}) I{{o.name}}() *{{o.name}} { - return self -} - -func (*{{o.name}}) GetCode() int32 { - return {{code}} -} - -{% endmacro %} - diff --git a/tpl/macros_rpc.twig b/tpl/macros_rpc.twig index 619705f..e6c9878 100644 --- a/tpl/macros_rpc.twig +++ b/tpl/macros_rpc.twig @@ -56,7 +56,7 @@ func (rpc *{{ name }}) WriteResponse(writer meta.Writer) error { type {{ req_name }} struct { {%~ for f in r.req.fields %} - {{ f|fname }} {{ f.type|go_type }} `json:"{{ f|alias }}" msgpack:"{{ f|alias }}"` + {{ f|fname }} {{ f.type|go_type(f.tokens) }} `json:"{{ f|alias }}" msgpack:"{{ f|alias }}"` {%~ endfor %} } @@ -71,7 +71,7 @@ func New{{ req_name }}() *{{ req_name }} { type {{ rsp_name }} struct { {%~ for f in r.rsp.fields %} - {{ f|fname }} {{ f.type|go_type }} `json:"{{ f|alias }}" msgpack:"{{ f|alias }}"` + {{ f|fname }} {{ f.type|go_type(f.tokens) }} `json:"{{ f|alias }}" msgpack:"{{ f|alias }}"` {%~ endfor %} } diff --git a/tpl/macros_struct.twig b/tpl/macros_struct.twig index d2280ed..2367ba1 100644 --- a/tpl/macros_struct.twig +++ b/tpl/macros_struct.twig @@ -611,12 +611,16 @@ func (s *{{ name|default(o.name) }}) Reset() { {% set fname = f|fname %} {% if f.type is array %} if s.{{ fname }} == nil { - s.{{ fname }} = make({{ f.type|go_type }}, 0) + s.{{ fname }} = make({{ f.type|go_type(f.tokens) }}, 0) } else { s.{{ fname }} = s.{{ fname }}[:0] } {% elseif f.type is struct %} - s.{{ fname }}.Reset() + {% if has_token(f, 'virtual') %} + s.{{ fname }} = New{{ f.type|go_type }}() + {% else %} + s.{{ fname }}.Reset() + {% endif %} {% else %} s.{{ fname }} = {{ f|default_val }} {% endif %} @@ -687,14 +691,14 @@ func (s *{{ name|default(s.name) }}) ReadFields(reader meta.Reader) error { contSize-- } if !use_mask || (use_mask && s.FieldChanged({{ loop.index0 }})) { - {{ _self.meta_read_field(f.type, 's.' ~ f|fname, f|alias) }} + {{ _self.meta_read_field(f.type, 's.' ~ f|fname, f|alias, f.tokens) }} {% if has_token(s, 'table') %} s.changedFields.SetChanged("{{ f|alias }}") {% endif %} } {% else %} contSize-- - {{ _self.meta_read_field(f.type, 's.' ~ f|fname, f|alias) }} + {{ _self.meta_read_field(f.type, 's.' ~ f|fname, f|alias, f.tokens) }} {% if has_token(s, 'table') %} s.changedFields.SetChanged("{{ f|alias }}") {% endif %} @@ -707,7 +711,7 @@ func (s *{{ name|default(s.name) }}) ReadFields(reader meta.Reader) error { {% endmacro meta_read %} -{% macro meta_read_field(type, fname, alias) %} +{% macro meta_read_field(type, fname, alias, tokens) %} {% if type is builtin %} if err := reader.Read{{ type|builtin_type_suffix }}(&{{ fname }}, "{{ alias }}"); err != nil && err != meta.FieldNotFound { return err @@ -720,6 +724,15 @@ func (s *{{ name|default(s.name) }}) ReadFields(reader meta.Reader) error { return errors.Errorf("bad enum value `%d` for `{{ alias }}`", {{ fname }}) } {% elseif type is struct %} + {% if tokens.virtual is defined %} + if v, err := meta.ReadGeneric(reader, CreateReadableById, "{{ alias }}"); err != nil { + if err != meta.FieldNotFound { + return err + } + } else { + {{ fname }} = v.(I{{ type.name }}) + } + {% else %} if err := reader.BeginContainer("{{ alias }}"); err != nil { if err != meta.FieldNotFound { return err @@ -732,6 +745,7 @@ func (s *{{ name|default(s.name) }}) ReadFields(reader meta.Reader) error { return err } } + {% endif %} {% elseif type is array %} {% set name = fname|split('.')|last %} {% set size_var = name|lcfirst ~ 'Size' %} @@ -746,8 +760,8 @@ func (s *{{ name|default(s.name) }}) ReadFields(reader meta.Reader) error { return err } for ; {{ size_var }} > 0; {{ size_var }}-- { - var {{ tmp_var }} {{ type.value|go_type }} - {{ _self.meta_read_field(type.value, tmp_var) }} + var {{ tmp_var }} {{ type.value|go_type(tokens) }} + {{ _self.meta_read_field(type.value, tmp_var, '', tokens) }} {{ fname }} = append({{ fname }}, {{ tmp_var }}) } if err := reader.EndContainer(); err != nil { @@ -779,15 +793,19 @@ func (s *{{ name|default(o.name) }}) WriteFields(writer meta.Writer) error { {% endif %} {% for f in o.fields %} - {{ _self.meta_write_field(f.type, 's.' ~ f|fname, f|alias) }} + {{ _self.meta_write_field(f.type, 's.' ~ f|fname, f|alias, f.tokens) }} {% endfor %} return nil } + +func (s *{{ name|default(o.name) }}) FieldsCount() int { + return {{ get_all_fields(o)|length }} +} {% endmacro meta_write %} -{% macro meta_write_field(type, fname, alias) %} +{% macro meta_write_field(type, fname, alias, tokens) %} {% if type is builtin %} if err := writer.Write{{ type|builtin_type_suffix }}({{ fname }}, "{{ alias }}"); err != nil { return err @@ -797,6 +815,11 @@ func (s *{{ name|default(o.name) }}) WriteFields(writer meta.Writer) error { return err } {% elseif type is struct %} + {% if tokens.virtual is defined %} + if err := meta.WriteGeneric(writer, {{ fname }}, "{{ alias }}"); err != nil { + return err + } + {% else %} if err := writer.BeginContainer({{ get_all_fields(type)|length }}, "{{ alias }}"); err != nil { return err } @@ -806,12 +829,13 @@ func (s *{{ name|default(o.name) }}) WriteFields(writer meta.Writer) error { if err := writer.EndContainer(); err != nil { return err } + {% endif %} {% elseif type is array %} if err := writer.BeginCollection(len({{ fname }}), "{{ alias }}"); err != nil { return err } for _, v := range {{ fname }} { - {{ _self.meta_write_field(type.value, 'v') }} + {{ _self.meta_write_field(type.value, 'v', '', tokens) }} } if err := writer.EndCollection(); err != nil { return err @@ -847,7 +871,7 @@ type {{ s.name }} struct { {% endif %} {% for f in s.fields %} - {{ f|fname }} {{ f.type|go_type }} `json:"{{ f|alias }},string" msgpack:"{{ f|alias }}"` + {{ f|fname }} {{ f.type|go_type(f.tokens) }} `json:"{{ f|alias }},string" msgpack:"{{ f|alias }}"` {% endfor %} {% if has_token(s, 'bitfields') %} @@ -878,7 +902,7 @@ func New{{ name }}() *{{ name }} { } type I{{ name }} interface { - meta.Class + meta.Struct Ptr{{ name }}() *{{ name }} } @@ -897,6 +921,14 @@ func ({{ name }}) ClassName() string { func (s *{{ name }}) Ptr{{ name }}() *{{ name }} { return s } + +func Ptr{{ name }}(s meta.Struct) *{{ name }} { + ptr, ok := s.(I{{ name }}) + if !ok { + return nil + } + return ptr.Ptr{{ name }}() +} {% endmacro struct_methods %} @@ -1083,7 +1115,7 @@ func (s *{{ name|default(s.name) }}) readFieldsAssociative(reader meta.Reader) e switch field { {% for f in all_fields %} case "{{ f|alias }}": - {{ _self.meta_read_field(f.type, 's.' ~ f|fname, f|alias) }} + {{ _self.meta_read_field(f.type, 's.' ~ f|fname, f|alias, f.tokens) }} {% endfor %} default: {# continue // do not return an error for nested structs #}