Skip to content
This repository has been archived by the owner on May 10, 2020. It is now read-only.

Commit

Permalink
Merge pull request #1 from slowli/factories-in-resolver
Browse files Browse the repository at this point in the history
Enable factories in type resolvers
  • Loading branch information
slowli committed Sep 29, 2017
2 parents 18defaa + cd419db commit 252606d
Show file tree
Hide file tree
Showing 40 changed files with 1,729 additions and 747 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"report-cover": "nyc report",
"report-to-coveralls": "nyc report --reporter=text-lcov | coveralls",
"lint": "eslint --ignore-path .gitignore .",
"compile": "babel src/ -d lib/ && cpy \"**/*.json\" ../lib/ --cwd=src --parents",
"compile": "rimraf lib && babel src/ -d lib/ && cpy \"**/*.json\" ../lib/ --cwd=src --parents",
"prepare": "npm run compile"
},
"author": "Exonum Team <exonum@bitury.com>",
Expand Down Expand Up @@ -42,7 +42,8 @@
"eslint-plugin-promise": "^3.5.0",
"eslint-plugin-standard": "^3.0.1",
"mocha": "^3.5.3",
"nyc": "^11.2.1"
"nyc": "^11.2.1",
"rimraf": "^2.6.2"
},
"nyc": {
"require": [
Expand Down
133 changes: 58 additions & 75 deletions src/Bits256.js
Original file line number Diff line number Diff line change
@@ -1,96 +1,79 @@
import std from './std'

const BIT_LENGTH = 256

const Bits256Base = std.resolve({
struct: [
{ name: 'isTerminal', type: 'Bool' },
{ name: 'bytes', type: { fixedBuffer: BIT_LENGTH / 8 } },
{ name: 'bitLengthByte', type: 'Uint8' }
]
})

export function getBit (buffer, pos) {
const byte = Math.floor(pos / 8)
const bitPos = pos % 8

return (buffer[byte] & (1 << (7 - bitPos))) >> (7 - bitPos)
}

/**
* `Bits256` represents partial and complete (terminal) keys of `MapView`s. The instances
* are comprised of 3 fields:
*
* - `isTerminal` marker signifying whether the the instance corresponds to a complete
* or incomplete key
* - `bytes` is an ordinary 32-byte serialization of the key
* - `bitLengthByte` is the number of bits in the `bytes` that are actually used.
* Other bits are set to zero. For terminal keys, this field is equal to 0
*/
export default class Bits256 extends Bits256Base {
constructor (str) {
if (typeof str !== 'string') {
throw new TypeError('Bits256 can only be initialized with a string')
}
if (!/^[01]*$/.test(str)) {
throw new TypeError('Invalid initializer string; binary string expected')
}
if (str.length > BIT_LENGTH) {
throw new TypeError(`Initializer too long: max ${BIT_LENGTH} bits expected`)
}

super({
isTerminal: str.length === BIT_LENGTH,
bytes: { bin: padWithZeros(str, BIT_LENGTH) },
bitLengthByte: str.length % BIT_LENGTH
})
}

bitLength () {
return this.isTerminal ? BIT_LENGTH : this.bitLengthByte
}
export default function extendBits256 (Bits256Base) {
// Length of the key
const BIT_LENGTH = 256

/**
* Retrieves a bit at a specific position of this key.
* `Bits256` represents partial and complete (terminal) keys of `MapView`s. The instances
* are comprised of 3 fields:
*
* @param {number} pos
* @returns {0 | 1 | void}
* - `isTerminal` marker signifying whether the the instance corresponds to a complete
* or incomplete key
* - `bytes` is an ordinary 32-byte serialization of the key
* - `bitLengthByte` is the number of bits in the `bytes` that are actually used.
* Other bits are set to zero. For terminal keys, this field is equal to 0
*/
bit (pos) {
pos = +pos
if (pos >= this.bitLength() || pos < 0) {
return undefined
return class Bits256 extends Bits256Base {
constructor (str) {
super({
isTerminal: str.length === BIT_LENGTH,
bytes: { bin: padWithZeros(str, BIT_LENGTH) },
bitLengthByte: str.length % BIT_LENGTH
})
}

return getBit(this.bytes, pos)
}
bitLength () {
return this.isTerminal ? BIT_LENGTH : this.bitLengthByte
}

/**
* Returns the result of concatenation of this key with another one. If the length
* of the concatenated key exceeds 256 bits, an error is raised.
*
* @param {Bits256} other
* @returns {Bits256}
*/
append (otherBits) {
const sumLength = this.bitLength() + otherBits.bitLength()
if (sumLength > BIT_LENGTH) {
throw new Error(`Resulting bit slice too long: ${sumLength} (max ${BIT_LENGTH} supported)`)
/**
* Retrieves a bit at a specific position of this key.
*
* @param {number} pos
* @returns {0 | 1 | void}
*/
bit (pos) {
pos = +pos
if (pos >= this.bitLength() || pos < 0) {
return undefined
}

return getBit(this.bytes, pos)
}

// XXX: lazy and inefficient
return new Bits256(this.toJSON() + otherBits.toJSON())
}
/**
* Returns the result of concatenation of this key with another one. If the length
* of the concatenated key exceeds 256 bits, an error is raised.
*
* @param {Bits256} other
* @returns {Bits256}
*/
append (otherBits) {
const sumLength = this.bitLength() + otherBits.bitLength()
if (sumLength > BIT_LENGTH) {
throw new Error(`Resulting bit slice too long: ${sumLength} (max ${BIT_LENGTH} supported)`)
}

// XXX: lazy and inefficient
return new Bits256(this.toJSON() + otherBits.toJSON())
}

toJSON () {
return trimZeros(this.getOriginal('bytes').toString('bin'), this.bitLength())
}
toJSON () {
return trimZeros(this.getOriginal('bytes').toString('bin'), this.bitLength())
}

toString () {
const bits = (this.bitLength() > 8)
? trimZeros(this.getOriginal('bytes').toString('bin'), 8) + '...'
: trimZeros(this.getOriginal('bytes').toString('bin'), this.bitLength())
return `bits(${bits})`
toString () {
const bits = (this.bitLength() > 8)
? trimZeros(this.getOriginal('bytes').toString('bin'), 8) + '...'
: trimZeros(this.getOriginal('bytes').toString('bin'), this.bitLength())
return `bits(${bits})`
}
}
}

Expand Down
18 changes: 0 additions & 18 deletions src/blockchain.js

This file was deleted.

38 changes: 0 additions & 38 deletions src/blockchain.json

This file was deleted.

4 changes: 2 additions & 2 deletions src/crypto.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import sha from 'sha.js'
import nacl from 'tweetnacl'

import fixedBuffer from './lowlevel/fixedBuffer'
import { isExonumObject, rawOrSelf } from './lowlevel/common'
import std from './std'

const { PublicKey } = std
const PublicKey = fixedBuffer(32)

export const hashLength = 32
export const secretKeyLength = nacl.sign.secretKeyLength
Expand Down
6 changes: 3 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import * as crypto from './crypto'
import types from './blockchain'
import std from './std'

// Export standard + blockchain types and resolver
// XXX: Is there any way to do this in ES6 manner?
for (let name in types) {
exports[name] = types[name]
for (let name in std) {
exports[name] = std[name]
}

export { isExonumFactory, isExonumType, isExonumObject } from './lowlevel/common'
Expand Down
42 changes: 9 additions & 33 deletions src/listView.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,6 @@ import { memoize, rawValue, createType } from './lowlevel/common'
import initFactory from './lowlevel/initFactory'
import { hash } from './crypto'

const LIST_VIEW_NODE_DEF = {
name: 'ListViewNode',
union: [
{
name: 'branch',
type: {
struct: [
{ name: 'left', type: 'ListViewNode' },
{ name: 'right', type: 'ListViewNode' }
]
}
},
{ name: 'stub', type: 'ListViewNode' },
{ name: 'hash', type: 'Hash' },
{ name: 'val', type: 'T' }
]
}

/**
* Creates a `ListViewNode<ValType>` for a specific type of values.
*/
function listViewNode (ValType, resolver) {
// XXX: works only with "native" type definitions
return resolver.addNativeType('T', ValType)
.addTypes([
LIST_VIEW_NODE_DEF
]).resolve('ListViewNode')
}

function parseTreeStructure (tree) {
const nodes = []

Expand Down Expand Up @@ -109,14 +80,13 @@ const PROXIED_METHODS = [
]

function listView (ValType, resolver) {
ValType = resolver.resolve(ValType)
const Node = listViewNode(ValType, resolver)
const ProofNode = resolver.resolve({ ListProofNode: ValType })

class ListView extends createType({
name: `ListView<${ValType.inspect()}>`
}) {
constructor (obj) {
const root = Node.from(obj)
const root = ProofNode.from(obj)
const { depth, values } = parseTreeStructure(root)

// Guaranteed to be sorted by ascending `node.pos`
Expand Down Expand Up @@ -147,4 +117,10 @@ function listView (ValType, resolver) {
return ListView
}

export default initFactory(listView, { name: 'listView' })
export default initFactory(listView, {
name: 'listView',

prepare (Type, resolver) {
return resolver.resolve(Type)
}
})
8 changes: 6 additions & 2 deletions src/lowlevel/Bool.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ export default class Bool extends createType({
name: 'Bool'
}) {
constructor (val) {
const raw = isBoolean(val) ? rawValue(val) : !!val
super(raw)
if (isBoolean(val)) val = rawValue(val)

if (typeof val !== 'boolean') {
throw new TypeError(`Cannot construct Bool from ${val}`)
}
super(val)
}

_doSerialize (buffer) {
Expand Down
12 changes: 10 additions & 2 deletions src/lowlevel/Str.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { rawValue, getMethodNames, createType } from './common'

function isStr (maybeStr) {
return maybeStr && typeof rawValue(maybeStr) === 'string'
}

/**
* Calculates string length in bytes.
*
Expand Down Expand Up @@ -62,8 +66,12 @@ export default class Str extends createType({
proxiedMethods: getMethodNames(String.prototype),
name: 'Str'
}) {
constructor (obj) {
super(obj.toString())
constructor (str) {
if (isStr(str)) str = rawValue(str)
if (typeof str !== 'string') {
throw new TypeError(`Cannot construct Str from ${str}`)
}
super(str)
}

_doSerialize (buffer) {
Expand Down
Loading

0 comments on commit 252606d

Please sign in to comment.