{% macro decl_units(units) %}

{%- for u in units ~%}
  {%- 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, extra = '') %}

{% set pkey_fields = token(o, 'table_pkey')|split(',') %}
{% set pkey = pkey_fields|filter(f => f|length > 0)|map(f => o.getField(f)) %}

  {%- 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 -%}

{{_self.attributes(o)}}
public {{_self.struct_type(o)}} {{o.name}} {{_self.base_struct_class(o)}} 
{
  {{token(o, 'cs_embed', '')}}

  {{_self.decl_struct_fields(o)}}

  public {{o.parent ? 'new'}} const uint STATIC_CLASS_ID = {{o.classid}};

  public {{_self.override(o)}} uint CLASS_ID() 
  {
    return {{o.classid}}; 
  }

  {{_self.comment_POD_begin(o)}}
  public {{o.name}}()
  {
    Reset();
  }
  {{_self.comment_POD_end(o)}}

  public {{_self.override(o)}} void Reset() 
  {
    {{_self.struct_fields_reset(o)}}
  }

  {{_self.comment_non_cloneable_begin(o)}}
  public void CloneTo(ref {{o.name}} dst)
  {
    MetaIO.Clone(this, ref dst, AutogenBundle.createById);
  }

  public {{_self.virtual_clone(o)}} IMetaStruct Clone()
  {
    var dst = new {{o.name}}();
    CloneTo(ref dst);
    return dst;
  }
  {{_self.comment_non_cloneable_end(o)}}

  public {{_self.override(o)}} void SyncFields(MetaSyncContext ctx) 
  {
    {{_self.sync_fields(o)}}
  }
  
  public {{_self.override(o)}} int GetFieldsCount() 
  {
    return {{fields_count(o)}};
  }
  
  public {{_self.override(o)}} int GetDirtyFieldsCount() 
  {
{%~ if has_token(o, 'bitfields') ~%}
    return fields_mask.GetDirtyFieldsCount();
{% else %}
    return GetFieldsCount();
{%- endif ~%}
  }

{%- if has_token(o, 'bitfields') ~%}
  {{_self.bitmask_helpers(o)}}
{%- endif -%}
  
{%- if has_token(o, 'table') ~%}
  public static bool operator <({{o.name}} o1, {{o.name}} o2)
  {
    return {{o.name}}Comparer.self.Compare(o1, o2) < 0;
  }

  public static bool operator >({{o.name}} o1, {{o.name}} o2)
  {
    return {{o.name}}Comparer.self.Compare(o1, o2) > 0;
  }

  public {{o.name}}Id MakeId()
  {
    return new {{o.name}}Id{
      {% for f in pkey %}
      {{f.name}} = {{f.name}},
      {% endfor %}
    };
  }
{%- endif -%}

{%- if has_token(o, 'diffable') ~%}
  {{_self.diffable_support(o)}}
{%- endif -%}

  {{_self.decl_struct_accessor_implements(o)}}

  {{extra}}
}

{%- if has_token(o, 'table') ~%}
public class {{o.name}}Comparer : IComparer<{{o.name}}>
{
  public readonly static {{o.name}}Comparer self = new {{o.name}}Comparer();

  public int Compare({{o.name}} o1, {{o.name}} o2)
  {
    int result;

    {% set comparable = pkey %}
    {% if comparable|length > 1 %}
      {% set comparable = comparable [1:] %}
    {% endif %}

    {% for f in comparable %}
      {% if not loop.first %}
      if(result == 0)
      {% endif %}
      result = o1.{{f.name}}.CompareTo(o2.{{f.name}});
    {% endfor %}

    return result;
  }
}
{%- endif ~%}

{% endmacro %}

{%- macro decl_struct_fields(o) -%}
{%- if has_token(o, 'bitfields') ~%}
public FieldsMask fields_mask;
{%- endif -%}
{%- for f in o.fields ~%}
{{_self.decl_struct_field(o, f)}}
{%- endfor -%}
{%- endmacro -%}

{%- macro decl_struct_field(o, f) -%}
{{_self.attributes(f)}}
{% if has_token(f, 'flt_i18n') -%}
{{f.type}} _{{f.name}} = "";
List<{{f.type}}> __{{f.name}} = new List<{{f.type}}>();
{%- endif ~%}
public {{f.type|cs_type|obscure_type(f)}} {{f.name}} {% if not has_token(o, 'POD') -%} {{_self.decl_init_value(f)}} {%- endif -%} {% if not has_token(f, 'flt_i18n') -%};{%- endif -%}
{%- endmacro -%}

