Skip to content

Commit b4377da

Browse files
committed
Fixed #64
1 parent ac59cc4 commit b4377da

File tree

12 files changed

+464
-6
lines changed

12 files changed

+464
-6
lines changed

dist/read.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,15 @@ function consumeType(typeBuffer, offset) {
189189
readType = new t.RecursiveType(recursiveName);
190190
break;
191191
}
192+
case t.SingletonType._value: {
193+
const valueType = consumeType(typeBuffer, offset + length);
194+
length += valueType.length;
195+
const subType = valueType.value;
196+
const value = subType.consumeValue(typeBuffer, offset + length);
197+
length += value.length;
198+
readType = new t.SingletonType({ type: subType, value: value.value });
199+
break;
200+
}
192201
case t.OptionalType._value: {
193202
const subType = consumeType(typeBuffer, offset + length);
194203
length += subType.length;

dist/types/enum.d.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,12 @@ export interface EnumParams<E> {
2828
*/
2929
export default class EnumType<E> extends AbstractType<E> {
3030
static readonly _value: number;
31-
/**
32-
* The list of possible values
33-
*/
31+
/** The list of possible values */
3432
readonly values: E[];
35-
private readonly type;
33+
readonly type: Type<E>;
3634
private cachedValueIndices;
3735
/**
38-
* @param type The type of each element in the tuple
36+
* @param type The type of each value of the enum
3937
* @param values The possible distinct values.
4038
* Cannot contain more than 255 values.
4139
* @throws If any value cannot be serialized by `type`

dist/types/enum.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const abstract_1 = require("./abstract");
2828
*/
2929
class EnumType extends abstract_1.default {
3030
/**
31-
* @param type The type of each element in the tuple
31+
* @param type The type of each value of the enum
3232
* @param values The possible distinct values.
3333
* Cannot contain more than 255 values.
3434
* @throws If any value cannot be serialized by `type`

dist/types/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,6 @@ export { default as EnumType } from './enum';
3131
export { default as ChoiceType } from './choice';
3232
export { default as NamedChoiceType } from './named-choice';
3333
export { default as RecursiveType } from './recursive';
34+
export { default as SingletonType } from './singleton';
3435
export { default as OptionalType } from './optional';
3536
export { default as PointerType } from './pointer';

dist/types/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ var named_choice_1 = require("./named-choice");
6464
exports.NamedChoiceType = named_choice_1.default;
6565
var recursive_1 = require("./recursive");
6666
exports.RecursiveType = recursive_1.default;
67+
var singleton_1 = require("./singleton");
68+
exports.SingletonType = singleton_1.default;
6769
var optional_1 = require("./optional");
6870
exports.OptionalType = optional_1.default;
6971
var pointer_1 = require("./pointer");

dist/types/singleton.d.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import AppendableBuffer from '../lib/appendable';
2+
import AbstractType from './abstract';
3+
import Type from './type';
4+
export interface SingletonParams<E> {
5+
type: Type<E, any>;
6+
value: E;
7+
}
8+
/**
9+
* A type storing a fixed value.
10+
* The value takes up no space in the value bytes,
11+
* only the type bytes.
12+
* Functions as an [[EnumType]] with only one value.
13+
*
14+
* Example:
15+
* ````javascript
16+
* //Encodes a JSON literal value
17+
* let type = new sb.ChoiceType([
18+
* new sb.StructType({
19+
* type: new sb.SingletonType({
20+
* type: new sb.StringType,
21+
* value: 'boolean'
22+
* }),
23+
* value: new sb.BooleanType
24+
* }),
25+
* new sb.StructType({
26+
* type: new sb.SingletonType({
27+
* type: new sb.StringType,
28+
* value: 'number'
29+
* }),
30+
* value: new sb.DoubleType
31+
* }),
32+
* new sb.StructType({
33+
* type: new sb.SingletonType({
34+
* type: new sb.StringType,
35+
* value: 'string'
36+
* }),
37+
* value: new sb.StringType
38+
* })
39+
* ])
40+
* ````
41+
*
42+
* @param E The type of the value
43+
*/
44+
export default class SingletonType<E> extends AbstractType<E> {
45+
static readonly _value: number;
46+
/** The type used to serialize the value */
47+
readonly type: Type<E>;
48+
/** The value that this type serializes */
49+
readonly value: E;
50+
private cachedValueBuffer;
51+
/**
52+
* @param type The type that can serialize this type's value
53+
* @param value The value to serialize
54+
* @throws If `value` cannot be serialized by `type`
55+
*/
56+
constructor({ type, value }: SingletonParams<E>);
57+
private readonly singletonValueBuffer;
58+
addToBuffer(buffer: AppendableBuffer): boolean;
59+
/**
60+
* Appends value bytes to an [[AppendableBuffer]] according to the type
61+
*
62+
* Example:
63+
* ````javascript
64+
* type.writeValue(buffer, {type: 'boolean', value: true})
65+
* type.writeValue(buffer, {type: 'string', value: 'abc'})
66+
* ````
67+
* @param buffer The buffer to which to append
68+
* @param value The value to write
69+
* @throws If the value doesn't match the type, e.g. `new sb.StringType().writeValue(buffer, 23)`
70+
*/
71+
writeValue(buffer: AppendableBuffer, value: E): void;
72+
consumeValue(): {
73+
value: E;
74+
length: number;
75+
};
76+
equals(otherType: any): boolean;
77+
}

dist/types/singleton.js

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
"use strict";
2+
Object.defineProperty(exports, "__esModule", { value: true });
3+
const assert_1 = require("../lib/assert");
4+
const util_inspect_1 = require("../lib/util-inspect");
5+
const abstract_1 = require("./abstract");
6+
/**
7+
* A type storing a fixed value.
8+
* The value takes up no space in the value bytes,
9+
* only the type bytes.
10+
* Functions as an [[EnumType]] with only one value.
11+
*
12+
* Example:
13+
* ````javascript
14+
* //Encodes a JSON literal value
15+
* let type = new sb.ChoiceType([
16+
* new sb.StructType({
17+
* type: new sb.SingletonType({
18+
* type: new sb.StringType,
19+
* value: 'boolean'
20+
* }),
21+
* value: new sb.BooleanType
22+
* }),
23+
* new sb.StructType({
24+
* type: new sb.SingletonType({
25+
* type: new sb.StringType,
26+
* value: 'number'
27+
* }),
28+
* value: new sb.DoubleType
29+
* }),
30+
* new sb.StructType({
31+
* type: new sb.SingletonType({
32+
* type: new sb.StringType,
33+
* value: 'string'
34+
* }),
35+
* value: new sb.StringType
36+
* })
37+
* ])
38+
* ````
39+
*
40+
* @param E The type of the value
41+
*/
42+
class SingletonType extends abstract_1.default {
43+
/**
44+
* @param type The type that can serialize this type's value
45+
* @param value The value to serialize
46+
* @throws If `value` cannot be serialized by `type`
47+
*/
48+
constructor({ type, value }) {
49+
super();
50+
assert_1.default.instanceOf(type, abstract_1.default);
51+
this.type = type;
52+
this.value = value;
53+
}
54+
static get _value() {
55+
return 0x59;
56+
}
57+
get singletonValueBuffer() {
58+
return this.cachedValueBuffer ||
59+
(this.cachedValueBuffer = this.type.valueBuffer(this.value));
60+
}
61+
addToBuffer(buffer) {
62+
/*istanbul ignore else*/
63+
if (super.addToBuffer(buffer)) {
64+
this.type.addToBuffer(buffer);
65+
buffer.addAll(this.singletonValueBuffer);
66+
return true;
67+
}
68+
/*istanbul ignore next*/
69+
return false;
70+
}
71+
/**
72+
* Appends value bytes to an [[AppendableBuffer]] according to the type
73+
*
74+
* Example:
75+
* ````javascript
76+
* type.writeValue(buffer, {type: 'boolean', value: true})
77+
* type.writeValue(buffer, {type: 'string', value: 'abc'})
78+
* ````
79+
* @param buffer The buffer to which to append
80+
* @param value The value to write
81+
* @throws If the value doesn't match the type, e.g. `new sb.StringType().writeValue(buffer, 23)`
82+
*/
83+
writeValue(buffer, value) {
84+
this.isBuffer(buffer);
85+
try {
86+
assert_1.default.equal(this.type.valueBuffer(value), this.singletonValueBuffer);
87+
}
88+
catch (_a) {
89+
assert_1.default.fail(`Expected ${util_inspect_1.inspect(this.value)} but got ${util_inspect_1.inspect(value)}`);
90+
}
91+
}
92+
consumeValue() {
93+
return { value: this.value, length: 0 };
94+
}
95+
equals(otherType) {
96+
if (!super.equals(otherType))
97+
return false;
98+
const otherSingletonType = otherType;
99+
if (!this.type.equals(otherSingletonType.type))
100+
return false;
101+
try {
102+
assert_1.default.equal(this.value, otherSingletonType.value);
103+
}
104+
catch (_a) {
105+
return false;
106+
}
107+
return true;
108+
}
109+
}
110+
exports.default = SingletonType;

read.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,15 @@ function consumeType(typeBuffer: ArrayBuffer, offset: number): ReadResult<t.Type
192192
readType = new t.RecursiveType(recursiveName)
193193
break
194194
}
195+
case t.SingletonType._value: {
196+
const valueType = consumeType(typeBuffer, offset + length)
197+
length += valueType.length
198+
const subType = valueType.value
199+
const value = subType.consumeValue(typeBuffer, offset + length)
200+
length += value.length
201+
readType = new t.SingletonType({type: subType, value: value.value})
202+
break
203+
}
195204
case t.OptionalType._value: {
196205
const subType = consumeType(typeBuffer, offset + length)
197206
length += subType.length

test/type-bytes/singleton.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import assert from '../../dist/lib/assert'
2+
import {r} from '../../dist'
3+
import * as t from '../../dist'
4+
import {bufferFrom} from '../test-common'
5+
6+
export = () => {
7+
assert.throws(
8+
() => new t.SingletonType({} as any),
9+
'undefined is not an instance of AbstractType'
10+
)
11+
12+
{
13+
const type = new t.SingletonType({
14+
type: new t.StringType,
15+
value: 1 as any
16+
})
17+
assert.throws(
18+
() => type.toBuffer(),
19+
'1 is not an instance of String'
20+
)
21+
}
22+
23+
const type = new t.SingletonType({
24+
type: new t.StringType,
25+
value: 'abc'
26+
})
27+
{
28+
assert.equal((type as any).cachedValueBuffer, undefined)
29+
const buffer = type.toBuffer()
30+
assert.equal((type as any).cachedValueBuffer, bufferFrom([0x61, 0x62, 0x63, 0]))
31+
assert.equal(buffer, bufferFrom([0x59, 0x41, 0x61, 0x62, 0x63, 0]))
32+
assert.equal(r.type(buffer), type)
33+
}
34+
35+
{
36+
assert(!type.equals('abc'))
37+
assert(!type.equals(new t.StringType))
38+
const equalValueBytesType = new t.SingletonType({
39+
type: new t.UnsignedIntType,
40+
value: 0x61_62_63_00
41+
})
42+
assert.equal(
43+
equalValueBytesType.type.valueBuffer(equalValueBytesType.value),
44+
type.type.valueBuffer(type.value)
45+
)
46+
assert(!type.equals(equalValueBytesType))
47+
assert(!type.equals(
48+
new t.SingletonType({
49+
type: new t.StringType,
50+
value: 'def'
51+
})
52+
))
53+
assert(type.equals(
54+
new t.SingletonType({
55+
type: new t.StringType,
56+
value: 'abc'
57+
})
58+
))
59+
}
60+
}

0 commit comments

Comments
 (0)