Skip to content

Commit

Permalink
Optimize Code Generation for Refinements
Browse files Browse the repository at this point in the history
  • Loading branch information
sinclairzx81 committed Apr 20, 2024
1 parent 224af7c commit 88ed430
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 7 deletions.
16 changes: 12 additions & 4 deletions example/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,18 @@ const Byte = Type.Refine(UnsafeByte)
.Check((value) => value < 256)
.Done()

console.log(Value.Check(Byte, 0)) // false
console.log(Value.Check(Byte, 255)) // false
console.log(Value.Check(Byte, -1)) // true
console.log(Value.Check(Byte, NaN)) // true
const A = Type.Object({
x: Byte,
y: Byte,
z: Byte,
})

console.log(Byte)
console.log(TypeCompiler.Code(A))
console.log(Value.Check(A, { x: 0, y: 0, z: 0 }))
console.log(Value.Check(Byte, 255))
console.log(Value.Check(Byte, -1))
console.log(Value.Check(Byte, NaN))

// Todo: Error Tests
// Todo: Investigate Error Propogation for Refinements
17 changes: 14 additions & 3 deletions src/compiler/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -457,10 +457,21 @@ export namespace TypeCompiler {
yield `kind('${schema[Kind]}', ${instance}, ${value})`
}
function* FromRefine(schema: { [RefineKind]: Refinement[] }, references: TSchema[], value: string): IterableIterator<string> {
// Optimization: Refine functions may be called multiple times on the same type. This occurs
// if a type with refinements is embedded multiple times within the compiled type. Rather than
// generating duplicate entries in the refinement map, we can test if the refinement check
// function is already stored, if so, we return the instance key, otherwise create.
function ResolveRefinement(refinement: Refinement): number {
for (const [key, existing] of state.refinements) {
if (existing.check === refinement.check) return key
}
const key = state.refinements.size
state.refinements.set(key, refinement)
return key
}
for (const refinement of schema[RefineKind]) {
const instance = state.refinements.size
state.refinements.set(instance, refinement)
yield `refine(${instance}, ${value})`
const key = ResolveRefinement(refinement)
yield `refine(${key}, ${value})`
}
}
function* Visit(schema: TSchema, references: TSchema[], value: string, useHoisting: boolean = true): IterableIterator<string> {
Expand Down

0 comments on commit 88ed430

Please sign in to comment.