urbit-ob

JavaScript utilities for phonemic base wrangling.
Log | Files | Refs | README

commit aa2867a7159d7193898b844ebe6b16a6cf35ea32
parent d9ab0c6d127898112f188f0bb5e9b3c3a29c7ccb
Author: Jared Tobin <jared@jtobin.io>
Date:   Tue, 12 Mar 2019 20:56:28 +1300

Add various vatp-casting functions.

Diffstat:
Msrc/internal/co.js | 147++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mtest/co.test.js | 39++++++++++++++++++++++++++++++++++++++-
2 files changed, 184 insertions(+), 2 deletions(-)

diff --git a/src/internal/co.js b/src/internal/co.js @@ -126,6 +126,15 @@ const hex2patp = (hex) => patp(new BN(hex, 'hex')) /** + * Convert a hex-encoded string to a @p-encoded string. + * + * @param {String} hex + * @return {String} + */ +const hex2vatp = (hex) => + vatp(new BN(hex, 'hex')) + +/** * Convert a Buffer to a @p-encoded string. * * @param {Buffer} buf @@ -135,6 +144,15 @@ const buf2patp = (buf) => hex2patp(buf.toString('hex')) /** + * Convert a Buffer to a @p-encoded string. + * + * @param {Buffer} buf + * @return {String} + */ +const buf2vatp = (buf) => + hex2vatp(buf.toString('hex')) + +/** * Convert a @p-encoded string to a hex-encoded string. * * @param {String} name @p @@ -163,6 +181,34 @@ const patp2hex = (name) => { } /** + * Convert a @p-encoded string to a hex-encoded string. + * + * @param {String} name @p + * @return {String} + */ +const vatp2hex = (name) => { + if (isValidPat(name) === false) { + throw new Error('patp2hex: not a valid @p') + } + const syls = patp2syls(name) + + const syl2bin = idx => + idx.toString(2).padStart(8, '0') + + const addr = lodash.reduce(syls, (acc, syl, idx) => + idx % 2 !== 0 || syls.length === 1 + ? acc + syl2bin(suffixes.indexOf(syl)) + : acc + syl2bin(prefixes.indexOf(syl)), + '') + + const bn = new BN(addr, 2) + const hex = ob.fynd(bn).toString('hex') + return hex.length % 2 !== 0 + ? hex.padStart(hex.length + 1, '0') + : hex +} + +/** * Convert a @p-encoded string to a Buffer. * * @param {String} name @@ -172,6 +218,15 @@ const patp2buf = name => Buffer.from(patp2hex(name), 'hex') /** + * Convert a @p-encoded string to a Buffer. + * + * @param {String} name + * @return {Buffer} + */ +const vatp2buf = name => + Buffer.from(vatp2hex(name), 'hex') + +/** * Convert a @p-encoded string to a bignum. * * @param {String} name @p @@ -181,6 +236,15 @@ const patp2bn = name => new BN(patp2hex(name), 'hex') /** + * Convert a @p-encoded string to a bignum. + * + * @param {String} name @p + * @return {BN} + */ +const vatp2bn = name => + new BN(vatp2hex(name), 'hex') + +/** * Convert a @p-encoded string to a decimal-encoded string. * * @param {String} name @p @@ -197,6 +261,22 @@ const patp2dec = name => { } /** + * Convert a @p-encoded string to a decimal-encoded string. + * + * @param {String} name @p + * @return {String} + */ +const vatp2dec = name => { + let bn + try { + bn = vatp2bn(name) + } catch(_) { + throw new Error('patp2dec: not a valid @p') + } + return bn.toString() +} + +/** * Convert a number to a @q-encoded string. * * @param {String, Number, BN} arg @@ -349,6 +429,32 @@ const clan = who => { } /** + * Determine the ship class of a @p value. + * + * @param {String} @p + * @return {String} + */ +const clen = who => { + let name + try { + name = vatp2bn(who) + } catch(_) { + throw new Error('clan: not a valid @p') + } + + const wid = met(three, name) + return wid.lte(one) + ? 'galaxy' + : wid.eq(two) + ? 'star' + : wid.lte(four) + ? 'planet' + : wid.lte(new BN(8)) + ? 'moon' + : 'comet' +} + +/** * Determine the parent of a @p value. * * @param {String} @p @@ -383,6 +489,40 @@ const sein = name => { } /** + * Determine the parent of a @p value. + * + * @param {String} @p + * @return {String} + */ +const sign = name => { + let who + try { + who = vatp2bn(name) + } catch(_) { + throw new Error('sein: not a valid @p') + } + + let mir + try { + mir = clen(name) + } catch(_) { + throw new Error('sein: not a valid @p') + } + + const res = + mir === 'galaxy' + ? who + : mir === 'star' + ? end(three, one, who) + : mir === 'planet' + ? end(four, one, who) + : mir === 'moon' + ? end(five, one, who) + : zero + return vatp(res) +} + +/** * Weakly check if a string is a valid @p or @q value. * * This is, at present, a pretty weak sanity check. It doesn't confirm the @@ -508,5 +648,10 @@ module.exports = { isValidPatq: isValidPat, // reserving for diff impls in future isValidPatp: isValidPat, - vatp + vatp, + vatp2hex, + hex2vatp, + vatp2dec, + sign, + clen } diff --git a/test/co.test.js b/test/co.test.js @@ -6,12 +6,18 @@ const { patp2hex, hex2patp, patp2dec, + vatp, + vatp2hex, + hex2vatp, + vatp2dec, patq, patq2hex, hex2patq, patq2dec, clan, sein, + clen, + sign, eqPatq, isValidPatq, isValidPatp @@ -22,12 +28,17 @@ const patps = jsc.uint32.smap( pp => parseInt(patp2dec(pp)) ) +const vatps = jsc.uint32.smap( + num => vatp(num), + pp => parseInt(vatp2dec(pp)) +) + const patqs = jsc.uint32.smap( num => patq(num), pq => parseInt(patq2dec(pq)) ) -describe('patp, etc.', () => { +describe('patp, vatp, etc.', () => { it('patp2dec matches expected reference values', () => { expect(patp2dec('~zod')).to.equal('0') expect(patp2dec('~lex')).to.equal('200') @@ -75,6 +86,19 @@ describe('patp, etc.', () => { jsc.assert(iso1) }) + it('vatp and vatp2dec are inverses', () => { + let iso0 = jsc.forall(jsc.uint32, num => + parseInt(vatp2dec(vatp(num))) === num + ) + + let iso1 = jsc.forall(vatps, vp => + vatp(vatp2dec(vp)) === vp + ) + + jsc.assert(iso0, { tests: 10000 }) + jsc.assert(iso1, { tests: 10000 }) + }) + it('patp2hex and hex2patp are inverses', () => { let iso0 = jsc.forall(jsc.uint32, num => parseInt(patp2hex(hex2patp(num.toString(16))), 16) === num @@ -87,6 +111,19 @@ describe('patp, etc.', () => { jsc.assert(iso0) jsc.assert(iso1) }) + + it('vatp2hex and hex2vatp are inverses', () => { + let iso0 = jsc.forall(jsc.uint32, num => + parseInt(vatp2hex(hex2vatp(num.toString(16))), 16) === num + ) + + let iso1 = jsc.forall(vatps, vp => + hex2vatp(vatp2hex(vp)) === vp + ) + + jsc.assert(iso0) + jsc.assert(iso1) + }) }) describe('patq, etc.', () => {