Content-Length: 595962 | pFad | http://github.com/manzt/zarrita.js/commit/#start-of-content

678CF797 refactor: Add `assert` utility function (#244) · manzt/zarrita.js@3d19ea9 · GitHub
Skip to content

Commit

Permalink
refactor: Add assert utility function (#244)
Browse files Browse the repository at this point in the history
Makes assertions more declarative throughout the codebase.
  • Loading branch information
manzt authored Jan 8, 2025
1 parent 7832f80 commit 3d19ea9
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 75 deletions.
14 changes: 6 additions & 8 deletions packages/core/src/codecs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Crc32cCodec } from "./codecs/crc32c.js";
import { JsonCodec } from "./codecs/json2.js";
import { TransposeCodec } from "./codecs/transpose.js";
import { VLenUTF8 } from "./codecs/vlen-utf8.js";
import { assert } from "./util.js";

type ChunkMetadata<D extends DataType> = {
data_type: D;
Expand Down Expand Up @@ -90,9 +91,7 @@ type BytesToBytesCodec = {
async function load_codecs<D extends DataType>(chunk_meta: ChunkMetadata<D>) {
let promises = chunk_meta.codecs.map(async (meta) => {
let Codec = await registry.get(meta.name)?.();
if (!Codec) {
throw new Error(`Unknown codec: ${meta.name}`);
}
assert(Codec, `Unknown codec: ${meta.name}`);
return { Codec, meta };
});
let array_to_array: ArrayToArrayCodec<D>[] = [];
Expand All @@ -112,11 +111,10 @@ async function load_codecs<D extends DataType>(chunk_meta: ChunkMetadata<D>) {
}
}
if (!array_to_bytes) {
if (!is_typed_array_like_meta(chunk_meta)) {
throw new Error(
`Cannot encode ${chunk_meta.data_type} to bytes without a codec`,
);
}
assert(
is_typed_array_like_meta(chunk_meta),
`Cannot encode ${chunk_meta.data_type} to bytes without a codec`,
);
array_to_bytes = BytesCodec.fromConfig({ endian: "little" }, chunk_meta);
}
return { array_to_array, array_to_bytes, bytes_to_bytes };
Expand Down
5 changes: 2 additions & 3 deletions packages/core/src/codecs/bitround.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Chunk, Float32, Float64 } from "../metadata.js";
import { assert } from "../util.js";

/**
* A codec for bit-rounding.
Expand All @@ -20,9 +21,7 @@ export class BitroundCodec<D extends Float64 | Float32> {
kind = "array_to_array";

constructor(configuration: { keepbits: number }, _meta: { data_type: D }) {
if (configuration.keepbits < 0) {
throw new Error("keepbits must be zero or positive");
}
assert(configuration.keepbits >= 0, "keepbits must be zero or positive");
}

static fromConfig<D extends Float32 | Float64>(
Expand Down
67 changes: 31 additions & 36 deletions packages/core/src/codecs/json2.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Adapted from https://github.com/hms-dbmi/vizarr/blob/5b0e3ea6fbb42d19d0e38e60e49bb73d1aca0693/src/utils.ts#L26
import type { Chunk, ObjectType } from "../metadata.js";
import { get_strides, json_decode_object } from "../util.js";
import { assert, get_strides, json_decode_object } from "../util.js";

type EncoderConfig = {
encoding?: "utf-8";
Expand All @@ -24,23 +24,18 @@ type ReplacerFunction = (key: string | number, value: any) => any;

// Reference: https://stackoverflow.com/a/21897413
function throw_on_nan_replacer(_key: string | number, value: number): number {
if (Number.isNaN(value)) {
throw new Error(
"JsonCodec allow_nan is false but NaN was encountered during encoding.",
);
}

if (value === Number.POSITIVE_INFINITY) {
throw new Error(
"JsonCodec allow_nan is false but Infinity was encountered during encoding.",
);
}

if (value === Number.NEGATIVE_INFINITY) {
throw new Error(
"JsonCodec allow_nan is false but -Infinity was encountered during encoding.",
);
}
assert(
!Number.isNaN(value),
"JsonCodec allow_nan is false but NaN was encountered during encoding.",
);
assert(
value !== Number.POSITIVE_INFINITY,
"JsonCodec allow_nan is false but Infinity was encountered during encoding.",
);
assert(
value !== Number.NEGATIVE_INFINITY,
"JsonCodec allow_nan is false but -Infinity was encountered during encoding.",
);
return value;
}

Expand Down Expand Up @@ -117,17 +112,19 @@ export class JsonCodec {
allow_nan,
sort_keys,
} = this.#encoder_config;
if (encoding !== "utf-8") {
throw new Error("JsonCodec does not yet support non-utf-8 encoding.");
}
assert(
encoding === "utf-8",
"JsonCodec does not yet support non-utf-8 encoding.",
);
const replacer_functions: ReplacerFunction[] = [];
if (!check_circular) {
// By default, for JSON.stringify,
// a TypeError will be thrown if one attempts to encode an object with circular references
throw new Error(
"JsonCodec does not yet support skipping the check for circular references during encoding.",
);
}

// By default, for JSON.stringify,
// a TypeError will be thrown if one attempts to encode an object with circular references
assert(
check_circular,
"JsonCodec does not yet support skipping the check for circular references during encoding.",
);

if (!allow_nan) {
// Throw if NaN/Infinity/-Infinity are encountered during encoding.
replacer_functions.push(throw_on_nan_replacer);
Expand Down Expand Up @@ -170,17 +167,15 @@ export class JsonCodec {

decode(bytes: Uint8Array): Chunk<ObjectType> {
const { strict } = this.#decoder_config;
if (!strict) {
// (i.e., allowing control characters inside strings)
throw new Error("JsonCodec does not yet support non-strict decoding.");
}
// (i.e., allowing control characters inside strings)
assert(strict, "JsonCodec does not yet support non-strict decoding.");

const items = json_decode_object(bytes);
const shape = items.pop();
items.pop(); // Pop off dtype (unused)
if (!shape) {
// O-d case
throw new Error("0D not implemented for JsonCodec.");
}

// O-d case
assert(shape, "0D not implemented for JsonCodec.");
const stride = get_strides(shape, "C");
const data = items;
return { data, shape, stride };
Expand Down
6 changes: 2 additions & 4 deletions packages/core/src/codecs/sharding.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Location } from "../hierarchy.js";
import type { Chunk } from "../metadata.js";
import type { ShardingCodecMetadata } from "../util.js";
import { assert, type ShardingCodecMetadata } from "../util.js";

import type { Readable } from "@zarrita/storage";
import { create_codec_pipeline } from "../codecs.js";
Expand All @@ -13,9 +13,7 @@ export function create_sharded_chunk_getter<Store extends Readable>(
encode_shard_key: (coord: number[]) => string,
sharding_config: ShardingCodecMetadata["configuration"],
) {
if (location.store.getRange === undefined) {
throw new Error("Store does not support range requests");
}
assert(location.store.getRange, "Store does not support range requests");
let get_range = location.store.getRange.bind(location.store);
let index_shape = shard_shape.map(
(d, i) => d / sharding_config.chunk_shape[i],
Expand Down
8 changes: 5 additions & 3 deletions packages/core/src/consolidated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
GroupMetadataV2,
} from "./metadata.js";
import {
assert,
json_decode_object,
json_encode_object,
rethrow_unless,
Expand Down Expand Up @@ -38,9 +39,10 @@ async function get_consolidated_metadata(
});
}
let meta: ConsolidatedMetadata = json_decode_object(bytes);
if (meta.zarr_consolidated_format !== 1) {
throw new Error("Unsupported consolidated format.");
}
assert(
meta.zarr_consolidated_format === 1,
"Unsupported consolidated format.",
);
return meta;
}

Expand Down
39 changes: 29 additions & 10 deletions packages/core/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,8 @@ export function get_ctr<D extends DataType>(
);
}
// @ts-expect-error - We've checked that the key exists
let ctr: TypedArrayConstructor<D> = CONSTRUCTORS[data_type];
if (!ctr) {
throw new Error(`Unknown or unsupported data_type: ${data_type}`);
}
let ctr: TypedArrayConstructor<D> | undefined = CONSTRUCTORS[data_type];
assert(ctr, `Unknown or unsupported data_type: ${data_type}`);
return ctr;
}

Expand Down Expand Up @@ -136,9 +134,8 @@ function coerce_dtype(
}

let match = dtype.match(endian_regex);
if (!match) {
throw new Error(`Invalid dtype: ${dtype}`);
}
assert(match, `Invalid dtype: ${dtype}`);

let [, endian, rest] = match;
let data_type =
{
Expand All @@ -155,9 +152,7 @@ function coerce_dtype(
f8: "float64",
}[rest] ??
(rest.startsWith("S") || rest.startsWith("U") ? `v2:${rest}` : undefined);
if (!data_type) {
throw new Error(`Unsupported or unknown dtype: ${dtype}`);
}
assert(data_type, `Unsupported or unknown dtype: ${dtype}`);
if (endian === "|") {
return { data_type } as { data_type: DataType };
}
Expand Down Expand Up @@ -332,3 +327,27 @@ export function rethrow_unless<E extends ReadonlyArray<ErrorConstructor>>(
throw error;
}
}

/**
* Make an assertion.
*
* Usage
* @example
* ```ts
* const value: boolean = Math.random() <= 0.5;
* assert(value, "value is greater than than 0.5!");
* value // true
* ```
*
* @param expression - The expression to test.
* @param msg - The optional message to display if the assertion fails.
* @throws an {@link Error} if `expression` is not truthy.
*/
export function assert(
expression: unknown,
msg: string | undefined = "",
): asserts expression {
if (!expression) {
throw new Error(msg);
}
}
22 changes: 22 additions & 0 deletions packages/storage/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,25 @@ export function merge_init(
},
};
}