{% macro decl_init_value(f) %}
{%- if f.type is instanceof('\\mtgBuiltinType') -%}
{%- if f.type.isstring -%}
{% if has_token(f, 'flt_i18n') -%}
{get{return plural_{{f.name}}(double.NaN);}set{_{{f.name}}=value;}}
{{f.type}} plural_{{f.name}}(double force_n){return MetaI18N.I18NPick(_{{f.name}},__{{f.name}},"#",force_n);}
{%- else -%}
= ""
{%- endif ~%}
{%- endif -%}
{%- else -%}
{%- if has_token(f, 'default') and token(f, 'default') == 'null'  -%}
/*null*/
{%- else -%}
= new {{f.type|cs_type}}()
{%- endif -%}
{%- endif -%}
{% endmacro %}

{% macro struct_fields_reset(o) %}
{%- if o.parent ~%} 
base.Reset();
{%- endif -%}
{%- for f in o.fields ~%}
{% set fname = f.name %}
{% if has_token(f, 'flt_i18n') -%}
{% set fname = '_' ~ f.name %}
if(_{{fname}} == null) _{{fname}} = new(); else _{{fname}}.Clear();
{%- endif ~%}
{{var_reset(fname, f.type, token_or(f, 'default', null))}}
{%- endfor -%}
{%- if has_token(o, 'bitfields') ~%} 
ResetFieldMask();
{%- endif -%}
{% endmacro %}

{%- macro attributes(o) %}
{% if has_token(o, "cs_obsolete") %}
/// <summary>
/// {{token(o, "cs_obsolete")}}
/// </summary>
[Obsolete]
{% endif %}
{%- if has_token(o, 'cs_attributes') -%} 
{%- for attr in token(o, 'cs_attributes')|split(',') -%} 
[{{attr}}]
{%- endfor -%} 
{%- endif -%}
{%- endmacro %}

{%- macro struct_type(o) -%}
{{has_token(o, 'POD') ? 'struct' : 'class'}}
{%- endmacro -%}

{%- macro base_struct_class(o) -%}
{%- if has_token(o, 'POD') -%} 
: IMetaStruct
{%- else -%}
: {{o.parent ? o.parent.name : 'BaseMetaStruct'}}
{{- has_token(o, 'cloneable') and not o.parent ? ', IMetaCloneable' -}}
{%- endif -%}
{%- if has_token(o, "cs_implements") -%}
{%- for ifs in token(o, "cs_implements")|split(',') -%} 
, {{ifs}}
{%- endfor -%} 
{%- endif -%} 

{%- for ai in get_accessor_interfaces(o) -%} 
, {{ai.interfacename}}
{%- endfor -%} 
{%- endmacro -%}

{%- macro override(o) -%}
{%- if not has_token(o, 'POD') -%} 
override
{%- endif -%}
{%- endmacro -%}

{%- macro virtual(o) -%}
{%- if not has_token(o, 'POD') -%} 
{{o.parent ? 'override' : 'virtual'}}
{%- endif -%}
{%- endmacro -%}

{%- macro comment_POD_begin(o) -%}
{%- if has_token(o, 'POD') -%} 
/* commented in POD
{%- endif -%}
{%- endmacro -%}

{%- macro comment_POD_end(o) -%}
{%- if has_token(o, 'POD') -%} 
*/
{%- endif -%}
{%- endmacro -%}

{%- macro comment_non_cloneable_begin(o) -%}
{%- if not has_token(o, 'cloneable') -%} 
/* commented in non-cloneable
{%- endif -%}
{%- endmacro -%}

{%- macro comment_non_cloneable_end(o) -%}
{%- if not has_token(o, 'cloneable') -%} 
*/
{%- endif -%}
{%- endmacro -%}

{%- macro virtual_clone(o) -%}
{%- if has_token(o, 'cloneable') -%} 
  {%- if has_token(o, 'POD') -%} 
  {%- elseif o.parent and has_token_in_parent(o.parent, 'cloneable') -%} 
    override
  {%- else -%}
    virtual
  {%- endif -%}
{%- endif -%}
{%- endmacro -%}

