Skip to content

Commit

Permalink
Refactor BoxArray into StructArray.
Browse files Browse the repository at this point in the history
  • Loading branch information
smack0007 committed Sep 20, 2024
1 parent 332c9e8 commit 370b996
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 114 deletions.
18 changes: 10 additions & 8 deletions examples/renderer/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { SDL } from "SDL_ts";
import { SDL_FUNCTIONS } from "./sdlConfig.ts";
import { ASSETS_PATH } from "../../shared/constants.ts";
import { join } from "@std/path";
import { StructArray } from "../../src/structs.ts";

const WINDOW_WIDTH = 1024;
const WINDOW_HEIGHT = 768;
Expand Down Expand Up @@ -41,11 +42,11 @@ function main(): void {
SDL.FreeSurface(denoSurface);

// deno-fmt-ignore
const points = new Uint32Array([
0, 0,
1, 0,
1, 1,
0, 1
const points = new StructArray<SDL.Point>(SDL.Point, [
new SDL.Point(0, 0),
new SDL.Point(1, 0),
new SDL.Point(1, 1),
new SDL.Point(0, 1)
]);

const event = new SDL.Event();
Expand Down Expand Up @@ -81,16 +82,17 @@ function main(): void {
textureCenter,
SDL.RendererFlip.NONE,
);

SDL.SetRenderDrawColor(renderer, 255, 0, 0, 255);
SDL.RenderDrawPoints(renderer, points, 4);

const rect = new SDL.Rect(100, 100, 200, 400);
SDL.RenderDrawLine(renderer, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
SDL.RenderFillRect(renderer, rect);
SDL.SetRenderDrawColor(renderer, 0, 0, 255, 255);
SDL.RenderDrawRect(renderer, rect);

SDL.SetRenderDrawColor(renderer, 0, 0, 255, 255);
SDL.RenderDrawPoints(renderer, points, 4);

SDL.RenderPresent(renderer);
SDL.RenderFlush(renderer);

Expand Down
103 changes: 2 additions & 101 deletions src/_boxes.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
import Platform from "./_platform.ts";
import {
AllocatableStruct,
AllocatableStructConstructor,
Constructor,
double,
Factory,
float,
int,
OrFactory,
Pointer,
Predicate,
Sint32,
Struct,
TypedNumber,
Uint16,
Uint32,
Uint64,
Uint8,
} from "./types.ts";
import { throwError } from "./_utils.ts";
import { PlatformDataView } from "./_types.ts";
import { sizeof } from "./_utils.ts";

export type BoxValue = Pointer<unknown> | TypedNumber | Struct;
export type BoxValue = TypedNumber | Pointer<unknown>;

export type BoxValueConstructor<T extends BoxValue> = Constructor<T>;

Expand All @@ -33,44 +28,6 @@ type BoxValueTransformer<T extends BoxValue> = (
offset: number,
) => T;

function sizeof<T extends BoxValue>(
factoryOrConstructor: BoxValueFactory<T> | BoxValueConstructor<T>,
): number {
if (
"SIZE_IN_BYTES" in
(factoryOrConstructor as unknown as AllocatableStructConstructor<AllocatableStruct>)
) {
return (
factoryOrConstructor as unknown as AllocatableStructConstructor<AllocatableStruct>
).SIZE_IN_BYTES;
}

switch (factoryOrConstructor) {
case Uint8:
return 1;

case Uint16:
return 2;

case float:
case int:
case Sint32:
case Uint32:
return 4;

case double:
case Uint64:
return 8;

case Pointer as unknown as BoxValueFactory<T>:
return Platform.POINTER_SIZE_IN_BYTES;
}

throwError(
`${factoryOrConstructor?.name} is not boxable. sizeof not implemented.`,
);
}

export function getTransformer<T extends BoxValue>(
factoryOrConstructor: BoxValueFactory<T> | BoxValueConstructor<T>,
): BoxValueTransformer<T> {
Expand Down Expand Up @@ -101,10 +58,6 @@ export function getTransformer<T extends BoxValue>(
return ((_, view, offset) => view.getPointer(offset)) as BoxValueTransformer<T>;
}

if ("of" in factoryOrConstructor) {
return factoryOrConstructor.of as unknown as BoxValueTransformer<T>;
}

throw new Error(
`${factoryOrConstructor?.name} is not boxable. getTransformer not implemented.`,
);
Expand Down Expand Up @@ -132,56 +85,4 @@ export class Box<T extends BoxValue> {
public get value(): T {
return this._transformer(this._data, this._view, 0);
}

public unbox(predicate: Predicate<T>, errorMessage: OrFactory<string>): T {
const value = this.value;
return predicate(value) ? value : throwError(errorMessage);
}

public unboxNotNull(errorMessage: OrFactory<string>): T {
return this.unbox((value) => value != 0, errorMessage);
}
}

export class BoxArray<T extends BoxValue> {
public readonly sizeOfElementInBytes: number;
private readonly _transformer: BoxValueTransformer<T>;
public readonly _data: Uint8Array;
public readonly _view: PlatformDataView;

public constructor(
factoryOrConstructor: BoxValueFactory<T> | BoxValueConstructor<T>,
length: number,
) {
if (length <= 0) {
throw new Error("length must be > 0.");
}

this.sizeOfElementInBytes = sizeof(factoryOrConstructor);
this._transformer = getTransformer(factoryOrConstructor);

this._data = new Uint8Array(this.sizeOfElementInBytes * length);
this._view = new Platform.DataView(this._data);
}

public static isBoxArray(value: unknown): value is BoxArray<BoxValue> {
return value instanceof BoxArray;
}

public at(index: number): T {
return this._transformer(
this._data,
this._view,
this.sizeOfElementInBytes * index,
);
}

public unboxAt(
index: number,
predicate: Predicate<T>,
errorMessage: string,
): T {
const value = this.at(index);
return predicate(value) ? value : throwError(errorMessage);
}
}
56 changes: 55 additions & 1 deletion src/_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,23 @@

import Platform from "./_platform.ts";
import { SDLError } from "./error.ts";
import { type OrFactory, type Pointer, type TypedArray } from "./types.ts";
import {
AllocatableStruct,
AllocatableStructConstructor,
Constructor,
double,
Factory,
float,
int,
type OrFactory,
Pointer,
Sint32,
type TypedArray,
Uint16,
Uint32,
Uint64,
Uint8,
} from "./types.ts";

//
// Constants
Expand Down Expand Up @@ -44,6 +60,44 @@ export function isTypedArray(value: unknown): value is TypedArray {
);
}

export function sizeof<T>(
factoryOrConstructor: Constructor<T> | Factory<T>,
): number {
if (
"SIZE_IN_BYTES" in
(factoryOrConstructor as unknown as AllocatableStructConstructor<AllocatableStruct>)
) {
return (
factoryOrConstructor as unknown as AllocatableStructConstructor<AllocatableStruct>
).SIZE_IN_BYTES;
}

switch (factoryOrConstructor) {
case Uint8:
return 1;

case Uint16:
return 2;

case float:
case int:
case Sint32:
case Uint32:
return 4;

case double:
case Uint64:
return 8;

case Pointer:
return Platform.POINTER_SIZE_IN_BYTES;
}

throw new Error(
`${factoryOrConstructor?.name} is not boxable. sizeof not implemented.`,
);
}

export function throwError(message: OrFactory<string>, cause?: Error): never {
throw new SDLError(typeof message === "function" ? message() : message, cause);
}
43 changes: 43 additions & 0 deletions src/structs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import Platform from "./_platform.ts";
import { PlatformDataView } from "./_types.ts";
import { sizeof } from "./_utils.ts";
import { AllocatableStruct, AllocatableStructConstructor } from "./types.ts";

export class StructArray<T extends AllocatableStruct> {
public readonly sizeOfElementInBytes: number;
public readonly _data: Uint8Array;
public readonly _view: PlatformDataView;

public constructor(constructor: AllocatableStructConstructor<T>, data: T[]);
public constructor(constructor: AllocatableStructConstructor<T>, length: number);
public constructor(
constructor: AllocatableStructConstructor<T>,
dataOrLength: T[] | number,
) {
this.sizeOfElementInBytes = sizeof(constructor);

const isArray = Array.isArray(dataOrLength);
const length = isArray ? dataOrLength.length : dataOrLength;

if (length < 0) {
throw new Error("length must be >= 0.");
}

this._data = new Uint8Array(this.sizeOfElementInBytes * length);
this._view = new Platform.DataView(this._data);

if (isArray) {
for (let i = 0; i < dataOrLength.length; i += 1) {
if (!(dataOrLength[i]._data instanceof Uint8Array)) {
throw new Error(`Struct at index ${i} is not backed by a Uint8Array.`);
}

this._data.set(dataOrLength[i]._data as Uint8Array, i * this.sizeOfElementInBytes);
}
}
}
}

export function isStructArray<T extends AllocatableStruct>(value: unknown): value is StructArray<T> {
return value instanceof StructArray;
}
10 changes: 6 additions & 4 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
// This file is for types exposed as part of the API.

import Platform from "./_platform.ts";
import { Box, BoxArray, BoxValue } from "./_boxes.ts";
import { Box, BoxValue } from "./_boxes.ts";
import { PlatformPointer } from "./_types.ts";
import { StructArray } from "./structs.ts";

declare const _: unique symbol;

Expand Down Expand Up @@ -63,8 +64,9 @@ export type Callback = Function;
// deno-lint-ignore ban-types
export type FunctionWithSymbolName = Function & { symbolName: string };

type PointerBoxableValue<T> = T extends BoxValue ? (BoxArray<T> | Box<T>) : never;
export type PointerLike<T> = Pointer<T> | TypedArray | Struct | PointerBoxableValue<T>;
type PointerBoxValue<T> = T extends BoxValue ? Box<T> : never;
type PointerStructArray<T> = T extends AllocatableStruct ? StructArray<T> : never;
export type PointerLike<T> = Pointer<T> | TypedArray | Struct | PointerBoxValue<T> | PointerStructArray<T>;

//
// Complex types
Expand All @@ -82,7 +84,7 @@ export interface InitOptions {
functions?: ReadonlyArray<FunctionWithSymbolName>;
}

export interface StructConstructor<T extends Struct> {
export interface StructConstructor<T extends Struct> extends Constructor<T> {
of(data: Uint8Array | Pointer<T> | null, byteOffset?: number): T | null;
}

Expand Down

0 comments on commit 370b996

Please sign in to comment.