Select Git revision
threadpi.cpp
-
Neil Gershenfeld authoredNeil Gershenfeld authored
typeset.js 13.07 KiB
// typeset: functional types -> bytes for js -> embedded sys
// bless up @ modern js https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays
let tsdebug = false
// oy,
const checkKey = (type, arr, start) => {
if (arr[start] !== type.key) throw new Error(`mismatched key on phy read: for ${type.name}, find ${arr[start]} instead of ${type.key} ... at ${start} index`, arr)
}
const checkBoolean = (value) => {
if (typeof value !== 'boolean') throw new Error('cannot cast non-boolean to bool at phy')
}
const checkNumber = (value) => {
if (typeof value !== 'number') throw new Error(`for uint8 cannot cast non-number into physical world "${value}", ${typeof value}`)
}
const checkString = (value) => {
if (typeof value !== 'string') throw new Error(`cannot cast non-string to string at phy! "${value}", "${typeof value}"`)
}
const checkArray = (thing) => {
if (!Array.isArray(thing)) throw new Error('this thing is not an array!')
}
const checkUnsigned = (value, bits) => {
if(value > Math.pow(2, bits)) throw new Error('value out of byte bounds')
}
const checkSigned = (value, bits) => {
let comparator = Math.pow(2, bits-1)
if(value > comparator || value < -comparator) throw new Error('value out of byte bounds')
}
const findPhy = (type) => {
let phy = TSET.find((cand) => {
return cand.name === type
})
if (phy === undefined) throw new Error(`could not find phy for datatype: ${type}`)
return phy
}
const TSET = [{
name: 'boolean',
key: 32,
write: function(value) {
checkBoolean(value)
let rtarr = [this.key]
if (value) {
rtarr.push(1)
} else {
rtarr.push(0)
}
return rtarr
},
read: function(arr, start) {
checkKey(this, arr, start)
let item
if (arr[start + 1] === 1) {
item = true
} else if (arr[start + 1] === 0) {
item = false
} else {
throw new Error(`non std boolean byte, ${arr[start+1]}`)
}
return {
item: item,
increment: 2
}
}
}, // booleanArray: 33,
{
name: 'byte',
key: 34,
write: function(value) {
checkNumber(value)
// truncate or error ?
checkUnsigned(value, 8)
return [this.key, value]
},
read: function(arr, start) {
checkKey(this, arr, start)
return {
item: arr[start + 1],
increment: 2
}
}
},
{
name: 'byteArray',
key: 35,
write: function(value) {
// assume justice has already been served,
checkArray(value)
let rtarr = writeLenBytes(value.length).concat(value)
rtarr.unshift(this.key)
if(tsdebug) console.log('byteArray sanity check:', value, 'written as:', rtarr)
return rtarr
},
read: function(arr, start) {
checkKey(this, arr, start)
let lb = readLenBytes(arr, start + 1)
// okey
let narr = new Array()
for(let i = 0; i < lb.len; i++){
narr.push(arr[start + 1 + lb.numBytes + i])
}
return {
item: narr,
increment: lb.len + lb.numBytes + 1
}
}
}, // char 36, string 37,
{
name: 'string',
key: 37,
write: function(str) {
checkString(str)
let rtarr = new Array()
for (let i = 0; i < str.length; i++) {
rtarr.push(str.charCodeAt(i))
}
// length bytes are 7-bit 'msb for continue' numbers ...
// the -1 because we are not counting the length of the key
let lb = writeLenBytes(rtarr.length)
rtarr = lb.concat(rtarr)
rtarr.unshift(this.key)
return rtarr
},
read: function(arr, start) {
checkKey(this, arr, start)
let lb = readLenBytes(arr, start + 1)
//console.log('lenbytes', lb)
let str = new String()
for (let i = 0; i < lb.len; i++) {
str += String.fromCharCode(arr[start + 1 + lb.numBytes + i])
}
return {
item: str,
increment: lb.len + lb.numBytes + 1
}
}
},
{
name: 'uint8',
key: 38,
write: function(value) {
checkNumber(value)
checkUnsigned(value, 8)
if (value > 255 || value < 0) throw new Error('num too large to represent with cast type, will contencate')
// dont' need to type-buffer this,
let rtarr = [this.key, value]
return rtarr
},
read: function(arr, start) {
// assume we're reading out of an array
// start[] should === key
if (arr[start] !== this.key) throw new Error(`mismatched key on phy read: ${arr[start]}, ${this.key}`)
if (arr[start + 1] > 255 || arr[start + 1] < 0) throw new Error('whaky read-in on uint8')
return {
item: arr[start + 1],
increment: 2
}
}
}, // uint8Array 39
{
name: 'uint16',
key: 40,
write: function(value) {
if (typeof value !== 'number') throw new Error(`cannot cast non-number into physical world "${value}"`)
if (value > 65536 || value < 0) throw new Error('num too large to represent with cast type, will contencate')
let tparr = new Uint16Array(1)
tparr[0] = value
let btarr = new Uint8Array(tparr.buffer)
//place
let rtarr = Array.from(btarr)
rtarr.unshift(this.key)
return rtarr
},
read: function(arr, start) {
// assume we're reading out of an array
// start[] should === key
if (arr[start] !== this.key) throw new Error(`mismatched key on phy read: ${arr[start]}, ${this.key}`)
let rdarr = arr.slice(start + 1, start + 3)
let btarr = Uint8Array.from(rdarr)
if (tsdebug) console.log('bytes on read of uint16 (little eadian)', btarr)
// now make uint32 view on this ...
let vlarr = new Uint16Array(btarr.buffer)
if (tsdebug) console.log('vlarr', vlarr)
return {
item: vlarr[0],
increment: 3
}
}
}, // uint16 array 41
{
name: 'uint32',
key: 42,
write: function(value) {
if (typeof value !== 'number') throw new Error('cannot cast non-number into physical world')
if (value > 4294967296) throw new Error('num too large to represent with cast type, will contencate')
let tparr = new Uint32Array(1)
tparr[0] = value
let btarr = new Uint8Array(tparr.buffer)
//place
let rtarr = Array.from(btarr)
rtarr.unshift(this.key)
console.log("UINT32 WRITES ARR: ", rtarr, "FOR: ", value)
return rtarr
},
read: function(arr, start) {
// assume we're reading out of an array
// start[] should === key
if (arr[start] !== this.key) throw new Error(`mismatched key on phy read: ${arr[start]}, ${this.key}`)
let rdarr = arr.slice(start + 1, start + 5)
let btarr = Uint8Array.from(rdarr)
if (tsdebug) console.log('bts on read of uint32', btarr)
// now make uint32 view on this ...
let vlarr = new Uint32Array(btarr.buffer)
console.log("UINT32 READ ARR: ", vlarr[0], "FROM: ", btarr)
if (tsdebug) console.log('vlarr', vlarr)
return {
item: vlarr[0],
increment: 5
}
}
}, // uint32array 43,
/*
uint64 44, uint64array 45,
int8 46, int8array 47,
int16 48, int16array 49,
int32 50, int32array 50,
*/
{
name: 'int32',
key: 50,
write: function(value) {
if (typeof value !== 'number') throw new Error('cannot cast non-number into physical world')
let tparr = new Int32Array(1)
tparr[0] = value
let btarr = new Uint8Array(tparr.buffer)
//place
let rtarr = Array.from(btarr)
rtarr.unshift(this.key)
console.warning('not sure about int -> uint8 byte casts yet')
console.log("INT32 WRITES ARR: ", rtarr, "FOR: ", value)
return rtarr
},
read: function(arr, start) {
// assume we're reading out of an array
// start[] should === key
if (arr[start] !== this.key) throw new Error(`mismatched key on phy read: ${arr[start]}, ${this.key}`)
let rdarr = arr.slice(start + 1, start + 5)
let btarr = Uint8Array.from(rdarr)
if (tsdebug) console.log('bts on read of uint32', btarr)
// now make uint32 view on this ...
let vlarr = new Int32Array(btarr.buffer)
console.warning('not sure about int -> uint8 byte casts yet')
console.log("UINT32 READ ARR: ", vlarr[0], "FROM: ", btarr)
if (tsdebug) console.log('vlarr', vlarr)
return {
item: vlarr[0],
increment: 5
}
}
},
/*
int64 52, int64array 53,
float32 54, float32array 55,
float64 56, float64array 57 (these are === javascript 'numbers') ... how to alias ?
*/
{
name: 'number',
key: 56,
write: function(value) {
if (typeof value !== 'number') throw new Error('cannot cast non-number into physical world')
let tparr = new Float64Array(1)
tparr[0] = value
let btarr = new Uint8Array(tparr.buffer)
// place
let rtarr = Array.from(btarr)
rtarr.unshift(this.key)
return rtarr
},
read: function(arr, start) {
if (arr[start] !== this.key) throw new Error(`mismatched key on phy read: ${arr[start]}, ${this.key}`)
let rdarr = arr.slice(start + 1, start + 9)
let btarr = Uint8Array.from(rdarr)
if (tsdebug) console.log('bts on read of float64', btarr)
let vlarr = new Float64Array(btarr.buffer)
if (tsdebug) console.log('vlarr', vlarr)
return {
item: vlarr[0],
increment: 9
}
}
}
// etc
] // end TSET
let intTypes = [
'uint8', 'uint16', 'uint32', 'uint64', 'int8', 'int16', 'int32', 'int64'
]
const isIntType = (type) => {
for(let t of intTypes){
if(type == t) return true
}
return false
}
const writeLenBytes = (len) => {
// return array of len bytes for this number
let bts = new Array()
if(len > 65536){
throw new Error('cannot write length bytes for len > 2^16')
} else {
// this is little eadian ... right ?
bts.push(len & 255);
bts.push((len >> 8) & 255);
}
// here to check,
if(len > 255){
console.log(`LEN > 255: writes len bytes `, bts[0], bts[1], 'for', len)
}
return bts
}
const readLenBytes = (arr, start) => {
// need 2 know how many to increment as well,
let len = (arr[start + 1] << 8) | arr[start]
// still interested in this,
if(len > 255){
console.log(`LEN > 255: reads len bytes `, arr[start], arr[start+1], 'for len', len)
}
return {
len: len,
numBytes: 2
}
}
// heavy mixin of functional programming
const MSGS = {
writeTo: function(bytes, thing, type, debug) {
let phy = findPhy(type)
let block = phy.write(thing)
if (debug) console.log(`writing for type ${type} and thing '${thing}' the following block of bytes`, block)
// write-in to msg like this
block.forEach((byte) => {
bytes.push(byte)
})
},
readFrom: function(bytes, place, type) {
let phy = findPhy(type)
// check that type exists at place, rip it oot and return it
return phy.read(bytes, place)
},
readListFrom: function(bytes, place, type) {
// using this where I expect a lit of values, i.e. the addLink(str,str,str,str) arguments,
// plucks thru, continuing to pull values as long as the next in the serialized list is of
// the right type
let phy = findPhy(type)
// the list of items,
let list = new Array()
while (place < bytes.length) {
let res = phy.read(bytes, place)
list.push(res.item)
place += res.increment
if (bytes[place] !== phy.key) break
// this could throw us into infinite loops, so
if (res.increment < 1) throw new Error('dangerous increment while reading list')
}
if (list.length < 1) throw new Error('reading list, found no items...')
if (tsdebug) console.log('read list as', list)
return list
}
}
// typically: call, response expected
// manager keys
const MK = {
// bzzt
ERR: 254, // (str) message
// heartbeats, wakeup
HELLO: 231, // (eom)
// request a top-level description
QUERY: 251, // (eom)
BRIEF: 250, // (str) name of interpreter, # hunks, # links (and then begin firing list back)
// please show what is available
REQLISTAVAIL: 249, // (eom)
LISTOFAVAIL: 248, // (list)(str) names 'dirs/like/this' (includes programs ?) (this might be multiple packets?)
// business ... we should be able to centralize all control w/i view.js if we can write these
REQADDHUNK: 247, // (str) name
REQNAMECHANGE: 246,
HUNKALIVE: 245, // (hunkdescription): name, id, inputlist, outputlist, statelist
HUNKREPLACE: 244,
REQSTATECHANGE: 243,
HUNKSTATECHANGE: 242,
REQRMHUNK: 241, // (str) id
HUNKREMOVED: 240, // (str) id
REQADDLINK: 239, // (str) id, (str) outname, (str) id, (str) inname
LINKALIVE: 238, // (str) id, (str) outname, (str) id, (str) inname
REQRMLINK: 237, // (str) id, (str) outname, (str) id, (str) inname
LINKREMOVED: 236, // (str) id, (str) outname, (str) id, (str) inname
// to id,
MSGID: 235
}
// hunk description keys,
const HK = {
NAME: 253,
TYPE: 252,
IND: 251,
DESCR: 250,
INPUT: 249,
OUTPUT: 247,
CONNECTIONS: 246,
CONNECTION: 245,
STATE: 244,
}
// link keys,
const LK = {
ACK: 254,
HELLO: 253 // ~ binary solo ~
}
// should write out as list of pairs ?
// or write fn to do key(stringtype)
export {
TSET,
MK, // manager keys
HK, // hunk def keys
LK, // link keys
MSGS,
isIntType
}