enhance-data-view
Version:
Reactive DataView extension with chainable API for type-safe binary data manipulation.
2 lines (1 loc) • 15.1 kB
JavaScript
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).EDataView={})}(this,function(e){"use strict";const t=Symbol("TYPE_DEFINITION");function n(e){return"object"==typeof e&&null!==e&&e.isTypeDefinition===t}const r=Symbol("TYPE_DEFINITION_RAW");function i(e){const t=e;if("object"==typeof t&&null!==t){const e=t[r];if(e)return e()}return t}function s(e){let n,r,i,o,f,l=e;const a=e=>s(e??l).setSize(n).setAlign(r).setGetter(i).setSetter(o).setReactive(f),c=()=>{throw new Error(`Getter not implemented for type '${l||"unknown"}'`)},u=()=>{throw new Error(`Setter not implemented for type '${l||"unknown"}'`)},d=({view:e,littleEndian:t,localOffset:n,baseOffset:r,cacheGetter:i})=>{const s=()=>g.getter({view:e,offset:n+r(),littleEndian:t});return i(s),s()},g={isTypeDefinition:t,get name(){return l??"unknown"},get size(){return Math.max(n??0,0)},get align(){return Math.max(r??n??1,1)},get getter(){return i??c},get setter(){return o??u},get reactive(){return f??d},setName:e=>(l=e,g),setSize:e=>(n=e,g),setAlign:e=>(r=e,g),setGetter:e=>(i=e,g),setSetter:e=>(o=e,g),setReactive:e=>(f=e,g),freeze:()=>{const e=a();return Object.freeze({isTypeDefinition:t,name:e.name,size:e.size,align:e.align,getter:e.getter,setter:e.setter,reactive:e.reactive,clone:e.clone})},clone:a};return g}const o=Symbol("PROPERTY_DEFINITION");function f(e,t){return{isPropertyDefinition:o,type:e,align:t?.align,offset:t?.offset,order:t?.order}}function l(e){return"object"==typeof e&&null!==e&&e.isPropertyDefinition===o}const a=Symbol("STRUCT_DEFINITION");function c(e,t){return"number"==typeof e?{isPaddingDefinition:a,size:e,align:t?.align??1,offset:t?.offset,order:t?.order}:{isPaddingDefinition:a,size:e.size,align:t?.align??e.align,offset:t?.offset,order:t?.order}}function u(e){return"object"==typeof e&&null!==e&&e.isPaddingDefinition===a}const d=s("UNKNOWN").freeze(),g=s("INT_8").setSize(1).setGetter(({view:e,offset:t})=>e.getInt8(t)).setSetter(({view:e,offset:t},n)=>e.setInt8(t,n)).setReactive(({view:e,localOffset:t,baseOffset:n,cacheGetter:r})=>{const i=()=>e.getInt8(t+n());return r(i),i()}).freeze(),y=s("INT_16").setSize(2).setGetter(({view:e,offset:t,littleEndian:n})=>e.getInt16(t,n)).setSetter(({view:e,offset:t,littleEndian:n},r)=>e.setInt16(t,r,n)).setReactive(({view:e,littleEndian:t,localOffset:n,baseOffset:r,cacheGetter:i})=>{const s=()=>e.getInt16(n+r(),t);return i(s),s()}).freeze(),p=y.clone("SHORT").freeze(),w=s("INT_32").setSize(4).setGetter(({view:e,offset:t,littleEndian:n})=>e.getInt32(t,n)).setSetter(({view:e,offset:t,littleEndian:n},r)=>e.setInt32(t,r,n)).setReactive(({view:e,littleEndian:t,localOffset:n,baseOffset:r,cacheGetter:i})=>{const s=()=>e.getInt32(n+r(),t);return i(s),s()}).freeze(),v=w.clone("INT").freeze(),O=s("INT_64").setSize(8).setGetter(({view:e,offset:t,littleEndian:n})=>e.getBigInt64(t,n)).setSetter(({view:e,offset:t,littleEndian:n},r)=>e.setBigInt64(t,r,n)).setReactive(({view:e,littleEndian:t,localOffset:n,baseOffset:r,cacheGetter:i})=>{const s=()=>e.getBigInt64(n+r(),t);return i(s),s()}).freeze(),z=O.clone("LONG").freeze(),m=s("UINT_8").setSize(1).setGetter(({view:e,offset:t})=>e.getUint8(t)).setSetter(({view:e,offset:t},n)=>e.setUint8(t,n)).setReactive(({view:e,localOffset:t,baseOffset:n,cacheGetter:r})=>{const i=()=>e.getUint8(t+n());return r(i),i()}).freeze(),E=m.clone("BYTE").freeze(),T=s("CHAR").setSize(1).setGetter(({view:e,offset:t})=>String.fromCharCode(e.getUint8(t))).setSetter(({view:e,offset:t},n)=>e.setUint8(t,n.charCodeAt(0))).setReactive(({view:e,localOffset:t,baseOffset:n,cacheGetter:r})=>{const i=()=>String.fromCharCode(e.getUint8(t+n()));return r(i),i()}).freeze(),h=s("UINT_16").setSize(2).setGetter(({view:e,offset:t,littleEndian:n})=>e.getUint16(t,n)).setSetter(({view:e,offset:t,littleEndian:n},r)=>e.setUint16(t,r,n)).setReactive(({view:e,littleEndian:t,localOffset:n,baseOffset:r,cacheGetter:i})=>{const s=()=>e.getUint16(n+r(),t);return i(s),s()}).freeze(),b=h.clone("USHORT").freeze(),N=h.clone("WORD").freeze(),S=s("UINT_32").setSize(4).setGetter(({view:e,offset:t,littleEndian:n})=>e.getUint32(t,n)).setSetter(({view:e,offset:t,littleEndian:n},r)=>e.setUint32(t,r,n)).setReactive(({view:e,littleEndian:t,localOffset:n,baseOffset:r,cacheGetter:i})=>{const s=()=>e.getUint32(n+r(),t);return i(s),s()}).freeze(),I=S.clone("UINT").freeze(),U=S.clone("DWORD").freeze(),_=s("UINT_64").setSize(8).setGetter(({view:e,offset:t,littleEndian:n})=>e.getBigUint64(t,n)).setSetter(({view:e,offset:t,littleEndian:n},r)=>e.setBigUint64(t,r,n)).setReactive(({view:e,littleEndian:t,localOffset:n,baseOffset:r,cacheGetter:i})=>{const s=()=>e.getBigUint64(n+r(),t);return i(s),s()}).freeze(),A=_.clone("ULONG").freeze(),G=s("FLOAT_16").setSize(2).setGetter(({view:e,offset:t,littleEndian:n})=>e.getFloat16(t,n)).setSetter(({view:e,offset:t,littleEndian:n},r)=>e.setFloat16(t,r,n)).setReactive(({view:e,littleEndian:t,localOffset:n,baseOffset:r,cacheGetter:i})=>{const s=()=>e.getFloat16(n+r(),t);return i(s),s()}).freeze(),D=s("FLOAT_32").setSize(4).setGetter(({view:e,offset:t,littleEndian:n})=>e.getFloat32(t,n)).setSetter(({view:e,offset:t,littleEndian:n},r)=>e.setFloat32(t,r,n)).setReactive(({view:e,littleEndian:t,localOffset:n,baseOffset:r,cacheGetter:i})=>{const s=()=>e.getFloat32(n+r(),t);return i(s),s()}).freeze(),R=D.clone("FLOAT").freeze(),k=s("FLOAT_64").setSize(8).setGetter(({view:e,offset:t,littleEndian:n})=>e.getFloat64(t,n)).setSetter(({view:e,offset:t,littleEndian:n},r)=>e.setFloat64(t,r,n)).setReactive(({view:e,littleEndian:t,localOffset:n,baseOffset:r,cacheGetter:i})=>{const s=()=>e.getFloat64(n+r(),t);return i(s),s()}).freeze(),L=k.clone("DOUBLE").freeze();var P=Object.freeze({__proto__:null,BYTE:E,CHAR:T,DOUBLE:L,DWORD:U,FLOAT:R,FLOAT_16:G,FLOAT_32:D,FLOAT_64:k,INT:v,INT_16:y,INT_32:w,INT_64:O,INT_8:g,LONG:z,SHORT:p,UINT:I,UINT_16:h,UINT_32:S,UINT_64:_,UINT_8:m,ULONG:A,UNKNOWN:d,USHORT:b,WORD:N});const F=(()=>{const e=new TextEncoder,t=new TextDecoder("utf-8");return{encode:t=>e.encode(t),decode:e=>t.decode(e)}})();e.BYTE=E,e.CHAR=T,e.DOUBLE=L,e.DWORD=U,e.DefaultStringCoder=F,e.FLOAT=R,e.FLOAT_16=G,e.FLOAT_32=D,e.FLOAT_64=k,e.INT=v,e.INT_16=y,e.INT_32=w,e.INT_64=O,e.INT_8=g,e.LONG=z,e.OperationRawSymbol=r,e.PaddingDefinitionSymbol=a,e.PropertyDefinitionSymbol=o,e.SHORT=p,e.TypeDefinitionSymbol=t,e.UINT=I,e.UINT_16=h,e.UINT_32=S,e.UINT_64=_,e.UINT_8=m,e.ULONG=A,e.UNKNOWN=d,e.USHORT=b,e.WORD=N,e.defineArray=function e(n,s,o,f){let l,a,c,u,g=d,y=0;const p=e=>(l=e,z),w=(e,t)=>(g=e??d,u=t,z),v=e=>(y=e??0,z),O=t=>e(g,y,u,t??l).setSize(a).setAlign(c),z={isTypeDefinition:t,get name(){return l??`${g.name}[${y}]`},get size(){return Math.max(a??g.size*y,0)},get align(){return Math.max(c??g.align,1)},get element(){return g},get filler(){return u},get length(){return y},getter:({view:e,offset:t,littleEndian:n})=>{const r=new Array(y);for(let i=0;i<y;i++)r[i]=g.getter({view:e,offset:t+i*g.size,littleEndian:n});return r},setter:({view:e,offset:t,littleEndian:n},r)=>{const i=r.length,s=Math.min(i,y);for(let i=0;i<s;i++)g.setter({view:e,offset:t+i*g.size,littleEndian:n},r[i]);if(void 0!==u&&i<y)for(let r=i;r<y;r++)g.setter({view:e,offset:t+r*g.size,littleEndian:n},u)},reactive:({view:e,littleEndian:t,localOffset:n,baseOffset:s,cacheGetter:o})=>{const f=new Map,l=r=>{let i=f.get(r);if(i)return i();const o={view:e,littleEndian:t,localOffset:n+r*g.size,baseOffset:s,cacheGetter:e=>f.set(r,e)};return i=()=>g.reactive(o),f.set(r,i),i()};let a;const c=r=>{const o=Array.prototype[r];if("function"!=typeof o)return;const f=(...r)=>{const f=(()=>{if(a)return a;a=new Array(y);for(let e=0;e<y;e++)a[e]=l(e);return a})().slice(),c=o.call(f,...r);return z.setter({view:e,offset:s()+n,littleEndian:t},f.map(e=>i(e))),c};return u.set(r,f),f},u=new Map([["length",y],["forEach",(e,t)=>{for(let n=0;n<y;n++)e.call(t,l(n),n,p)}],["map",(e,t)=>{const n=new Array(y);for(let r=0;r<y;r++)n[r]=e.call(t,l(r),r,p);return n}],[Symbol.iterator,function*(){for(let e=0;e<y;e++)yield l(e)}],[r,()=>z.getter({view:e,offset:s()+n,littleEndian:t})]]);let d;const p=new Proxy([],{get:(e,t)=>{if("symbol"==typeof t)return u.has(t)?u.get(t):c(t);const n=Number(t);return isNaN(n)?u.has(t)?u.get(t):c(t):n<0||n>=y?void 0:l(n)},set:(r,i,o)=>{if("symbol"==typeof i)return!1;const f=Number(i);return!isNaN(f)&&(!(f<0||f>=y)&&(g.setter({view:e,offset:s()+n+f*g.size,littleEndian:t},o),!0))},has:(e,t)=>{if("symbol"==typeof t)return!1;const n=Number(t);return!isNaN(n)&&!(n<0||n>=y)},ownKeys:()=>{if(d)return d;d=new Array(y);for(let e=0;e<y;e++)d[e]=String(e);return d},defineProperty:()=>!1,deleteProperty:()=>!1});return o(()=>p),p},setName:p,setSize:e=>(a=e,z),setAlign:e=>(c=e,z),setElement:w,setLength:v,freeze:()=>{const e=O();return Object.freeze({isTypeDefinition:t,name:e.name,size:e.size,align:e.align,element:e.element,filler:e.filler,length:e.length,getter:e.getter,setter:e.setter,reactive:e.reactive,clone:e.clone})},clone:O};return"object"==typeof n?(w(n,o),v(s),p(f)):p(n),z},e.definePadding=c,e.definePrimitive=s,e.defineProperty=f,e.defineString=function e(n,r,i){let s,o,f,l=0,a=F,c=new Uint8Array(l);const u=e=>(s=e,p),d=e=>(l=e??0,c=new Uint8Array(l),p),g=e=>(f=e,p),y=t=>e(l,f,t??s).setAlign(o).setCoder(a),p={isTypeDefinition:t,get name(){return s??`string(${l})`},get size(){return Math.max(l,0)},get align(){return Math.max(o??1,1)},get filler(){return f},get coder(){return a},getter:({view:e,offset:t})=>{let n=l;for(let r=0;r<l;r++){const i=e.getUint8(t+r);if(c[r]=i,"number"==typeof f&&i===f){n=r;break}}const r=c.subarray(0,n);return a.decode(r)},setter:({view:e,offset:t},n)=>{const r=a.encode(n),i=Math.min(r.length,l);for(let n=0;n<i;n++)e.setUint8(t+n,r[n]);if("number"==typeof f&&i<l)for(let n=i;n<l;n++)e.setUint8(t+n,f)},reactive:({view:e,localOffset:t,baseOffset:n,cacheGetter:r})=>{const i=()=>{const r=t+n();let i=l;for(let t=0;t<l;t++){const n=e.getUint8(r+t);if(c[t]=n,"number"==typeof f&&n===f){i=t;break}}const s=c.subarray(0,i);return a.decode(s)};return r(i),i()},setName:u,setSize:d,setAlign:e=>(o=e,p),setFiller:g,setCoder:e=>(a=e??F,p),freeze:()=>{const e=y();return Object.freeze({isTypeDefinition:t,name:e.name,size:e.size,align:e.align,filler:e.filler,coder:e.coder,getter:e.getter,setter:e.setter,reactive:e.reactive,clone:e.clone})},clone:y};return"number"==typeof n?(d(n),g(r),u(i)):u(n),p},e.defineStruct=function e(i,s){let o,a,d,g=0,y=1,p=new Array,w=new Map,v=new Array,O=new Array;const z=e=>(o=e,I),m=()=>{const e=new Array,t=new Map,n=new Array;let r=1,i=0,s=0;for(const o of O){let f,l;o.padding?(f=o.size,l=Math.max(o.align,1)):(f=o.type.size,l=Math.max(o.align??o.type.align,1),e.push(o.key),t.set(o.key,o),n.push(o));const a=o.offsetStatic;if("number"==typeof a)o.offset=a,s=a+f;else{s+=(l-s%l)%l,o.offset=s,s+=f}r=Math.max(r,l),i=Math.max(i,s)}return y=r,g=i+(r-i%r)%r,p=e,w=t,v=n,I},E=(e,t)=>({key:e,type:t.type,align:t.align,offset:0,offsetStatic:t.offset}),T=(e,t)=>({key:e,size:t.size,align:t.align,offset:0,offsetStatic:t.offset,padding:!0}),h=e=>{const t=[],r=[];for(const[i,s]of Object.entries(e)){if(n(s)){r.push({key:i,type:s,offset:0});continue}let e;if(l(s))e=E(i,s);else{if(!u(s))throw new Error(`[${I.name}] Unknown option type.`);e=T(i,s)}"number"==typeof s.order?t.push({order:s.order,property:e}):r.push(e)}return t.sort((e,t)=>e.order-t.order),O=t.map(e=>e.property).concat(r),m()},b=e=>{if(O.find(t=>t.key===e.key)){const t="symbol"==typeof e.key?`Symbol(${e.key.description||""})`:e.key;throw new Error(`[${I.name}] Repeat adding records with key: ${t}`)}return O.push(e),m()},N=e=>{const t=O.findIndex(t=>t.key===e.key);if(t<0){const t="symbol"==typeof e.key?`Symbol(${e.key.description||""})`:e.key;throw new Error(`[${I.name}] There is no record with key: ${t}`)}return O.splice(t,1,e),m()},S=t=>e((()=>{let e=0;const t={};for(const n of O){let r;const i={align:n.align,offset:n.offsetStatic,order:e++};r=n.padding?c(n.size,i):f(n.type,i),t[n.key]=r}return t})(),t??o).setSize(a).setAlign(d),I={isTypeDefinition:t,get name(){return o??`struct{${p.length}}`},get size(){return Math.max(a??g,0)},get align(){return Math.max(d??y,1)},get keys(){return p},get properties(){return w},get propertyList(){return v},get recordList(){return O},getter:({view:e,offset:t,littleEndian:n})=>{const r={};for(const i of v)r[i.key]=i.type.getter({view:e,offset:t+i.offset,littleEndian:n});return r},setter:({view:e,offset:t,littleEndian:n},r)=>{for(const i of v)i.type.setter({view:e,offset:t+i.offset,littleEndian:n},r[i.key])},reactive:({view:e,littleEndian:t,localOffset:n,baseOffset:i,cacheGetter:s})=>{const o=new Map([[r,()=>I.getter({view:e,offset:i()+n,littleEndian:t})]]),f=new Map,l=new Proxy({},{get:(r,s)=>{let l=f.get(s);if(l)return l();const a=w.get(s);if(a){const r={view:e,littleEndian:t,localOffset:n+a.offset,baseOffset:i,cacheGetter:e=>f.set(a.key,e)};return l=()=>a.type.reactive(r),f.set(a.key,l),l()}return o.get(s)},set:(r,s,o)=>{const f=w.get(s);return!!f&&(f.type.setter({view:e,offset:i()+n+f.offset,littleEndian:t},o),!0)},has:(e,t)=>w.has(t),ownKeys:()=>p,defineProperty:()=>!1,deleteProperty:()=>!1});return s(()=>l),l},setName:z,setSize:e=>(a=e,I),setAlign:e=>(d=e,I),setProperties:h,addProperty:(e,t,n)=>b(E(e,f(t,n))),addPadding:(e,t,n)=>b(T(e,c(t,n))),updateProperty:(e,t,n)=>N(E(e,f(t,n))),updatePadding:(e,t,n)=>N(T(e,c(t,n))),remove:e=>{const t=O.findIndex(t=>t.key===e);if(t<0){const t="symbol"==typeof e?`Symbol(${e.description||""})`:e;throw new Error(`[${I.name}] There is no record with key: ${t}`)}return O.splice(t,1),m()},freeze:()=>{const e=S();return Object.freeze({isTypeDefinition:t,name:e.name,size:e.size,align:e.align,keys:Object.freeze(e.keys),properties:Object.freeze(e.properties),propertyList:Object.freeze(e.propertyList),recordList:Object.freeze(e.recordList),getter:e.getter,setter:e.setter,reactive:e.reactive,clone:e.clone})},clone:S};return"object"==typeof i?(h(i),z(s)):z(i),I},e.get=function(e,t,n,r){return t.getter({view:e,offset:n,littleEndian:r})},e.getArray=function(e,t,n,r,i){const s=new Array(r),o=t.size;for(let f=0;f<r;f++)s[f]=t.getter({view:e,offset:n+o*f,littleEndian:i});return s},e.isPaddingDefinition=u,e.isPropertyDefinition=l,e.isTypeDefinition=n,e.reactive=function(e,t,n,r){const i="function"==typeof n?n:()=>n;return t.reactive({view:e,littleEndian:r,localOffset:0,baseOffset:i,cacheGetter:()=>{}})},e.ref=function(e,t,n,i){const s="function"==typeof n?n:()=>n;let o;return{[r]:()=>({value:t.getter({view:e,offset:s(),littleEndian:i})}),get value(){return o?o():t.reactive({view:e,littleEndian:i,localOffset:0,baseOffset:s,cacheGetter:e=>o=e})},set value(n){t.setter({view:e,offset:s(),littleEndian:i},n)}}},e.set=function(e,t,n,r,i){return t.setter({view:e,offset:n,littleEndian:i},r)},e.setArray=function(e,t,n,r,i){const s=r.length,o=t.size;for(let f=0;f<s;f++)t.setter({view:e,offset:n+o*f,littleEndian:i},r[f])},e.toRaw=i,e.toRef=function(e,t){return{[r]:()=>({value:e[t]}),get value(){return e[t]},set value(n){e[t]=n}}},e.types=P});