301 lines
7.9 KiB
JavaScript
Executable File
301 lines
7.9 KiB
JavaScript
Executable File
/*
|
|
Flags
|
|
0x01 01 watch enabled
|
|
0x02 02 read layer enabled
|
|
0x04 04 write layer enable
|
|
0x08 08 initial state
|
|
0x10 16 changing state
|
|
0x20 32 immediate change
|
|
*/
|
|
(()=>{
|
|
let pipeLine = function(){
|
|
this.reads = [];
|
|
this.writes = [];
|
|
this.read = (fn,pr) => reads.push({fn,pr});
|
|
this.write = (fn,pr) => writes.push({fn,pr});
|
|
this.get = (val) => {
|
|
let fns = reads.sort((a,b) => (a?.pr|0) - (b?.pr|0)),
|
|
real = val;
|
|
for (const { fn } of fns) {
|
|
fn( real, e => real = e );
|
|
};
|
|
return real;
|
|
};
|
|
this.set = () => {
|
|
let fns = writes.sort((a,b) => (a?.pr|0) - (b?.pr|0)),
|
|
real = val;
|
|
for (const { fn } of fns) {
|
|
fn( real, e => real = e );
|
|
};
|
|
return real;
|
|
};
|
|
}
|
|
pipeLine.prototype.read = function(fn,pr){
|
|
this.reads.push({fn,pr})
|
|
}
|
|
pipeLine.prototype.write = function(fn,pr){
|
|
this.writes.writes({fn,pr})
|
|
}
|
|
pipeLine.prototype.get = function(val){
|
|
let fns = this.reads.sort((a,b) => (a?.pr|0) - (b?.pr|0)),
|
|
real = val;
|
|
for (const { fn } of fns) {
|
|
fn( real, e => real = e );
|
|
};
|
|
return real;
|
|
}
|
|
pipeLine.prototype.set = function(val){
|
|
let fns = this.writes.sort((a,b) => (a?.pr|0) - (b?.pr|0)),
|
|
real = val;
|
|
for (const { fn } of fns) {
|
|
fn( real, e => real = e );
|
|
};
|
|
return real;
|
|
}
|
|
function é(defaultValue)
|
|
{
|
|
if(this instanceof é)
|
|
{
|
|
this.value = é.extract(defaultValue);
|
|
this.version = 0;
|
|
this.effects = [];
|
|
this.piping = new pipeLine();
|
|
this.flag = 8;
|
|
}else{
|
|
return new é(defaultValue)
|
|
}
|
|
}
|
|
é.fingerPrint = Symbol("wire");
|
|
é.isWire = n => n?.fp == é.fingerPrint;
|
|
é.extract = (e,v) => {
|
|
if(typeof e=='function')
|
|
{
|
|
return é.freeze(e(v))
|
|
}else{
|
|
return é.freeze(e);
|
|
}
|
|
};
|
|
é.freeze = a => {
|
|
if(Object.isFrozen(a))
|
|
{
|
|
return a;
|
|
}
|
|
switch(typeof a)
|
|
{
|
|
case "object":{
|
|
if(Array.isArray(a))
|
|
{
|
|
let k = [...a];
|
|
for (let name = 0; name < k.length; name++) {
|
|
let value = k[name];
|
|
if(typeof value == "object")
|
|
{
|
|
k[name]=é.freeze(value);
|
|
}
|
|
};
|
|
Object.freeze(k);
|
|
return k;
|
|
}else{
|
|
let k = Object.assign({}, a);
|
|
for (const [name, value] of Object.entries(k)) {
|
|
if(typeof value == "object")
|
|
{
|
|
k[name]=é.freeze(value);
|
|
}
|
|
};
|
|
Object.freeze(k);
|
|
return k;
|
|
}
|
|
}
|
|
default: return a;
|
|
};
|
|
};
|
|
é.isSame = (a,b) => !é.diff(a,b);
|
|
é.watch = (fn, assoc) => {
|
|
for (const wireVar of assoc)
|
|
{
|
|
if(é.isWire(wireVar))
|
|
{
|
|
wireVar.watch(fn);
|
|
}
|
|
}
|
|
};
|
|
é.diff = (a,b,c) => {
|
|
let cursoryDiffResult = cDiff(a,b);
|
|
if(cursoryDiffResult == cDiff.adiff)
|
|
{
|
|
return adiff(a,b,c||[])
|
|
}else{
|
|
return cursoryDiffResult == cDiff.some ? false : true;
|
|
}
|
|
}
|
|
const adiff = (a,b,c) => {
|
|
if(c.includes(a) && c.includes(b))
|
|
{
|
|
console.error("Circular object detected !")
|
|
return cObjectDiff(a,b);
|
|
}
|
|
let typea = a instanceof Array ? 0 : a.byteLength ? 1 : 2;
|
|
let typeb = b instanceof Array ? 0 : b.byteLength ? 1 : 2;
|
|
if(typea != typeb)
|
|
{
|
|
return true;
|
|
}
|
|
if(typea==0)
|
|
{
|
|
if(a.length != b.length)
|
|
{
|
|
return true
|
|
}
|
|
for(let k = 0; k < a.length; k++)
|
|
{
|
|
if(é.diff(a[k], b[k]))
|
|
{
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
if(a instanceof Object)
|
|
{
|
|
if(Object.keys(a).length != Object.keys(b).length)
|
|
{
|
|
return true
|
|
}
|
|
c.push(a);
|
|
c.push(b);
|
|
for (const key in a)
|
|
{
|
|
if (Object.hasOwnProperty.call(a, key))
|
|
{
|
|
if(é.diff(a[key], b[key], c))
|
|
{
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
}
|
|
const cArrDiff = (a,b) => {
|
|
return a.length != b.length || !a.every((v,i) => a[i] === v)
|
|
};
|
|
const cObjectDiff = (a,b) => {
|
|
return cArrDiff(
|
|
Object.keys(a),
|
|
Object.keys(b)
|
|
);
|
|
};
|
|
const cDiff = (a,b) => {
|
|
switch(typeof a)
|
|
{
|
|
case "undefined":
|
|
case "function":{
|
|
return typeof a == typeof b ? cDiff.some : cDiff.different
|
|
}
|
|
case "symbol":
|
|
case "bigint":
|
|
case "boolean":
|
|
case "number":
|
|
case "string":{
|
|
return a === b ? cDiff.some : cDiff.different;
|
|
}
|
|
case "object":{
|
|
return cDiff.adiff;
|
|
}
|
|
};
|
|
}
|
|
cDiff.adiff = -1;
|
|
cDiff.some = 0;
|
|
cDiff.different = 1;
|
|
|
|
é.prototype.fp = é.fingerPrint;
|
|
é.prototype.diff = é.diff;
|
|
é.prototype.get = function(){
|
|
if(this.flag & 2)
|
|
{
|
|
return this.piping.get(this.value)
|
|
}else{
|
|
return this.value
|
|
}
|
|
};
|
|
é.prototype.set = function(newValue){
|
|
if(this.flag & 16)
|
|
{
|
|
return;
|
|
}
|
|
newValue = é.extract(newValue, this.value);
|
|
if(this.flag & 4)
|
|
{
|
|
newValue = this.piping.set(newValue)
|
|
};
|
|
if(this.diff(newValue,this.value))
|
|
{
|
|
this.flag = this.flag | 16;
|
|
if(this.flag & 1)
|
|
{
|
|
schedule((()=>{
|
|
this.effects.filter(e => e.o).forEach(k => k())
|
|
}));
|
|
}
|
|
this.value = newValue;
|
|
this.version++;
|
|
if(this.flag & 1)
|
|
{
|
|
schedule((()=>{
|
|
this.effects.forEach(e => e.f());
|
|
}));
|
|
}
|
|
this.flag = this.flag ^ 16;
|
|
}
|
|
};
|
|
const schedule = function(fn){
|
|
schedule.jobs.push(fn)
|
|
if(!schedule.executing)
|
|
{
|
|
requestAnimationFrame(()=>{
|
|
for (const fn of schedule.jobs) {
|
|
try{
|
|
fn()
|
|
}catch(e){
|
|
console.error(e)
|
|
}
|
|
};
|
|
schedule.jobs=[];
|
|
})
|
|
}
|
|
};
|
|
schedule.executing = false;
|
|
schedule.jobs = [];
|
|
é.prototype.watch = function(fn){
|
|
this.flag = this.flag | 1;
|
|
let k = {
|
|
f:fn,
|
|
o:undefined
|
|
};
|
|
requestAnimationFrame(()=> {
|
|
k.o = fn();
|
|
})
|
|
this.effects.push(k);
|
|
};
|
|
é.prototype.getVersion = function(){
|
|
return this.version;
|
|
}
|
|
é.prototype.equalTo = function(value){
|
|
return é.isSame(value, this.value)
|
|
}
|
|
é.prototype.readLayer = function(value){
|
|
this.flag = this.flag | 2;
|
|
this.piping.read(a,b)
|
|
}
|
|
é.prototype.writeLayer = function(value){
|
|
this.flag = this.flag | 4;
|
|
this.piping.write(a,b)
|
|
}
|
|
try{
|
|
module.exports = é;
|
|
}catch{
|
|
window.é = é;
|
|
}
|
|
})();
|