Skip to content

Commit

Permalink
fix: misc (#164)
Browse files Browse the repository at this point in the history
  • Loading branch information
tjjfvi committed Jun 29, 2023
1 parent 4f5f85a commit 3f30d42
Show file tree
Hide file tree
Showing 10 changed files with 41 additions and 37 deletions.
11 changes: 6 additions & 5 deletions codecs/compact.ts
@@ -1,4 +1,5 @@
import { Codec, CodecVisitor, createCodec, metadata, ScaleDecodeError, withMetadata } from "../common/mod.ts"
import { AnyCodec } from "../mod.ts"
import { constant } from "./constant.ts"
import { u128, u16, u256, u32, u64, u8 } from "./int.ts"
import { field, object } from "./object.ts"
Expand All @@ -8,10 +9,10 @@ const MAX_U6 = 0b00111111
const MAX_U14 = 0b00111111_11111111
const MAX_U30 = 0b00111111_11111111_11111111_11111111

export const compactVisitor = new CodecVisitor<Codec<any>>()
export const compactVisitor = new CodecVisitor<AnyCodec>()

export function compact<T>(codec: Codec<T>): Codec<T> {
return compactVisitor.visit(codec)
export function compact<I, O>(codec: Codec<I, O>): Codec<I, O> {
return compactVisitor.visit(codec) as any
}

function compactNumber($base: Codec<number>): Codec<number> {
Expand Down Expand Up @@ -120,10 +121,10 @@ compactVisitor.add(constant<any>, (codec) => codec)
compactVisitor.add(tuple<any[]>, (codec, ...entries) => {
if (entries.length === 0) return codec
if (entries.length > 1) throw new Error("Cannot derive compact codec for tuples with more than one field")
return withMetadata(metadata("$.compact", compact<any>, codec), tuple(compact(entries[0]!)))
return withMetadata(metadata("$.compact", compact<any, any>, codec), tuple(compact(entries[0]!)))
})

compactVisitor.add(field<any, any>, (codec, key, value) => {
compactVisitor.add(field<any, any, any>, (codec, key, value) => {
return withMetadata(metadata("$.compact", compact, codec), field(key, compact(value)))
})

Expand Down
10 changes: 5 additions & 5 deletions codecs/instance.ts
@@ -1,10 +1,10 @@
import { AssertState } from "../common/assert.ts"
import { Codec, createCodec, metadata } from "../common/mod.ts"

export function instance<A extends unknown[], O extends I, I = O>(
ctor: new(...args: A) => O,
$args: Codec<A>,
toArgs: (value: I) => [...A],
export function instance<AI extends readonly unknown[], AO extends readonly unknown[], I, O>(
ctor: new(...args: AO) => O,
$args: Codec<AI, AO>,
toArgs: (value: I) => [...AI],
): Codec<I, O> {
return createCodec({
_metadata: metadata("$.instance", instance, ctor, $args, toArgs),
Expand All @@ -17,7 +17,7 @@ export function instance<A extends unknown[], O extends I, I = O>(
},
_assert(assert) {
assert.instanceof(this, ctor)
$args._assert(new AssertState(toArgs(assert.value as O), "#arguments", assert))
$args._assert(new AssertState(toArgs(assert.value as I), "#arguments", assert))
},
})
}
13 changes: 7 additions & 6 deletions codecs/object.ts
Expand Up @@ -2,9 +2,9 @@ import { AnyCodec, Codec, CodecVisitor, createCodec, Expand, Input, metadata, Ou
import { constant } from "./constant.ts"
import { option } from "./option.ts"

export function field<K extends keyof any, V>(key: K, $value: Codec<V>): Codec<
Expand<Readonly<Record<K, V>>>,
Expand<Record<K, V>>
export function field<K extends keyof any, VI, VO>(key: K, $value: Codec<VI, VO>): Codec<
Expand<Readonly<Record<K, VI>>>,
Expand<Record<K, VO>>
> {
return createCodec({
_metadata: metadata("$.field", field, key, $value),
Expand All @@ -21,9 +21,9 @@ export function field<K extends keyof any, V>(key: K, $value: Codec<V>): Codec<
})
}

export function optionalField<K extends keyof any, V>(key: K, $value: Codec<V>): Codec<
Expand<Readonly<Partial<Record<K, V>>>>,
Expand<Partial<Record<K, V>>>
export function optionalField<K extends keyof any, VI, VO>(key: K, $value: Codec<VI, VO>): Codec<
Expand<Readonly<Partial<Record<K, VI>>>>,
Expand<Partial<Record<K, VO>>>
> {
const $option = option($value)
return createCodec({
Expand Down Expand Up @@ -70,6 +70,7 @@ type UnionKeys<T> = T extends T ? keyof T : never
export type ObjectMembers<T extends AnyCodec[]> = [
...never extends T ? {
[K in keyof T]:
AnyCodec extends T[K] ? AnyCodec :
& UnionKeys<Input<T[K]>>
& {
[L in keyof T]: K extends L ? never : UnionKeys<Input<T[L]>>
Expand Down
2 changes: 1 addition & 1 deletion codecs/test/instance.test.ts
Expand Up @@ -27,7 +27,7 @@ const $myError = $.withMetadata(
$.field("c", $.bool),
),
),
(myError) => [myError.code, myError.message, myError.payload],
(myError: MyError) => [myError.code, myError.message, myError.payload],
),
)

Expand Down
2 changes: 1 addition & 1 deletion codecs/test/result.test.ts
Expand Up @@ -8,7 +8,7 @@ class StrErr extends Error {
}
}

const $strError = $.instance(StrErr, $.tuple($.str), (err) => [err.str])
const $strError = $.instance(StrErr, $.tuple($.str), (err: StrErr) => [err.str])

testCodec($.result($.str, $strError), [
"ok",
Expand Down
4 changes: 2 additions & 2 deletions codecs/tuple.ts
@@ -1,9 +1,9 @@
import { AnyCodec, Codec, createCodec, Input, metadata, Output } from "../common/mod.ts"

type InputTuple<T extends AnyCodec[]> = {
export type InputTuple<T extends AnyCodec[]> = {
readonly [K in keyof T]: Input<T[K]>
}
type OutputTuple<T extends AnyCodec[]> = {
export type OutputTuple<T extends AnyCodec[]> = {
[K in keyof T]: Output<T[K]>
}

Expand Down
20 changes: 11 additions & 9 deletions codecs/union.ts
Expand Up @@ -7,6 +7,8 @@ export class Variant<T extends string, I, O> {
constructor(readonly tag: T, readonly codec: Codec<I, O>) {}
}

export type AnyVariant = Variant<any, never, unknown>

export function variant<T extends string, E extends AnyCodec[]>(
tag: T,
...members: ObjectMembers<E>
Expand All @@ -16,29 +18,29 @@ export function variant<T extends string, E extends AnyCodec[]>(

export type InputTaggedUnion<
K extends keyof any,
M extends Record<number, Variant<any, any, any>>,
M extends Record<number, AnyVariant>,
> = {
[I in keyof M]: Expand<
& Readonly<Record<K, Extract<M[I], Variant<any, any, any>>["tag"]>>
& Input<Extract<M[I], Variant<any, any, any>>["codec"]>
& Readonly<Record<K, Extract<M[I], AnyVariant>["tag"]>>
& Input<Extract<M[I], AnyVariant>["codec"]>
>
}[keyof M & number]
export type OutputTaggedUnion<
K extends keyof any,
M extends Record<number, Variant<any, any, any>>,
M extends Record<number, AnyVariant>,
> = {
[I in keyof M]: Expand<
& Record<K, Extract<M[I], Variant<any, any, any>>["tag"]>
& Output<Extract<M[I], Variant<any, any, any>>["codec"]>
& Record<K, Extract<M[I], AnyVariant>["tag"]>
& Output<Extract<M[I], AnyVariant>["codec"]>
>
}[keyof M & number]

export function taggedUnion<
K extends keyof any,
M extends [] | Record<number, Variant<any, any, any>>,
M extends [] | Record<number, Variant<any, never, unknown>>,
>(tagKey: K, members: M): Codec<InputTaggedUnion<K, M>, OutputTaggedUnion<K, M>> {
const tagToDiscriminant: Record<string, number> = Object.create(null)
const discriminantToMember: Record<number, Codec<any>> = Object.create(null)
const discriminantToMember: Record<number, AnyCodec> = Object.create(null)
for (const _discriminant in members) {
const discriminant = +_discriminant
if (isNaN(discriminant)) continue
Expand All @@ -61,7 +63,7 @@ export function taggedUnion<
if (!$member) {
throw new ScaleDecodeError(this, buffer, `No such member codec matching the discriminant \`${discriminant}\``)
}
return $member._decode(buffer)
return $member._decode(buffer) as any
},
_assert(assert) {
const assertTag = assert.key(this, tagKey)
Expand Down
4 changes: 2 additions & 2 deletions common/codec.ts
Expand Up @@ -35,7 +35,7 @@ export function withMetadata<I, O>(metadata: Metadata<NoInfer<I>, NoInfer<O>>, c
return result
}

const codecInspectCtx = new Map<Codec<any>, number | null>()
const codecInspectCtx = new Map<AnyCodec, number | null>()
let codecInspectIdN = 0
const nodeCustomInspect = Symbol.for("nodejs.util.inspect.custom")
const denoCustomInspect = Symbol.for("Deno.customInspect")
Expand All @@ -51,7 +51,7 @@ abstract class _Codec {

// Properly handles circular codecs in the case of $.deferred
private _inspect(inspect: (value: unknown) => string): string
private _inspect<T>(this: Codec<T>, inspect: (value: unknown) => string): string {
private _inspect(this: AnyCodec, inspect: (value: unknown) => string): string {
let id = codecInspectCtx.get(this)
if (id !== undefined) {
if (id === null) {
Expand Down
10 changes: 5 additions & 5 deletions common/metadata.ts
Expand Up @@ -64,11 +64,11 @@ export function docs<I = any, O = any>(docs: string): Metadata<I, O> {
}

export class CodecVisitor<R> {
#fallback?: <T>(codec: Codec<T>) => R
#fallback?: <I, O>(codec: Codec<I, O>) => R
#visitors = new Map<Metadata<any, any>[number] | Function, (codec: Codec<any>, ...args: any[]) => R>()

add<T, A extends unknown[]>(codec: (...args: A) => Codec<T>, fn: (codec: Codec<T>, ...args: A) => R): this
add<T>(codec: Codec<T>, fn: (codec: Codec<T>) => R): this
add<I, O, A extends unknown[]>(codec: (...args: A) => Codec<I, O>, fn: (codec: Codec<I, O>, ...args: A) => R): this
add<I, O>(codec: Codec<I, O>, fn: (codec: Codec<I, O>) => R): this
add(codec: Codec<any> | Metadata<any, any>[number] | Function, fn: (codec: Codec<any>, ...args: any[]) => R): this {
if (codec instanceof Codec) {
codec = codec._metadata[0]!
Expand All @@ -81,7 +81,7 @@ export class CodecVisitor<R> {
return this
}

fallback(fn: <T>(codec: Codec<T>) => R): this {
fallback(fn: <I, O>(codec: Codec<I, O>) => R): this {
if (this.#fallback) {
throw new Error("Duplicate fallback")
}
Expand All @@ -103,7 +103,7 @@ export class CodecVisitor<R> {
return this
}

visit<T>(codec: Codec<T>): R {
visit<I, O>(codec: Codec<I, O>): R {
for (const metadata of codec._metadata) {
let visitor = this.#visitors.get(metadata)
if (visitor) return visitor(codec)
Expand Down
2 changes: 1 addition & 1 deletion examples/objects.eg.ts
Expand Up @@ -25,7 +25,7 @@ class MyError extends Error {
export const $myError = $.instance(
MyError,
$.tuple($.u8, $.str), // Specify how to encode/decode constructor arguments
(myError) => [myError.code, myError.message], // Specify how to extract arguments from an instance
(myError: MyError) => [myError.code, myError.message], // Specify how to extract arguments from an instance
)

$myError // Codec<MyError>

0 comments on commit 3f30d42

Please sign in to comment.