	// Deserializes the object from an Uint8Array and returns the number of bytes read.
	this.{{.NameNative}}.prototype.unmarshal = function(data) {
		if (!data || ! data.length) throw new Error(EOF);
		var header = data[0];
		var i = 1;
		var readHeader = function() {
			if (i >= data.length) throw new Error(EOF);
			header = data[i++];
		}

		var view = new DataView(data.buffer, data.byteOffset, data.byteLength);

		var readVarint = function() {
			var pos = 0, result = 0;
			while (pos != 8) {
				var c = data[i+pos];
				result += (c & 127) * Math.pow(128, pos);
				++pos;
				if (c < 128) {
					i += pos;
					if (result > Number.MAX_SAFE_INTEGER) break;
					return result;
				}
				if (pos == data.length) throw new Error(EOF);
			}
			return -1;
		}
{{range .Fields}}{{if eq .Type "bool"}}
		if (header == {{.Index}}) {
			this.{{.NameNative}} = true;
			readHeader();
		}
{{else if eq .Type "uint8"}}
		if (header == {{.Index}}) {
			if (i + 1 >= data.length) throw new Error(EOF);
			this.{{.NameNative}} = data[i++];
			header = data[i++];
		}
{{else if eq .Type "uint16"}}
		if (header == {{.Index}}) {
			if (i + 2 >= data.length) throw new Error(EOF);
			this.{{.NameNative}} = (data[i++] << 8) | data[i++];
			header = data[i++];
		} else if (header == ({{.Index}} | 128)) {
			if (i + 1 >= data.length) throw new Error(EOF);
			this.{{.NameNative}} = data[i++];
			header = data[i++];
		}
{{else if eq .Type "uint32"}}
		if (header == {{.Index}}) {
			var x = readVarint();
			if (x < 0) throw new Error('colfer: {{.String}} exceeds Number.MAX_SAFE_INTEGER');
			this.{{.NameNative}} = x;
			readHeader();
		} else if (header == ({{.Index}} | 128)) {
			if (i + 4 > data.length) throw new Error(EOF);
			this.{{.NameNative}} = view.getUint32(i);
			i += 4;
			readHeader();
		}
{{else if eq .Type "uint64"}}
		if (header == {{.Index}}) {
			var x = readVarint();
			if (x < 0) throw new Error('colfer: {{.String}} exceeds Number.MAX_SAFE_INTEGER');
			this.{{.NameNative}} = x;
			readHeader();
		} else if (header == ({{.Index}} | 128)) {
			if (i + 8 > data.length) throw new Error(EOF);
			var x = view.getUint32(i) * 0x100000000;
			x += view.getUint32(i + 4);
			if (x > Number.MAX_SAFE_INTEGER)
				throw new Error('colfer: {{.String}} exceeds Number.MAX_SAFE_INTEGER');
			this.{{.NameNative}} = x;
			i += 8;
			readHeader();
		}
{{else if eq .Type "int32"}}
		if (header == {{.Index}}) {
			var x = readVarint();
			if (x < 0) throw new Error('colfer: {{.String}} exceeds Number.MAX_SAFE_INTEGER');
			this.{{.NameNative}} = x;
			readHeader();
		} else if (header == ({{.Index}} | 128)) {
			var x = readVarint();
			if (x < 0) throw new Error('colfer: {{.String}} exceeds Number.MAX_SAFE_INTEGER');
			this.{{.NameNative}} = -1 * x;
			readHeader();
		}
{{else if eq .Type "int64"}}
		if (header == {{.Index}}) {
			var x = readVarint();
			if (x < 0) throw new Error('colfer: {{.String}} exceeds Number.MAX_SAFE_INTEGER');
			this.{{.NameNative}} = x;
			readHeader();
		} else if (header == ({{.Index}} | 128)) {
			var x = readVarint();
			if (x < 0) throw new Error('colfer: {{.String}} exceeds Number.MAX_SAFE_INTEGER');
			this.{{.NameNative}} = -1 * x;
			readHeader();
		}
{{else if eq .Type "float32"}}
		if (header == {{.Index}}) {
 {{- if .TypeList}}
			var l = readVarint();
			if (l < 0) throw new Error('colfer: {{.String}} length exceeds Number.MAX_SAFE_INTEGER');
			if (l > colferListMax)
				throw new Error('colfer: {{.String}} length ' + l + ' exceeds ' + colferListMax + ' elements');
			if (i + l * 4 > data.length) throw new Error(EOF);

			this.{{.NameNative}} = new Float32Array(l);
			for (var n = 0; n < l; ++n) {
				this.{{.NameNative}}[n] = view.getFloat32(i);
				i += 4;
			}
 {{- else}}
			if (i + 4 > data.length) throw new Error(EOF);
			this.{{.NameNative}} = view.getFloat32(i);
			i += 4;
 {{- end}}
			readHeader();
		}
{{else if eq .Type "float64"}}
		if (header == {{.Index}}) {
 {{- if .TypeList}}
			var l = readVarint();
			if (l < 0 || l > colferListMax)
				throw new Error('colfer: {{.String}} length ' + l + ' exceeds ' + colferListMax + ' elements');
			if (i + l * 8 > data.length) throw new Error(EOF);

			this.{{.NameNative}} = new Float64Array(l);
			for (var n = 0; n < l; ++n) {
				this.{{.NameNative}}[n] = view.getFloat64(i);
				i += 8;
			}
 {{- else}}
			if (i + 8 > data.length) throw new Error(EOF);
			this.{{.NameNative}} = view.getFloat64(i);
			i += 8;
 {{- end}}
			readHeader();
		}
{{else if eq .Type "timestamp"}}
		if (header == {{.Index}}) {
			if (i + 8 > data.length) throw new Error(EOF);

			var ms = view.getUint32(i) * 1E3;
			var ns = view.getUint32(i + 4);
			ms += Math.floor(ns / 1E6);
			this.{{.NameNative}} = new Date(ms);
			this.{{.NameNative}}_ns = ns % 1E6;

			i += 8;
			readHeader();
		} else if (header == ({{.Index}} | 128)) {
			if (i + 12 > data.length) throw new Error(EOF);

			var ms = decodeInt64(data, i) * 1E3;
			var ns = view.getUint32(i + 8);
			ms += Math.floor(ns / 1E6);
			if (ms < -864E13 || ms > 864E13)
				throw new Error('colfer: {{.String}} exceeds ECMA Date range');
			this.{{.NameNative}} = new Date(ms);
			this.{{.NameNative}}_ns = ns % 1E6;

			i += 12;
			readHeader();
		}
{{else if eq .Type "text"}}
		if (header == {{.Index}}) {
 {{- if .TypeList}}
			var l = readVarint();
			if (l < 0 || l > colferListMax)
				throw new Error('colfer: {{.String}} length ' + l + ' exceeds ' + colferListMax + ' elements');

			this.{{.NameNative}} = new Array(l);
			for (var n = 0; n < l; ++n) {
				var size = readVarint();
				if (size < 0 || size > colferSizeMax)
					throw new Error('colfer: {{.String}}[' + this.{{.NameNative}}.length + '] size ' + size + ' exceeds ' + colferSizeMax + ' bytes');

				var start = i;
				i += size;
				if (i > data.length) throw new Error(EOF);
				this.{{.NameNative}}[n] = decodeUTF8(data.subarray(start, i));
			}
 {{- else}}
			var size = readVarint();
			if (size < 0 || size > colferSizeMax)
				throw new Error('colfer: {{.String}} size ' + size + ' exceeds ' + colferSizeMax + ' bytes');

			var start = i;
			i += size;
			if (i > data.length) throw new Error(EOF);
			this.{{.NameNative}} = decodeUTF8(data.subarray(start, i));
 {{- end}}
			readHeader();
		}
{{else if eq .Type "binary"}}
		if (header == {{.Index}}) {
 {{- if .TypeList}}
			var l = readVarint();
			if (l < 0 || l > colferListMax)
				throw new Error('colfer: {{.String}} length ' + l + ' exceeds ' + colferListMax + ' elements');

			this.{{.NameNative}} = new Array(l);
			for (var n = 0; n < l; ++n) {
				var size = readVarint();
				if (size < 0 || size > colferSizeMax)
					throw new Error('colfer: {{.String}}[' + this.{{.NameNative}}.length + '] size ' + size + ' exceeds ' + colferSizeMax + ' bytes');

				var start = i;
				i += size;
				if (i > data.length) throw new Error(EOF);
				this.{{.NameNative}}[n] = data.slice(start, i);
			}
 {{- else}}
			var size = readVarint();
			if (size < 0 || size > colferSizeMax)
				throw new Error('colfer: {{.String}} size ' + size + ' exceeds ' + colferSizeMax + ' bytes');

			var start = i;
			i += size;
			if (i > data.length) throw new Error(EOF);
			this.{{.NameNative}} = data.slice(start, i);
 {{- end}}
			readHeader();
		}
{{else if .TypeList}}
		if (header == {{.Index}}) {
			var l = readVarint();
			if (l < 0 || l > colferListMax)
				throw new Error('colfer: {{.String}} length ' + l + ' exceeds ' + colferListMax + ' elements');

			for (var n = 0; n < l; ++n) {
				var o = new {{.TypeRef.Pkg.NameNative}}.{{.TypeRef.NameNative}}();
				i += o.unmarshal(data.subarray(i));
				this.{{.NameNative}}[n] = o;
			}
			readHeader();
		}
{{else}}
		if (header == {{.Index}}) {
			var o = new {{.TypeRef.Pkg.NameNative}}.{{.TypeRef.NameNative}}();
			i += o.unmarshal(data.subarray(i));
			this.{{.NameNative}} = o;
			readHeader();
		}
{{end}}{{end}}
		if (header != 127) throw new Error('colfer: unknown header at byte ' + (i - 1));
		if (i > colferSizeMax)
			throw new Error('colfer: {{.String}} serial size ' + size + ' exceeds ' + colferSizeMax + ' bytes');
		return i;
	}