{%- macro sync_fields(o) -%}
{%- if has_token(o, 'bitfields') ~%}
var bitctx = new MetaIO.BitfieldsContext(ctx, fields_mask);
bitctx.SyncMaskHeader();
{%- endif -%}
{%- if o.parent ~%} 
base.SyncFields(ctx);
{%- endif -%}
{%- for f in o.fields ~%}
{% set fname = f.name %}
{% if has_token(f, 'flt_i18n') -%}
{% set fname = '_' ~ f.name %}
{%- endif -%}
{{var_sync(fname, f.type, 'ctx', f.tokens, get_sync_opts(o, 'bitctx'))}}
{%- endfor -%}
{%- endmacro -%}

{%- macro bitmask_helpers(o) ~%}

  public void ResetFieldMask()
  {
    fields_mask = FieldsMask.MakeClean(fields_amount: {{fields_count(o)}});
  }

  public void SetPrimaryFieldsChanged()
  {
    SetPrimaryFieldsChanged(ref this.fields_mask);
  }

  static void SetPrimaryFieldsChanged(ref FieldsMask mask)
  {
{%- for f in o.fields ~%}
{%- if is_primary_field(o, f) ~%}
    MetaIO.SetFieldDirty(ref mask, {{loop.index0}});
{%- endif -%}
{%- endfor ~%}
  }

  public bool IsContentDirty()
  {
    int fields_amount = {{fields_count(o)}};
    var primary_id_mask = FieldsMask.MakeClean(fields_amount); 
    SetPrimaryFieldsChanged(ref primary_id_mask);
    for(int i = 0; i < fields_amount; i++)
    {
      bool is_primary_id = primary_id_mask.IsDirty(i);
      if(!is_primary_id && fields_mask.IsDirty(i))
        return true;
    }
    
    return false;
  }

  public void SetDirtyMask()
  {
    fields_mask = FieldsMask.MakeDirty(fields_amount: {{fields_count(o)}});
  }

  public void SetDirtyMaskDeep()
  {
    SetDirtyMask();
{%- for f in o.fields ~%}
{%- if f.type is instanceof('\\mtgMetaStruct') and has_token(f.type, 'bitfields') ~%}
    {{f.name}}.SetDirtyMaskDeep();
{%- elseif f.type is instanceof('\\mtgArrType') and f.type.value is instanceof('\\mtgMetaStruct') and has_token(f.type.value, "bitfields") ~%}
    {
      for(int i=0;i<{{f.name}}.Count;++i) 
      {
        var __tmp = {{f.name}}[i];
        __tmp.SetDirtyMaskDeep();
        {{f.name}}[i] = __tmp;
      }
    }
{%- endif -%}
{%- endfor ~%}
  }

{%- endmacro -%}

{% macro decl_enum(o) %}
{{_self.attributes(o)}}
public enum {{o.name}}
{
{%- for n,v in o.values ~%}
  {{n}} = {{v}},
{%- endfor ~%}
}
{% endmacro %}

{% macro decl_rpc(o, is_global = true) %}

{% if is_global %}
{{_self.decl_struct(o.req)}}
{{_self.decl_struct(o.rsp)}}
{% endif %}

public class {{o.name}} : IRpc
{
{% if not is_global %}
  {{_self.decl_struct(o.req)}}
  {{_self.decl_struct(o.rsp)}}
{% endif %}

  public IRpcError error = null;
  public {{o.req.name}} req = new {{o.req.name}}();
  public {{o.rsp.name}} rsp = new {{o.rsp.name}}();

  public int GetCode() 
  {
    return {{o.code}};
  }

  public void SetError(IRpcError error)
  {
    this.error = error;
  }

  public IRpcError GetError()
  {
    return error;
  }

  public IMetaStruct GetRequest()
  {
    return req as IMetaStruct;
  }

  public IMetaStruct GetResponse()
  {
    return rsp as IMetaStruct;
  }
}

{% endmacro %}

