chromium/mojo/public/tools/bindings/generators/js_templates/union_definition.tmpl

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