Skip to content

Commit a4cc8de

Browse files
authored
Merge pull request #1556 from silx-kit/dtype-h5wasm
Improve dtype parsing with h5wasm
2 parents 1bdd035 + 406fa47 commit a4cc8de

File tree

6 files changed

+205
-160
lines changed

6 files changed

+205
-160
lines changed

packages/h5wasm/src/__snapshots__/h5wasm-api.test.ts.snap

+20-8
Original file line numberDiff line numberDiff line change
@@ -876,7 +876,8 @@ exports[`test file matches snapshot 1`] = `
876876
},
877877
"shape": [],
878878
"type": {
879-
"class": "Unknown",
879+
"class": "Opaque",
880+
"tag": "",
880881
},
881882
"value": Uint8Array [
882883
0,
@@ -897,7 +898,8 @@ exports[`test file matches snapshot 1`] = `
897898
},
898899
"shape": [],
899900
"type": {
900-
"class": "Unknown",
901+
"class": "Opaque",
902+
"tag": "",
901903
},
902904
"value": Uint8Array [
903905
150,
@@ -923,7 +925,8 @@ exports[`test file matches snapshot 1`] = `
923925
},
924926
"shape": [],
925927
"type": {
926-
"class": "Unknown",
928+
"class": "Opaque",
929+
"tag": "",
927930
},
928931
"value": Uint8Array [
929932
0,
@@ -1724,7 +1727,10 @@ exports[`test file matches snapshot 1`] = `
17241727
],
17251728
},
17261729
"vlen": {
1727-
"class": "Unknown",
1730+
"base": {
1731+
"class": "Unknown",
1732+
},
1733+
"class": "Array (variable length)",
17281734
},
17291735
},
17301736
},
@@ -1792,7 +1798,7 @@ exports[`test file matches snapshot 1`] = `
17921798
},
17931799
"shape": [],
17941800
"type": {
1795-
"class": "Unknown",
1801+
"class": "Reference",
17961802
},
17971803
"value": Uint8Array [
17981804
214,
@@ -1818,7 +1824,7 @@ exports[`test file matches snapshot 1`] = `
18181824
},
18191825
"shape": [],
18201826
"type": {
1821-
"class": "Unknown",
1827+
"class": "Reference",
18221828
},
18231829
"value": Uint8Array [
18241830
34,
@@ -2028,7 +2034,10 @@ exports[`test file matches snapshot 1`] = `
20282034
},
20292035
"shape": [],
20302036
"type": {
2031-
"class": "Unknown",
2037+
"base": {
2038+
"class": "Unknown",
2039+
},
2040+
"class": "Array (variable length)",
20322041
},
20332042
"value": Uint8Array [
20342043
2,
@@ -2056,7 +2065,10 @@ exports[`test file matches snapshot 1`] = `
20562065
3,
20572066
],
20582067
"type": {
2059-
"class": "Unknown",
2068+
"base": {
2069+
"class": "Unknown",
2070+
},
2071+
"class": "Array (variable length)",
20602072
},
20612073
"value": Uint8Array [
20622074
1,

packages/h5wasm/src/guards.ts

+4-59
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,18 @@
11
import { isCompoundType } from '@h5web/shared/guards';
22
import type { Dataset, DType } from '@h5web/shared/hdf5-models';
33
import { DTypeClass } from '@h5web/shared/hdf5-models';
4-
import type { Metadata } from 'h5wasm';
54
import { Dataset as H5WasmDataset } from 'h5wasm';
65

7-
import type {
8-
CompoundMetadata,
9-
EnumMetadata,
10-
H5WasmEntity,
11-
NumericMetadata,
12-
} from './models';
6+
import type { H5WasmEntity } from './models';
137

148
export function assertH5WasmDataset(
15-
entity: H5WasmEntity,
16-
): asserts entity is H5WasmDataset {
17-
if (!(entity instanceof H5WasmDataset)) {
9+
h5wEntity: NonNullable<H5WasmEntity>,
10+
): asserts h5wEntity is H5WasmDataset {
11+
if (!(h5wEntity instanceof H5WasmDataset)) {
1812
throw new TypeError('Expected H5Wasm entity to be dataset');
1913
}
2014
}
2115

22-
// See H5T_class_t in https://github.com/usnistgov/h5wasm/blob/main/src/hdf5_util_helpers.d.ts
23-
export function isIntegerMetadata(metadata: Metadata) {
24-
return metadata.type === 0;
25-
}
26-
27-
export function isFloatMetadata(metadata: Metadata) {
28-
return metadata.type === 1;
29-
}
30-
31-
export function isNumericMetadata(
32-
metadata: Metadata,
33-
): metadata is NumericMetadata {
34-
return isIntegerMetadata(metadata) || isFloatMetadata(metadata);
35-
}
36-
37-
export function isStringMetadata(metadata: Metadata) {
38-
return metadata.type === 3;
39-
}
40-
41-
export function isArrayMetadata(metadata: Metadata) {
42-
return metadata.type === 10;
43-
}
44-
45-
export function isCompoundMetadata(
46-
metadata: Metadata,
47-
): metadata is CompoundMetadata {
48-
return metadata.type === 6;
49-
}
50-
51-
export function isEnumMetadata(metadata: Metadata): metadata is EnumMetadata {
52-
return metadata.type === 8;
53-
}
54-
55-
export function assertCompoundMetadata(
56-
metadata: Metadata,
57-
): asserts metadata is CompoundMetadata {
58-
if (!isCompoundMetadata(metadata)) {
59-
throw new Error('Expected H5Wasm compound metadata');
60-
}
61-
}
62-
63-
export function assertNumericMetadata(
64-
metadata: Metadata,
65-
): asserts metadata is NumericMetadata {
66-
if (!isNumericMetadata(metadata)) {
67-
throw new Error('Expected H5Wasm numeric metadata');
68-
}
69-
}
70-
7116
function isInt64Type(type: DType): boolean {
7217
return (
7318
(type.class === DTypeClass.Integer || type.class === DTypeClass.Unsigned) &&

packages/h5wasm/src/models.ts

+1-18
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,5 @@
1-
import type {
2-
CompoundTypeMetadata,
3-
EnumTypeMetadata,
4-
Group as H5WasmGroup,
5-
Metadata,
6-
} from 'h5wasm';
1+
import type { Group as H5WasmGroup } from 'h5wasm';
72

83
export type H5WasmEntity = ReturnType<H5WasmGroup['get']>;
94

105
export type H5WasmAttributes = H5WasmGroup['attrs'];
11-
12-
export interface CompoundMetadata extends Metadata {
13-
compound_type: CompoundTypeMetadata;
14-
}
15-
16-
export interface NumericMetadata extends Metadata {
17-
type: 0 | 1;
18-
}
19-
20-
export interface EnumMetadata extends Metadata {
21-
enum_type: EnumTypeMetadata;
22-
}

packages/h5wasm/src/utils.ts

+65-72
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
1-
import { assertDefined } from '@h5web/shared/guards';
1+
import { assertDefined, isNumericType } from '@h5web/shared/guards';
22
import type {
33
Attribute,
44
ChildEntity,
55
DType,
66
Group,
7-
NumericType,
87
ProvidedEntity,
98
Shape,
109
} from '@h5web/shared/hdf5-models';
11-
import { Endianness, EntityKind } from '@h5web/shared/hdf5-models';
10+
import { Endianness, EntityKind, H5TClass } from '@h5web/shared/hdf5-models';
1211
import {
1312
arrayType,
14-
boolType,
13+
bitfieldType,
1514
buildEntityPath,
16-
compoundType,
17-
cplxType,
18-
enumType,
15+
compoundOrCplxType,
16+
enumOrBoolType,
1917
floatType,
20-
intType,
21-
isBoolEnumType,
18+
intOrUintType,
19+
opaqueType,
20+
referenceType,
2221
strType,
23-
uintType,
22+
timeType,
23+
toCharSet,
2424
unknownType,
2525
} from '@h5web/shared/hdf5-utils';
2626
import type { Metadata } from 'h5wasm';
@@ -32,17 +32,7 @@ import {
3232
Group as H5WasmGroup,
3333
} from 'h5wasm';
3434

35-
import {
36-
assertNumericMetadata,
37-
isArrayMetadata,
38-
isCompoundMetadata,
39-
isEnumMetadata,
40-
isFloatMetadata,
41-
isIntegerMetadata,
42-
isNumericMetadata,
43-
isStringMetadata,
44-
} from './guards';
45-
import type { H5WasmAttributes, H5WasmEntity, NumericMetadata } from './models';
35+
import type { H5WasmAttributes, H5WasmEntity } from './models';
4636

4737
// https://github.com/h5wasm/h5wasm-plugins#included-plugins
4838
// https://support.hdfgroup.org/services/contributions.html
@@ -162,83 +152,86 @@ function parseAttributes(h5wAttrs: H5WasmAttributes): Attribute[] {
162152
});
163153
}
164154

165-
export function parseDTypeFromNumericMetadata(
166-
metadata: NumericMetadata,
167-
): NumericType {
168-
const { signed, size: length, littleEndian } = metadata;
169-
const size = length * 8;
170-
const endianness = littleEndian ? Endianness.LE : Endianness.BE;
155+
export function parseDType(metadata: Metadata): DType {
156+
const { type: h5tClass, size } = metadata;
171157

172-
if (isIntegerMetadata(metadata)) {
173-
return signed ? intType(size, endianness) : uintType(size, endianness);
158+
if (h5tClass === H5TClass.Integer) {
159+
const { signed, littleEndian } = metadata;
160+
return intOrUintType(signed, size * 8, toEndianness(littleEndian));
174161
}
175-
176-
if (isFloatMetadata(metadata)) {
177-
return floatType(size, endianness);
162+
if (h5tClass === H5TClass.Float) {
163+
const { littleEndian } = metadata;
164+
return floatType(size * 8, toEndianness(littleEndian));
178165
}
179166

180-
throw new Error('Expected numeric metadata');
181-
}
182-
183-
export function parseDType(metadata: Metadata): DType {
184-
if (isNumericMetadata(metadata)) {
185-
return parseDTypeFromNumericMetadata(metadata);
167+
if (h5tClass === H5TClass.Time) {
168+
return timeType();
186169
}
187170

188-
if (isStringMetadata(metadata)) {
189-
const { size, cset, vlen } = metadata;
190-
191-
return strType(
192-
cset === 1 ? 'UTF-8' : 'ASCII',
193-
// For variable-length string datatypes, the returned value is the size of the pointer to the actual string and
194-
// not the size of actual variable-length string data (https://portal.hdfgroup.org/display/HDF5/H5T_GET_SIZE)
195-
vlen ? undefined : size,
196-
);
171+
if (h5tClass === H5TClass.String) {
172+
const { cset, vlen } = metadata;
173+
return strType(toCharSet(cset), vlen ? undefined : size);
197174
}
198175

199-
if (isArrayMetadata(metadata)) {
200-
const { array_type } = metadata;
201-
assertDefined(array_type);
176+
if (h5tClass === H5TClass.Bitfield) {
177+
return bitfieldType();
178+
}
202179

203-
return arrayType(parseDType(array_type), array_type.shape);
180+
if (h5tClass === H5TClass.Opaque) {
181+
return opaqueType();
204182
}
205183

206-
if (isCompoundMetadata(metadata)) {
184+
if (h5tClass === H5TClass.Compound) {
207185
const { compound_type } = metadata;
208-
const { members, nmembers } = compound_type;
209-
210-
if (nmembers === 2 && members[0].name === 'r' && members[1].name === 'i') {
211-
const [realTypeMetadata, imagTypeMetadata] = members;
212-
assertNumericMetadata(realTypeMetadata);
213-
assertNumericMetadata(imagTypeMetadata);
186+
assertDefined(compound_type);
214187

215-
return cplxType(
216-
parseDTypeFromNumericMetadata(realTypeMetadata),
217-
parseDTypeFromNumericMetadata(imagTypeMetadata),
218-
);
219-
}
220-
221-
return compoundType(
188+
return compoundOrCplxType(
222189
Object.fromEntries(
223-
members.map((member) => [member.name, parseDType(member)]),
190+
compound_type.members.map((member) => [
191+
member.name,
192+
parseDType(member),
193+
]),
224194
),
225195
);
226196
}
227197

228-
if (isEnumMetadata(metadata)) {
198+
if (h5tClass === H5TClass.Reference) {
199+
return referenceType();
200+
}
201+
202+
if (h5tClass === H5TClass.Enum) {
229203
const { enum_type } = metadata;
230-
const { members: mapping, type: baseType } = enum_type;
204+
assertDefined(enum_type);
205+
const { members, type } = enum_type;
231206

232-
const baseMetadata = { ...metadata, type: baseType };
233-
assertNumericMetadata(baseMetadata);
207+
const baseType = parseDType({ ...metadata, type });
208+
if (!isNumericType(baseType)) {
209+
throw new Error('Expected enum type to have numeric base type');
210+
}
234211

235-
const type = enumType(parseDTypeFromNumericMetadata(baseMetadata), mapping);
236-
return isBoolEnumType(type) ? boolType() : type; // booleans stored as enums by h5py
212+
return enumOrBoolType(baseType, members);
213+
}
214+
215+
if (h5tClass === H5TClass.Vlen) {
216+
// Not currently provided, so unable to know base type
217+
// const { array_type } = metadata;
218+
// assertDefined(array_type);
219+
return arrayType(unknownType());
220+
}
221+
222+
if (h5tClass === H5TClass.Array) {
223+
const { array_type } = metadata;
224+
assertDefined(array_type);
225+
return arrayType(parseDType(array_type), array_type.shape);
237226
}
238227

239228
return unknownType();
240229
}
241230

231+
function toEndianness(littleEndian: boolean): Endianness {
232+
return littleEndian ? Endianness.LE : Endianness.BE;
233+
}
234+
242235
export function convertSelectionToRanges(
243236
dataset: H5WasmDataset,
244237
selection: string,

0 commit comments

Comments
 (0)