{%- macro diffable_support(o) -%}

    public bool GetDiff({{o.name}} old, {{o.name}} diff = null, {{o.name}}RemovedIds removed = null)
    {
      if(diff != null) 
        diff.Reset();
      if(removed != null)
        removed.Reset();
      bool no_changes = true;

    {% set field_idx = -1 %}
    {%- for f in o.fields ~%}
      {% set field_idx = field_idx + 1 %}
      
      {%- if not has_token(f, 'nodiff') -%}
      {{_self.field_diff(f, field_idx, o)}}
      {%- endif -%}
    {% endfor %}

     return !no_changes;
    }
    
    {% set unique_diff_units = [] %}
    {% for u in get_diff_related_units(o) %}
      {% if u not in unique_diff_units %}
        {{_self.diff_methods_for(u)}}
        {% set unique_diff_units = unique_diff_units|merge([u]) %}
      {% endif %}
    {% endfor %}

{% endmacro %}

{%- macro diff_methods_for(u) -%}
  {% if has_token(u, 'table') %}
  static public bool DiffOne(ref {{u.name}} curr, {{u.name}} old)
  {
    return !{{_self.compare_func_name(u)}}(ref curr, old);
  }

  static public bool DiffCollection(List<{{u.name}}> items, List<{{u.name}}> old_items, List<{{u.name}}> changed, List<{{u.name}}Id> removed)
  {
    bool has_diff = false;
    if(changed != null)
      changed.Clear();

    items.Sort({{u.name}}Comparer.self);
    old_items.Sort({{u.name}}Comparer.self);

    int i = 0;
    int old_i = 0;
    for(; i < items.Count && old_i < old_items.Count;)
    {
      var old = old_items[old_i];
      var item = items[i];

      if(old < item)
      {
        if(removed != null)
          removed.Add(old.MakeId());
        old_i++;
        has_diff = true;
      }
      else if(old > item)
      {
        item.SetDirtyMaskDeep();
        if(changed != null)
          changed.Add(item);
        i++;
        has_diff = true;
      }
      else
      {
        if(!{{_self.compare_func_name(u)}}(ref item, old) && item.IsContentDirty())
        {
          if(changed != null)
            changed.Add(item);
          has_diff = true;
        }

        i++;
        old_i++;
      }
    }

    //items leftovers are considered changed
    for(; i < items.Count; i++)
    {
      var item = items[i];
      item.SetDirtyMaskDeep();
      if(changed != null)
        changed.Add(item);
      has_diff = true;
    }

    //old items leftovers are considered removed
    for(; old_i < old_items.Count; old_i++)
    {
      if(removed != null)
        removed.Add(old_items[old_i].MakeId());
      has_diff = true;
    }

    //if(changed.Count > 0)
    //  MetaIO.LogDebug("Changed in collection {{u.name}}");
    //if(removed_ids.Count > 0)
    //  MetaIO.LogDebug("Removed in collection {{u.name}}");

    return has_diff;
  }
  {% endif %}

  public static bool {{_self.compare_func_name(u)}}(ref {{u.name}} a, {{u.name}} b)
  {
    bool is_equal = true;

  {%- if has_token(u, 'bitfields') ~%}
    a.ResetFieldMask();
  {%- endif -%}

  {%- for f in u.fields ~%}
  {{_self.field_compare(u, f, loop.index0)}}
  {%- endfor -%}

  {%- if has_token(u, 'bitfields') ~%}
    if(!is_equal)
      a.SetPrimaryFieldsChanged();
  {%- endif -%}

    return is_equal;
  }

{% endmacro %}

{% macro compare_func_name(o) %}
{{has_token(o, 'bitfields')?'CompareAndMarkFields':'IsEqual'}}
{%- endmacro %}

