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