Skip to content

Commit

Permalink
feat(random): add randomBytesFrom(), update UUID fns
Browse files Browse the repository at this point in the history
- add thi.ng/hex dependency
- update uuidv4Bytes() to take opt IRandom arg
- refactor/optimize uuid()
- add tests
  • Loading branch information
postspectacular committed Nov 13, 2020
1 parent 1c2f331 commit b31c872
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 14 deletions.
5 changes: 4 additions & 1 deletion packages/random/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@
},
"dependencies": {
"@thi.ng/api": "^6.13.1",
"@thi.ng/checks": "^2.7.9"
"@thi.ng/checks": "^2.7.9",
"@thi.ng/hex": "^0.0.1"
},
"files": [
"*.js",
Expand All @@ -59,8 +60,10 @@
],
"keywords": [
"binary",
"datastructure",
"generator",
"random",
"typedarray",
"typescript"
],
"publishConfig": {
Expand Down
27 changes: 18 additions & 9 deletions packages/random/src/random-bytes.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
import { hasCrypto } from "@thi.ng/checks";
import type { IRandom } from "./api";
import { SYSTEM } from "./system";

/**
* Fills given byte array with random values sourced from given {@link IRandom}
* instance.
*
* @param rnd -
* @param buf -
*/
export const randomBytesFrom = (rnd: IRandom, buf: Uint8Array) => {
for (let i = buf.length; --i >= 0; ) {
buf[i] = rnd.int() & 0xff;
}
return buf;
};

/**
* Fills given byte array with random values. Wrapper for
* `crypto.getRandomValues()` with automatic fallback to using
* `Math.random` if platform doesn't provide global crypto instance.
* `crypto.getRandomValues()` with automatic fallback to using `Math.random` if
* platform doesn't provide global crypto instance.
*/
export const randomBytes = hasCrypto()
? (buf: Uint8Array) => window.crypto.getRandomValues(buf)
: (buf: Uint8Array) => {
const n = buf.length;
for (let i = 0; i < n; i++) {
buf[i] = SYSTEM.int() & 0xff;
}
return buf;
};
: (buf: Uint8Array) => randomBytesFrom(SYSTEM, buf);
35 changes: 31 additions & 4 deletions packages/random/src/uuid.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,41 @@
import { randomBytes } from "./random-bytes";
import { U16BE, U32BE, U48BE } from "@thi.ng/hex";
import type { IRandom } from "./api";
import { randomBytes, randomBytesFrom } from "./random-bytes";

/**
* Uses {@link randomBytes} to fill given (optional) byte array with a UUIDv4.
* Depending on if `rnd` is given, uses {@link randomBytesFrom} or
* {@link randomBytes} to fill given (optional) byte array with a new UUIDv4.
* Creates new Uint8Array if none given.
*
* @param buf -
* @param rnd -
*/
export const uuidv4Bytes = (buf?: Uint8Array) => {
buf = randomBytes(buf || new Uint8Array(16));
export const uuidv4Bytes = (buf?: Uint8Array, rnd?: IRandom) => {
buf = buf || new Uint8Array(16);
buf = rnd ? randomBytesFrom(rnd, buf) : randomBytes(buf);
buf[6] = 0x40 | (buf[6] & 0x0f);
buf[8] = 0x80 | (buf[8] & 0x3f);
return buf;
};

/**
* Returns a UUID string, either from given byte array, of if omitted, a new
* UUID v4 produced by {@link uuidv4Bytes}.
*
* @param id - byte array
* @param i - start index
*/
export const uuid = (id?: ArrayLike<number>) => {
id = id || uuidv4Bytes();
return (
U32BE(id, 0) +
"-" +
U16BE(id, 4) +
"-" +
U16BE(id, 6) +
"-" +
U16BE(id, 8) +
"-" +
U48BE(id, 10)
);
};
22 changes: 22 additions & 0 deletions packages/random/test/uuid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as assert from "assert";
import { uuid, uuidv4Bytes, Xoshiro128 } from "../src";

describe("uuid", () => {
it("from seeded rnd", () => {
const rnd = new Xoshiro128();
let buf = uuidv4Bytes(undefined, rnd);
assert.deepStrictEqual(
buf,
// prettier-ignore
new Uint8Array([44,98,107,50,243,204,71,35,138,45,143,201,148,141,255,157])
);
assert.strictEqual(uuid(buf), "2c626b32-f3cc-4723-8a2d-8fc9948dff9d");
buf = uuidv4Bytes(undefined, rnd);
assert.deepStrictEqual(
buf,
// prettier-ignore
new Uint8Array([197,193,190,153,60,45,73,45,185,35,233,127,29,138,9,147])
);
assert.strictEqual(uuid(buf), "c5c1be99-3c2d-492d-b923-e97f1d8a0993");
});
});

0 comments on commit b31c872

Please sign in to comment.