wirejs/wire.js

301 lines
8.0 KiB
JavaScript
Raw Normal View History

2023-05-21 21:32:29 +03:00
/*
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 = [];
2023-11-10 21:37:49 +03:00
this.read = (fn,pr) => this.reads.push({fn,pr});
this.write = (fn,pr) => this.writes.push({fn,pr});
2023-05-21 21:32:29 +03:00
this.get = (val) => {
2023-11-10 21:37:49 +03:00
let fns = this.reads.sort((a,b) => (a?.pr|0) - (b?.pr|0)),
2023-05-21 21:32:29 +03:00
real = val;
for (const { fn } of fns) {
fn( real, e => real = e );
};
return real;
};
2023-11-10 21:37:49 +03:00
this.set = (val) => {
let fns = this.writes.sort((a,b) => (a?.pr|0) - (b?.pr|0)),
2023-05-21 21:32:29 +03:00
real = val;
for (const { fn } of fns) {
fn( real, e => real = e );
};
return real;
2023-05-17 23:39:01 +03:00
};
}
2023-05-21 21:32:29 +03:00
pipeLine.prototype.read = function(fn,pr){
this.reads.push({fn,pr})
2023-05-17 23:39:01 +03:00
}
2023-05-21 21:32:29 +03:00
pipeLine.prototype.write = function(fn,pr){
this.writes.writes({fn,pr})
2023-05-17 23:39:01 +03:00
}
2023-05-21 21:32:29 +03:00
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;
2023-05-17 23:39:01 +03:00
}
2023-05-21 21:32:29 +03:00
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;
2023-05-17 23:39:01 +03:00
}
2023-05-21 21:32:29 +03:00
function é(defaultValue)
2023-05-17 23:39:01 +03:00
{
2023-05-21 21:32:29 +03:00
if(this instanceof é)
2023-05-17 23:39:01 +03:00
{
2023-05-21 21:32:29 +03:00
this.value = é.extract(defaultValue);
this.version = 0;
this.effects = [];
this.piping = new pipeLine();
this.flag = 8;
}else{
return new é(defaultValue)
2023-05-17 23:39:01 +03:00
}
2023-05-21 21:32:29 +03:00
}
é.fingerPrint = Symbol("wire");
é.isWire = n => n?.fp == é.fingerPrint;
2023-06-18 15:09:09 +03:00
é.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":{
2023-06-18 15:25:43 +03:00
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;
}
2023-06-18 15:09:09 +03:00
}
default: return a;
};
};
2023-05-21 21:32:29 +03:00
é.isSame = (a,b) => !é.diff(a,b);
é.watch = (fn, assoc) => {
for (const wireVar of assoc)
2023-05-17 23:39:01 +03:00
{
2023-05-21 21:32:29 +03:00
if(é.isWire(wireVar))
2023-05-17 23:39:01 +03:00
{
2023-05-21 21:32:29 +03:00
wireVar.watch(fn);
2023-05-17 23:39:01 +03:00
}
}
2023-05-21 21:32:29 +03:00
};
é.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;
}
2023-05-17 23:39:01 +03:00
}
2023-05-21 21:32:29 +03:00
const adiff = (a,b,c) => {
if(c.includes(a) && c.includes(b))
2023-05-17 23:39:01 +03:00
{
2023-05-21 21:32:29 +03:00
console.error("Circular object detected !")
return cObjectDiff(a,b);
2023-05-17 23:39:01 +03:00
}
2023-05-21 21:32:29 +03:00
let typea = a instanceof Array ? 0 : a.byteLength ? 1 : 2;
let typeb = b instanceof Array ? 0 : b.byteLength ? 1 : 2;
if(typea != typeb)
2023-05-17 23:39:01 +03:00
{
2023-05-21 21:32:29 +03:00
return true;
}
if(typea==0)
{
if(a.length != b.length)
{
return true
}
for(let k = 0; k < a.length; k++)
2023-05-17 23:39:01 +03:00
{
2023-05-21 21:32:29 +03:00
if(é.diff(a[k], b[k]))
2023-05-17 23:39:01 +03:00
{
return true
}
}
2023-05-21 21:32:29 +03:00
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
2023-05-17 23:39:01 +03:00
}
}
2023-05-21 21:32:29 +03:00
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":{
2023-06-18 15:09:09 +03:00
return typeof a == typeof b ? cDiff.some : cDiff.different
2023-05-21 21:32:29 +03:00
}
case "symbol":
case "bigint":
case "boolean":
case "number":
case "string":{
2023-06-18 15:09:09 +03:00
return a === b ? cDiff.some : cDiff.different;
2023-05-21 21:32:29 +03:00
}
case "object":{
2023-06-18 15:09:09 +03:00
return cDiff.adiff;
2023-05-21 21:32:29 +03:00
}
};
}
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
2023-05-17 23:39:01 +03:00
}
2023-05-21 21:32:29 +03:00
};
é.prototype.set = function(newValue){
if(this.flag & 16)
{
return;
2023-05-17 23:39:01 +03:00
}
2023-05-21 21:32:29 +03:00
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((()=>{
2023-06-18 15:14:12 +03:00
this.effects.forEach(e => e.f());
2023-05-21 21:32:29 +03:00
}));
}
this.flag = this.flag ^ 16;
2023-05-17 23:39:01 +03:00
}
};
2023-05-21 21:32:29 +03:00
const schedule = function(fn){
schedule.jobs.push(fn)
2023-06-18 15:09:09 +03:00
if(!schedule.executing)
2023-05-21 21:32:29 +03:00
{
requestAnimationFrame(()=>{
for (const fn of schedule.jobs) {
try{
fn()
}catch(e){
console.error(e)
}
2023-06-18 15:09:09 +03:00
};
schedule.jobs=[];
2023-05-21 21:32:29 +03:00
})
}
2023-05-17 23:39:01 +03:00
};
2023-05-21 21:32:29 +03:00
schedule.executing = false;
schedule.jobs = [];
é.prototype.watch = function(fn){
this.flag = this.flag | 1;
let k = {
f:fn,
o:undefined
2023-05-17 23:39:01 +03:00
};
2023-05-21 21:32:29 +03:00
requestAnimationFrame(()=> {
k.o = fn();
})
this.effects.push(k);
2023-05-17 23:39:01 +03:00
};
2023-05-21 21:32:29 +03:00
é.prototype.getVersion = function(){
return this.version;
}
é.prototype.equalTo = function(value){
return é.isSame(value, this.value)
}
2023-11-10 21:37:49 +03:00
é.prototype.readLayer = function(fn,priority){
2023-05-21 21:32:29 +03:00
this.flag = this.flag | 2;
2023-11-10 21:37:49 +03:00
this.piping.read(fn,priority)
2023-05-21 21:32:29 +03:00
}
2023-11-10 21:37:49 +03:00
é.prototype.writeLayer = function(fn,priority){
2023-05-21 21:32:29 +03:00
this.flag = this.flag | 4;
2023-11-10 21:37:49 +03:00
this.piping.write(fn,priority)
2023-05-21 21:32:29 +03:00
}
try{
module.exports = é;
}catch{
window.é = é;
}
})();