wgpu/src/utils/index.ts
2025-04-24 01:49:29 -05:00

128 lines
4.8 KiB
TypeScript

export type Optional<T, K extends keyof T> = Pick<Partial<T>, K & Omit<T, K>>
export type Only<T, U> = { [P in keyof T]: T[P] } & { [P in keyof U]?: never }
export type Either<T, U> = Only<T, U> | Only<U, T>
export interface Newable {
new(...args: any[]): any
}
export type TypedArray = Int8Array
| Uint8Array
| Uint8ClampedArray
| Int16Array
| Uint16Array
| Int32Array
| Uint32Array
| Float32Array
| Float64Array
| BigInt64Array
| BigUint64Array
export type TypedArrayConstructor = Int8ArrayConstructor
| Uint8ArrayConstructor
| Uint8ClampedArrayConstructor
| Int16ArrayConstructor
| Uint16ArrayConstructor
| Int32ArrayConstructor
| Uint32ArrayConstructor
| Float32ArrayConstructor
| Float64ArrayConstructor
| BigInt64ArrayConstructor
| BigUint64ArrayConstructor
export type PowersOfTwo = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512,
1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144,
524288, 1048576, 2097152, 4194304, 8388608, 16777216,
33554432, 67108864, 134217728, 268435456, 536870912, 1073741824,
2147483648]
export type PositiveInteger<T extends number> = `${T}` extends `-${string}` | '0' | `${string}.${string}` ? never : T
export type CapitalizeAll<T extends ReadonlyArray<string>> = T extends readonly [] ? [] : T extends readonly [infer Head extends string, ...infer Tail extends ReadonlyArray<string>] ? [Capitalize<Head>, ...CapitalizeAll<Tail>] : string[]
export type Join<T extends ReadonlyArray<string>, Sep extends string = ''> = T extends readonly [] ? '' : T extends readonly [infer Head] ? Head : T extends readonly [infer Head extends string, ...infer Tail extends ReadonlyArray<string>] ? `${Head}${Sep}${Join<Tail, Sep>}` : string
export type Split<S extends string, D extends string> = D extends '' ? [S] : S extends `${infer Head}${D}${infer Tail}` ? [Head, ...Split<Tail, D>] : [S]
export type PascalCaseFromDelimiter<S extends string, D extends string> = S extends `${infer Left}${D}${infer Right}` ? `${PascalCaseFromDelimiter<Left, D>}${Capitalize<PascalCaseFromDelimiter<Right, D>>}` : S
export type PascalCaseString<S extends string> = Capitalize<PascalCaseFromDelimiter<PascalCaseFromDelimiter<PascalCaseFromDelimiter<Lowercase<S>, '-'>, '_'>, ' '>>
export type PascalCase<T extends string | ReadonlyArray<string>> = T extends string ? PascalCaseString<T> : T extends ReadonlyArray<string> ? Join<CapitalizeAll<T>, ''> : T
export type IndexOf<T extends readonly any[], V, Acc extends any[] = []> = T extends readonly [infer Head, ...infer Tail]
? Head extends V ? Acc['length'] : IndexOf<Tail, V, [...Acc, Head]>
: never
export const uppercase = <T extends string>(s: T) => s.toUpperCase() as Uppercase<T>
export const lowercase = <T extends string>(s: T) => s.toLowerCase() as Lowercase<T>
export const split = <const T extends string, const D extends string>(delim: D, s: T) => s.split(delim) as Split<T, D>
export const fromKebab = <const T extends string>(s: T) => split('-', s) as Split<T, '-'>
export const toPascal = <const T extends string>(xs: T) => uppercase(xs[0]) + xs.slice(1) as PascalCase<T>
const pascal = <const T extends string[]>(xs: T) => xs.map(toPascal).join('') as PascalCase<T>
export const Enum = <const T extends string>(...values: T[]) => Object.freeze(
values.reduce((acc, x) => {
const key = pascal(fromKebab(x)).toString()
acc[key] = x
return acc
}, {})
) as Readonly<{ [K in T as PascalCase<K>]: K }>
type ParseInt<T> = T extends `${infer N extends number}` ? N : never
type FlagEnum<T extends string, A extends T[]> = Readonly<{ [K in keyof A as A[K] extends T ? PascalCase<A[K]> : never]: PowersOfTwo[ParseInt<K>] }>
export const FlagEnum = <const T extends string, const A extends T[]>(...values: A) => Object.freeze(
values.reduce((acc, x, i) => {
const key = pascal(fromKebab(x)).toString()
acc[key] = 1 << i
return acc
}, {})
) as FlagEnum<T, A>
export const pick = <T extends object, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K> => (Object.fromEntries(
keys
.filter(key => key in obj)
.map(key => [key, obj[key]])
)) as Pick<T, K>
export const inclusivePick = <T extends object, K extends keyof T>(obj: T, ...keys: K[]) => Object.fromEntries(
keys.map(key => [key, obj[key]])
) as { [Key in K]: Key extends keyof T ? T[Key] : never }
export const omit = <T extends object, K extends keyof T>(obj: T, ...keys: K[]) => Object.fromEntries(
Object.entries(obj)
.filter(([key]: K[]) => !keys.includes(key))
) as Omit<T, K>
export class Flags {
_value: number
constructor(value: number) {
this._value = value
}
static has(flag: number, bitflags: number) {
return bitflags & flag
}
static add(a: number, b: number) {
return a | b
}
has(flag: number) {
return Flags.has(flag, this._value)
}
add(flag: number) {
return Flags.add(flag, this._value)
}
}