/**
* Make an assertion.
*
* Usage
* @example
* ```ts
* const value: boolean = Math.random() <= 0.5;
* assert(value, "value is greater than than 0.5!");
* value // true
* ```
*
* @param expression - The expression to test.
* @param msg - The optional message to display if the assertion fails.
* @throws an {@link Error} if `expression` is not truthy.
*/
export function assert(
expression: unknown,
msg: string | undefined = "",
): asserts expression {
if (!expression) throw new Error(msg);
}
20 changes: 9 additions & 11 deletions packages/storage/src/zip.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { unzip } from "unzipit";
import { fetch_range, strip_prefix } from "./util.js";
import { assert, fetch_range, strip_prefix } from "./util.js";

import type { Reader, ZipInfo } from "unzipit";
import type { AbsolutePath, AsyncReadable } from "./types.js";
Expand Down Expand Up @@ -35,11 +35,10 @@ export class HTTPRangeReader implements Reader {
...this.#overrides,
method: "HEAD",
});
if (!req.ok) {
throw new Error(
`failed http request ${this.url}, status: ${req.status}: ${req.statusText}`,
);
}
assert(
req.ok,
`failed http request ${this.url}, status: ${req.status}: ${req.statusText}`,
);
this.length = Number(req.headers.get("content-length"));
if (Number.isNaN(this.length)) {
throw Error("could not get length");
Expand All @@ -53,11 +52,10 @@ export class HTTPRangeReader implements Reader {
return new Uint8Array(0);
}
const req = await fetch_range(this.url, offset, size, this.#overrides);
if (!req.ok) {
throw new Error(
`failed http request ${this.url}, status: ${req.status} offset: ${offset} size: ${size}: ${req.statusText}`,
);
}
assert(
req.ok,
`failed http request ${this.url}, status: ${req.status} offset: ${offset} size: ${size}: ${req.statusText}`,
);
return new Uint8Array(await req.arrayBuffer());
}
}
Expand Down

0 comments on commit 3d19ea9

Please sign in to comment.








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/manzt/zarrita.js/commit/#start-of-content

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy