{%- macro union_def(union, generate_fuzzing=false) %}
function {{union.name}}(value) {
this.initDefault_();
this.initValue_(value);
}
{{tags(union)}}
{{union.name}}.prototype.initDefault_ = function() {
this.$data = null;
this.$tag = undefined;
}
{{union.name}}.prototype.initValue_ = function(value) {
if (value == undefined) {
return;
}
var keys = Object.keys(value);
if (keys.length == 0) {
return;
}
if (keys.length > 1) {
throw new TypeError("You may set only one member on a union.");
}
var fields = [
{%- for field in union.fields %}
"{{field.name}}",
{%- endfor %}
];
if (fields.indexOf(keys[0]) < 0) {
throw new ReferenceError(keys[0] + " is not a {{union.name}} member.");
}
this[keys[0]] = value[keys[0]];
}
{%- if generate_fuzzing %}
{%- from "fuzzing.tmpl" import generate_or_mutate %}
{{union.name}}.generate = function(generator_) {
var generated = new {{union.name}};
var generators = [
{%- for field in union.fields %}
{
field: "{{field.name}}",
generator: function() { return {{generate_or_mutate('generator_', 'generate', field.kind)|indent(6)}}; },
},
{%- endfor %}
];
var result = generator_.generateUnionField(generators);
generated[result.field] = result.value;
return generated;
}
{{union.name}}.prototype.mutate = function(mutator_) {
var mutators = [
{%- for field in union.fields %}
{
field: "{{field.name}}",
mutator: function(val) { return {{generate_or_mutate('mutator_', 'mutate', field.kind, 'val.' ~ field.name)|indent(6)}}; },
},
{%- endfor %}
];
var result = mutator_.mutateUnionField(this, mutators);
this[result.field] = result.value;
return this;
}
{%- from "fuzzing.tmpl" import get_handle_deps %}
{{union.name}}.prototype.getHandleDeps = function() {
{%- for field in union.fields %}
{%- if field.kind|contains_handles_or_interfaces %}
if (this.$tag == {{union.name}}.Tags.{{field.name}}) {
return {{get_handle_deps(field.kind, 'this.' ~ field.name)}};
}
{%- endif %}
{%- endfor %}
return [];
}
{%- from "fuzzing.tmpl" import set_handles %}
{{union.name}}.prototype.setHandles = function() {
{%- for field in union.fields %}
{%- if field.kind|contains_handles_or_interfaces %}
if (this.$tag == {{union.name}}.Tags.{{field.name}}) {
return {{set_handles(field.kind, 'this.' ~ field.name)}};
}
{%- endif %}
{%- endfor %}
return [];
}
{%- endif %}
{%- for field in union.fields %}
Object.defineProperty({{union.name}}.prototype, "{{field.name}}", {
get: function() {
if (this.$tag != {{union.name}}.Tags.{{field.name}}) {
throw new ReferenceError(
"{{union.name}}.{{field.name}} is not currently set.");
}
return this.$data;
},
set: function(value) {
this.$tag = {{union.name}}.Tags.{{field.name}};
this.$data = value;
}
});
{%- endfor %}
{{encode(union)|indent(2)}}
{{decode(union)|indent(2)}}
{{validate(union)|indent(2)}}
{{union.name}}.encodedSize = 16;
{%- endmacro %}
{%- macro tags(union) %}
{{union.name}}.Tags = {
{%- for field in union.fields %}
{{field.name}}: {{field.ordinal}},
{%- endfor %}
};
{%- endmacro %}
{%- macro encode(union) %}
{{union.name}}.encode = function(encoder, val) {
if (val == null) {
encoder.writeUint64(0);
encoder.writeUint64(0);
return;
}
if (val.$tag == undefined) {
throw new TypeError("Cannot encode unions with an unknown member set.");
}
encoder.writeUint32(16);
encoder.writeUint32(val.$tag);
switch (val.$tag) {
{%- for field in union.fields %}
case {{union.name}}.Tags.{{field.name}}:
{%- if field.kind|is_bool_kind %}
encoder.writeUint8(val.{{field.name}} ? 1 : 0);
{%- else %}
encoder.{{field.kind|union_encode_snippet}}val.{{field.name}});
{%- endif %}
break;
{%- endfor %}
}
encoder.align();
};
{%- endmacro %}
{%- macro decode(union) %}
{{union.name}}.decode = function(decoder) {
var size = decoder.readUint32();
if (size == 0) {
decoder.readUint32();
decoder.readUint64();
return null;
}
var result = new {{union.name}}();
var tag = decoder.readUint32();
switch (tag) {
{%- for field in union.fields %}
case {{union.name}}.Tags.{{field.name}}:
{%- if field.kind|is_bool_kind %}
result.{{field.name}} = decoder.readUint8() ? true : false;
{%- else %}
result.{{field.name}} = decoder.{{field.kind|union_decode_snippet}};
{%- endif %}
break;
{%- endfor %}
}
decoder.align();
return result;
};
{%- endmacro %}
{%- from "validation_macros.tmpl" import validate_union_field %}
{%- macro validate(union) %}
{{union.name}}.validate = function(messageValidator, offset) {
var size = messageValidator.decodeUnionSize(offset);
if (size != 16) {
return validator.validationError.INVALID_UNION_SIZE;
}
var tag = messageValidator.decodeUnionTag(offset);
var data_offset = offset + 8;
var err;
switch (tag) {
{%- for field in union.fields %}
{%- set name = union.name ~ '.' ~ field.name %}
case {{union.name}}.Tags.{{field.name}}:
{{validate_union_field(field, "data_offset", name)}}
break;
{%- endfor %}
}
return validator.validationError.NONE;
};
{%- endmacro %}