-
Notifications
You must be signed in to change notification settings - Fork 0
/
Data.ts
107 lines (96 loc) · 2.76 KB
/
Data.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
import { DataB } from "./DataB";
import { DataConstr } from "./DataConstr";
import { DataI } from "./DataI";
import { DataList } from "./DataList";
import { DataMap } from "./DataMap";
export type Data
= DataConstr
// | DataPair<Data,Data>
| DataMap<any, any> // <Data, Data> but without circular def
| DataList
| DataI
| DataB;
function isSomething( something: any ): boolean
{
return something !== null && something !== undefined;
}
export function isData( something: any ): something is Data
{
if( !isSomething( something ) ) return false;
const proto = Object.getPrototypeOf( something );
return (
proto === DataConstr.prototype ||
proto === DataMap.prototype ||
proto === DataList.prototype ||
proto === DataI.prototype ||
proto === DataB.prototype
);
}
export function eqData( a: Data, b: Data ): boolean
{
if(!(
isSomething( a ) &&
isSomething( b )
)) return false;
const aProto = Object.getPrototypeOf( a );
const bProto = Object.getPrototypeOf( b );
if( aProto !== bProto ) return false;
if( aProto === DataConstr.prototype )
{
try {
return (
(a as DataConstr).constr === (b as DataConstr).constr &&
(a as DataConstr).fields.length === (b as DataConstr).fields.length &&
(a as DataConstr).fields.every(
(aField, idx) => eqData( aField, (b as DataConstr).fields[ idx ] )
)
);
} catch (e) {
return false;
}
}
if( aProto === DataMap.prototype )
{
type D = DataMap<Data,Data>;
const aMap = (a as D).map;
const bMap = (b as D).map;
return (
aMap.length === bMap.length &&
aMap.every(
(entry, idx) => {
const bEntry = bMap[ idx ];
return (
eqData( entry.fst, bEntry.fst ) &&
eqData( entry.snd, bEntry.snd )
);
}
)
);
}
if( aProto === DataList.prototype )
{
return (
(a as DataList).list.every(
( elem, idx ) => eqData( elem, (b as DataList).list[ idx ] )
)
);
}
if( aProto === DataI.prototype )
{
return (
(a as DataI).int === (b as DataI).int
);
}
if( aProto === DataB.prototype )
{
return (
(a as DataB).bytes.asString === (b as DataB).bytes.asString
);
}
return false;
}
export function cloneData<D extends Data>( data: D ): D
{
if( !isData( data ) ) throw new Error("invalid data while cloning");
return data.clone() as any;
}