import BinaryArray from './BinaryArray'
/**
* Types used by the {@link binary} decorator
* @enum
*/
const Types = {
Float32: {
extractor: Float32Array,
bytes: 4,
get: (dv, offset) => dv.getFloat32(offset),
set: (dv, offset, value) => dv.setFloat32(offset, value)
},
Float64: {
extractor: Float64Array,
bytes: 8,
get: (dv, offset) => dv.getFloat64(offset),
set: (dv, offset, value) => dv.setFloat64(offset, value)
},
Int8: {
extractor: Int8Array,
bytes: 1,
get: (dv, offset) => dv.getInt8(offset),
set: (dv, offset, value) => dv.setInt8(offset, value)
},
Int16: {
extractor: Int16Array,
bytes: 2,
get: (dv, offset) => dv.getInt16(offset),
set: (dv, offset, value) => dv.setInt16(offset, value)
},
Int32: {
extractor: Int32Array,
bytes: 4,
get: (dv, offset) => dv.getInt32(offset),
set: (dv, offset, value) => dv.setInt32(offset, value)
},
BigInt64: {
extractor: BigInt64Array,
bytes: 8,
get: (dv, offset) => dv.getBigInt64(offset),
set: (dv, offset, value) => dv.setBigInt64(offset, value)
},
Uint8: {
extractor: Uint8Array,
bytes: 1,
get: (dv, offset) => dv.getUint8(offset),
set: (dv, offset, value) => dv.setUint8(offset, value)
},
/** Not implemented */
Uint8Clamped: {
extractor: Uint8ClampedArray,
bytes: 1
},
Uint16: {
extractor: Uint16Array,
bytes: 2,
get: (dv, offset) => dv.getUint16(offset),
set: (dv, offset, value) => dv.setUint16(offset, value)
},
Uint32: {
extractor: Uint32Array,
bytes: 4,
get: (dv, offset) => dv.getUint32(offset),
set: (dv, offset, value) => dv.setUint32(offset, value)
},
BigUint64: {
extractor: BigUint64Array,
bytes: 8,
get: (dv, offset) => dv.getBigUint64(offset),
set: (dv, offset, value) => dv.setBigUint64(offset, value)
},
/**
* Array type generator `(type, length, padding=false)`
* @function
* @param {@link Types} type - One of Types.*
* @param {number} length - The number of elements of the array
* @param {boolean} padding - If true, adds initial unused bytes so initialOffset is a multiple of the elements size. One byte size {@link Types} are always treated as padded for optimization.
* @return {object} - The generated Types.* compliant
*/
Array: (type, length, padding = false) => {
return {
bytes: length * type.bytes,
padding: padding && type.bytes,
// Change getter/setter depending on padding ensured
// 1-byte sized native types always have padding ensured
...(padding || ('extractor' in type && type.bytes === 1)
? {
get (dv, offset) {
return new type.extractor(dv.buffer, offset, length)
},
set (dv, offset, values) {
const typed = new type.extractor(dv.buffer, offset, length)
typed.set(values)
return true
}
}
: {
get (dv, offset) {
return BinaryArray(dv, type, offset, length)
},
set (dv, offset, values) {
values.forEach((value, index) =>
type.set(dv, offset + type.bytes * index, value)
)
return true
}
})
}
},
/**
* Nested/composited struct generator `(Class)` which extends {@link Binary}
* @function
* @param {class} Class - The class the wrapped member belongs to
* @return {object} - The generated {@link Types} compliant
*/
Struct: (Class) => {
return {
bytes: Class.binarySize,
get (dv, offset) {
return new Class(dv, offset)
},
set (dv, offset, values) {
// TODO: Test if values is a Binary Object and we can just copy binary data, or nothing,
// because binary data, class and offset are the same.
const obj = new Class(dv, offset)
for (const prop of Object.keys(values)) {
if (Class.binaryProps.includes(prop)) {
obj[prop] = values[prop]
}
}
return true
}
}
},
/**
* Text generator `(length, {encoding='utf8', zeroTerminated=true}={})`
* @function
* @param {number} length - The maximum length of the binary array (not necessarily equal to the string length)
* @param {object} options - The options for the generated text field:
* - @param {text} encoding - The encoding (defaults to utf8)
* - @param {boolean} zeroTerminated - True if using the C zero terminated strings (default)
* @return {object} - The generated Types.* compliant
*/
Text: (length, { encoding = 'utf8', zeroTerminated = true } = {}) => {
const decoder = new TextDecoder(encoding)
const encoder = new TextEncoder() // Only UTF8 available
return {
bytes: length,
get (dv, offset) {
const arr = new Types.Uint8.extractor(dv.buffer, offset, length)
if (zeroTerminated) {
const firstZero = arr.indexOf(0x00)
if (firstZero === 0) {
return ''
} else if (firstZero > 0) {
const arrSmaller = new Types.Uint8.extractor(
dv.buffer,
offset,
firstZero
)
return decoder.decode(arrSmaller)
}
}
return decoder.decode(arr)
},
set (dv, offset, value) {
const arr = new Types.Uint8.extractor(dv.buffer, offset, length)
const { read, written } = encoder.encodeInto(value, arr)
if (zeroTerminated && written < arr.length) {
arr[written] = 0 // append null if room
}
return true
}
}
}
}
export default Types