{% macro field_compare_array_bitfields_nested_diffable(o, f, field_idx) %}
    {
      int {{f.name}}_count_a = a.{{f.name}} == null ? 0 : a.{{f.name}}.Count;
      int {{f.name}}_count_b = b.{{f.name}} == null ? 0 : b.{{f.name}}.Count;

      //For NESTED arrays of DIFFABLE structs:
      //for DB compatibility we must add the WHOLE ARRAY to the diff if ANY ELEMENT of the array has changed.
      //That means marking each element's fields_mask as dirty

      //Changed size means the array has changed, no furhter checks required.
      bool {{f.name}}_equal = {{f.name}}_count_a == {{f.name}}_count_b;

      //For same size arrays - check contents for changes.
      if({{f.name}}_equal)
      {
        for(int i=0;i<{{f.name}}_count_a && i<{{f.name}}_count_b;++i)
        {
          var tmp_{{f.name}} = a.{{f.name}}[i];
          if(!CompareAndMarkFields(ref tmp_{{f.name}}, b.{{f.name}}[i]))
          {
            {{f.name}}_equal = false;
            break;
          }
        }
      }

      //If change detected - mark top-level field as changed and add the whole array to the diff
      if(!{{f.name}}_equal)
      {
        MetaIO.SetFieldDirty(ref a.fields_mask, {{field_idx}});
        for(int i=0; i<{{f.name}}_count_a;++i)
        {
          var tmp_{{f.name}} = a.{{f.name}}[i];
          tmp_{{f.name}}.SetDirtyMaskDeep();
          a.{{f.name}}[i] = tmp_{{f.name}};
          is_equal = false;
        }
      }
    }
{%- endmacro %}

{% macro field_compare_array_bitfields_nested_plain(o, f, field_idx) %}
    if(a.{{f.name}} == null ||
       b.{{f.name}} == null ||
       a.{{f.name}}.Count != b.{{f.name}}.Count)
    {
      MetaIO.SetFieldDirty(ref a.fields_mask, {{field_idx}});
      is_equal = false;
    }
    else
    {
      for(int i=0;i<a.{{f.name}}.Count;++i)
      {
        {%- if f.type.value is instanceof('\\mtgMetaStruct') ~%}
          var tmp_{{f.name}} = a.{{f.name}}[i];
          if(!{{_self.compare_func_name(f.type.value)}}(ref tmp_{{f.name}}, b.{{f.name}}[i]))
          {
            MetaIO.SetFieldDirty(ref a.fields_mask, {{field_idx}});
            is_equal = false;
            break;
          }
        {%- else -%}
          if(a.{{f.name}}[i] != b.{{f.name}}[i])
          {
            MetaIO.SetFieldDirty(ref a.fields_mask, {{field_idx}});
            is_equal = false;
            break;
          }
        {%- endif -%}
      }
    }
{%- endmacro %}

{% macro field_compare_array_plain(o, f, field_idx) %}
    if(a.{{f.name}} == null || 
       b.{{f.name}} == null || 
       a.{{f.name}}.Count != b.{{f.name}}.Count) 
      return false;
    for(int i=0;i<a.{{f.name}}.Count;++i) 
    {
      {%- if f.type.value is instanceof('\\mtgMetaStruct') ~%}
        var tmp_{{f.name}} = a.{{f.name}}[i];
        if(!{{_self.compare_func_name(f.type.value)}}(ref tmp_{{f.name}}, b.{{f.name}}[i]))
          return false;
      {%- else -%}
        if(a.{{f.name}}[i] != b.{{f.name}}[i])
          return false;
      {%- endif -%}
    }
{%- endmacro %}

{%- macro field_compare(o, f, field_idx) -%}

  {% if f.type is instanceof('\\mtgArrType') ~%}
    {% if has_token(o, 'bitfields') ~%}
      {% if has_token(f.type.value, 'bitfields') ~%}
        {{_self.field_compare_array_bitfields_nested_diffable(o, f, field_idx)}}
      {% else ~%}
        {{_self.field_compare_array_bitfields_nested_plain(o, f, field_idx)}}
      {% endif ~%}
    {% else ~%}
      {{_self.field_compare_array_plain(o, f, field_idx)}}
    {% endif ~%}

  {% elseif f.type is instanceof('\\mtgMetaStruct') ~%}
    var tmp_{{f.name}} = a.{{f.name}}[i];
    if(!{{_self.compare_func_name(f.type.value)}}(ref tmp_{{f.name}}, b.{{f.name}}))
    {% if has_token(o, 'bitfields') ~%}
    {
      MetaIO.SetFieldDirty(ref a.fields_mask, {{field_idx}});
      is_equal = false;
    }
    {% else ~%}
      return false;
    {% endif ~%}
  {% elseif f.type is instanceof('\\mtgBuiltinType') and f.type.isstring ~%}
      if((a.{{f.name}} == null ? "" : a.{{f.name}}) 
      != (b.{{f.name}} == null ? "" : b.{{f.name}}))
      {% if has_token(o, 'bitfields') ~%}
      {
        MetaIO.SetFieldDirty(ref a.fields_mask, {{field_idx}});
        is_equal = false;
      }
      {% else ~%}
        return false;
      {%- endif -%}
  {% else ~%}
      if(a.{{f.name}} != b.{{f.name}})
      {% if has_token(o, 'bitfields') ~%}
      {
        MetaIO.SetFieldDirty(ref a.fields_mask, {{field_idx}});
        is_equal = false;
      }
      {% else ~%}
        return false;
      {%- endif -%}
  {%- endif -%}

