-
Notifications
You must be signed in to change notification settings - Fork 48
/
Integer.ts
131 lines (119 loc) · 3.87 KB
/
Integer.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import { IonTypes, Writer } from "../Ion";
import {
FromJsConstructor,
FromJsConstructorBuilder,
Primitives,
} from "./FromJsConstructor";
import { Constructor, Value } from "./Value";
// BigInt is an irregular class type in that it provides no constructor, only static
// constructor methods. This means that bigint does not conform to the typical Constructor
// interface of new(...args) => any. Because FromJsConstructor will only use it for
// instanceof tests, we can safely cast it as a Constructor to satisfy the compiler.
const _bigintConstructor: Constructor = (BigInt as unknown) as Constructor;
const _fromJsConstructor: FromJsConstructor = new FromJsConstructorBuilder()
.withPrimitives(Primitives.Number, Primitives.BigInt)
.withClassesToUnbox(Number)
.withClasses(_bigintConstructor)
.build();
/**
* Represents an integer value in an Ion stream.
*
* [1] https://amazon-ion.github.io/ion-docs/docs/spec.html#int
*/
export class Integer extends Value(Number, IonTypes.INT, _fromJsConstructor) {
private _bigIntValue: bigint | null;
private _numberValue: number;
/**
* Constructor.
* @param value The numeric value to represent as an integer.
* @param annotations An optional array of strings to associate with `value`.
*/
constructor(value: bigint | number, annotations: string[] = []) {
// If the provided value is a JS number, we will defer constructing a BigInt representation
// of it until it's requested later by a call to bigIntValue().
if (typeof value === "number") {
super(value);
this._numberValue = value;
this._bigIntValue = null;
} else {
const numberValue: number = Number(value);
super(numberValue);
this._bigIntValue = value;
this._numberValue = numberValue;
}
this._setAnnotations(annotations);
}
bigIntValue(): bigint {
if (this._bigIntValue === null) {
this._bigIntValue = BigInt(this.numberValue());
}
return this._bigIntValue;
}
numberValue(): number {
return this._numberValue;
}
toString(): string {
if (this._bigIntValue === null) {
return this._numberValue.toString();
}
return this._bigIntValue.toString();
}
valueOf() {
return this.numberValue();
}
writeTo(writer: Writer): void {
writer.setAnnotations(this.getAnnotations());
if (this._bigIntValue === null) {
writer.writeInt(this.numberValue());
} else {
writer.writeInt(this._bigIntValue);
}
}
_valueEquals(
other: any,
options: {
epsilon?: number | null;
ignoreAnnotations?: boolean;
ignoreTimestampPrecision?: boolean;
onlyCompareIon?: boolean;
} = {
epsilon: null,
ignoreAnnotations: false,
ignoreTimestampPrecision: false,
onlyCompareIon: true,
}
): boolean {
let isSupportedType: boolean = false;
let valueToCompare: any = null;
// if the provided value is an ion.dom.Integer instance.
if (other instanceof Integer) {
isSupportedType = true;
if (this._bigIntValue == null && other._bigIntValue == null) {
valueToCompare = other.numberValue();
} else {
// One of them is a bigint
valueToCompare = other.bigIntValue();
}
} else if (!options.onlyCompareIon) {
// We will consider other Integer-ish types
if (other instanceof Number || typeof other === "number") {
isSupportedType = true;
if (this.bigIntValue == null) {
valueToCompare = other.valueOf();
} else {
valueToCompare = BigInt(other.valueOf());
}
} else if (typeof other === "bigint") {
isSupportedType = true;
valueToCompare = other;
}
}
if (!isSupportedType) {
return false;
}
if (typeof valueToCompare === "bigint") {
return this.bigIntValue() === valueToCompare;
}
return this.numberValue() == valueToCompare;
}
}