{% endmacro %}

{%- macro field_diff(f, field_idx, o) -%}

{% if f.type is instanceof('\\mtgMetaStruct') %}
  {%- if not has_token(f.type, 'POD') -%}
  {{Error("Diffable struct '" ~ f.type ~ "' must be POD")}}
  {%- endif -%}

  {
    var __tmp = {{f.name}};
    if(DiffOne(ref __tmp, old.{{f.name}})) 
    { 
      no_changes &= false; 
      if(diff != null) 
      { 
        diff.{{f.name}} = __tmp; 
        MetaIO.SetFieldDirty(ref diff.fields_mask, {{field_idx}}); 
      } 
    }
  }
{% elseif f.type is instanceof('\\mtgArrType') %}
  {%- if not has_token(f.type.value, 'POD') -%}
  {{Error("Diffable struct '" ~ f.type.value ~ "' must be POD")}}
  {%- endif -%}

  if(DiffCollection({{f.name}}, old.{{f.name}}, 
      diff == null ? null : diff.{{f.name}}, 
      removed == null ? null : removed.{{f.name}}
     )) 
  { 
    no_changes &= false; 
    if(diff != null) 
      MetaIO.SetFieldDirty(ref diff.fields_mask, {{field_idx}});
    if(removed != null && removed.{{f.name}}.Count > 0)
      MetaIO.SetFieldDirty(ref removed.fields_mask, {{ field_index(find_struct(o.name ~ 'RemovedIds'), f.name) }});
  }
{% elseif f.type is instanceof('\\mtgBuiltinType') %}
  if(diff != null) 
    diff.{{f.name}} = {{f.name}};

  if({{f.name}} != old.{{f.name}}) 
  { 
    no_changes &= false; 
    if(diff != null) 
      MetaIO.SetFieldDirty(ref diff.fields_mask, {{field_idx}}); 
  }
{% else %}
  {{Error("Diff for field '"~ f.name ~"' is not supported") }}
{% endif %}

{% endmacro %}

{% macro decl_accessor_interface(ai) ~%}
public interface {{ai.interfacename}}
{
  {%- for aif in ai.fields ~%}
  {% if aif.is_accessor -%}
  {{aif.field.type|cs_type}} Get{{aif.camelfieldname}}();
  void Set{{aif.camelfieldname}}({{aif.field.type|cs_type}} v);
  {% endif -%}

  {%- if aif.is_propget -%}
  {{aif.field.type|cs_type}} {{aif.camelfieldname}} {
  {%- if aif.is_propget -%}
    get;
  {%- endif %}
  {%- if aif.is_propset -%}
    set;
  {%- endif -%}
  }
  {%- endif ~%}
  {%- endfor ~%}
}
{% endmacro %}

{%- macro decl_struct_accessor_implements(o) -%}
{%- for ai in get_accessor_interfaces(o) ~%}
{%- for aif in ai.fields ~%}
{% if aif.is_accessor %}
  public {{aif.field.type|cs_type}} Get{{aif.camelfieldname}}()
  {
    return {{aif.field.name}};
  }
  public void Set{{aif.camelfieldname}}({{aif.field.type|cs_type}} v)
  {
    this.{{aif.field.name}} = v;
  }
{% endif %}

{% if aif.is_propget or aif.is_propset %}
  public {{aif.field.type|cs_type}} {{aif.camelfieldname}} {
  {%- if aif.is_propget -%}
    get => this.{{aif.field.name}};
  {%- endif -%}
  {%- if aif.is_propset -%}
    set => this.{{aif.field.name}} = value;
  {%- endif -%}
  }
{%- endif ~%}
{% endfor %}
{%- endfor ~%}
{% endmacro %}