-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Can now estimate the max value of a schema.
- Loading branch information
Showing
9 changed files
with
231 additions
and
160 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ export { | |
u32, | ||
f32, | ||
string, | ||
MaxValue, | ||
Ref, | ||
IRefResolver, | ||
Schema, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,92 +1,113 @@ | ||
import { Parsed } from '..'; | ||
import { TypedBinaryError } from '../error'; | ||
import { ISerialInput, ISerialOutput } from '../io'; | ||
import { IRefResolver, ISchema, IStableSchema, Keyed, Ref } from './types'; | ||
import { | ||
IRefResolver, | ||
ISchema, | ||
IStableSchema, | ||
Keyed, | ||
Ref, | ||
MaxValue, | ||
} from './types'; | ||
|
||
class RefSchema<K extends string> implements IStableSchema<Ref<K>> { | ||
public readonly _infered!: Ref<K>; | ||
public readonly ref: Ref<K>; | ||
|
||
constructor(key: K) { | ||
this.ref = new Ref(key); | ||
} | ||
|
||
resolve(): void { | ||
throw new TypedBinaryError(`Tried to resolve a reference directly. Do it through a RefResolver instead.`); | ||
} | ||
|
||
read(): Ref<K> { | ||
throw new TypedBinaryError(`Tried to read a reference directly. Resolve it instead.`); | ||
} | ||
|
||
write(): void { | ||
throw new TypedBinaryError(`Tried to write a reference directly. Resolve it instead.`); | ||
} | ||
|
||
sizeOf(): number { | ||
throw new TypedBinaryError(`Tried to estimate size of a reference directly. Resolve it instead.`); | ||
} | ||
public readonly _infered!: Ref<K>; | ||
public readonly ref: Ref<K>; | ||
|
||
constructor(key: K) { | ||
this.ref = new Ref(key); | ||
} | ||
|
||
resolve(): void { | ||
throw new TypedBinaryError( | ||
`Tried to resolve a reference directly. Do it through a RefResolver instead.`, | ||
); | ||
} | ||
|
||
read(): Ref<K> { | ||
throw new TypedBinaryError( | ||
`Tried to read a reference directly. Resolve it instead.`, | ||
); | ||
} | ||
|
||
write(): void { | ||
throw new TypedBinaryError( | ||
`Tried to write a reference directly. Resolve it instead.`, | ||
); | ||
} | ||
|
||
sizeOf(): number { | ||
throw new TypedBinaryError( | ||
`Tried to estimate size of a reference directly. Resolve it instead.`, | ||
); | ||
} | ||
} | ||
|
||
class RefResolve implements IRefResolver { | ||
private registry: {[key: string]: IStableSchema<unknown>} = {}; | ||
|
||
hasKey(key: string): boolean { | ||
return this.registry[key] !== undefined; | ||
private registry: { [key: string]: IStableSchema<unknown> } = {}; | ||
|
||
hasKey(key: string): boolean { | ||
return this.registry[key] !== undefined; | ||
} | ||
|
||
register<K extends string>(key: K, schema: IStableSchema<unknown>): void { | ||
this.registry[key] = schema; | ||
} | ||
|
||
resolve<T>(unstableSchema: ISchema<T>): IStableSchema<T> { | ||
if (unstableSchema instanceof RefSchema) { | ||
const ref = unstableSchema.ref; | ||
const key = ref.key as string; | ||
if (this.registry[key] !== undefined) { | ||
return this.registry[key] as IStableSchema<T>; | ||
} | ||
|
||
throw new TypedBinaryError( | ||
`Couldn't resolve reference to ${key}. Unknown key.`, | ||
); | ||
} | ||
|
||
register<K extends string>(key: K, schema: IStableSchema<unknown>): void { | ||
this.registry[key] = schema; | ||
} | ||
|
||
resolve<T>(unstableSchema: ISchema<T>): IStableSchema<T> { | ||
if (unstableSchema instanceof RefSchema) { | ||
const ref = unstableSchema.ref; | ||
const key = ref.key as string; | ||
if (this.registry[key] !== undefined) { | ||
return this.registry[key] as IStableSchema<T>; | ||
} | ||
|
||
throw new TypedBinaryError(`Couldn't resolve reference to ${key}. Unknown key.`); | ||
} | ||
// Since it's not a RefSchema, we assume it can be resolved. | ||
(unstableSchema as IStableSchema<T>).resolve(this); | ||
|
||
// Since it's not a RefSchema, we assume it can be resolved. | ||
(unstableSchema as IStableSchema<T>).resolve(this); | ||
|
||
return unstableSchema as IStableSchema<T>; | ||
} | ||
return unstableSchema as IStableSchema<T>; | ||
} | ||
} | ||
|
||
export class KeyedSchema<K extends string, S extends IStableSchema<unknown>> implements ISchema<Keyed<K, S>> { | ||
public readonly _infered!: Keyed<K, S>; | ||
public innerType: S; | ||
export class KeyedSchema<K extends string, S extends IStableSchema<unknown>> | ||
implements ISchema<Keyed<K, S>> | ||
{ | ||
public readonly _infered!: Keyed<K, S>; | ||
public innerType: S; | ||
|
||
constructor(public readonly key: K, innerResolver: (ref: ISchema<Ref<K>>) => S) { | ||
this.innerType = innerResolver(new RefSchema(key)); | ||
this._infered = new Keyed(key, this.innerType); | ||
constructor( | ||
public readonly key: K, | ||
innerResolver: (ref: ISchema<Ref<K>>) => S, | ||
) { | ||
this.innerType = innerResolver(new RefSchema(key)); | ||
this._infered = new Keyed(key, this.innerType); | ||
|
||
// Automatically resolving after keyed creation. | ||
this.resolve(new RefResolve()); | ||
} | ||
// Automatically resolving after keyed creation. | ||
this.resolve(new RefResolve()); | ||
} | ||
|
||
resolve(ctx: IRefResolver): void { | ||
if (!ctx.hasKey(this.key)) { | ||
ctx.register(this.key, this.innerType); | ||
resolve(ctx: IRefResolver): void { | ||
if (!ctx.hasKey(this.key)) { | ||
ctx.register(this.key, this.innerType); | ||
|
||
this.innerType.resolve(ctx); | ||
} | ||
this.innerType.resolve(ctx); | ||
} | ||
} | ||
|
||
read(input: ISerialInput): Parsed<S> { | ||
return this.innerType.read(input) as Parsed<S>; | ||
} | ||
read(input: ISerialInput): Parsed<S> { | ||
return this.innerType.read(input) as Parsed<S>; | ||
} | ||
|
||
write(output: ISerialOutput, value: Parsed<S>): void { | ||
this.innerType.write(output, value); | ||
} | ||
write(output: ISerialOutput, value: Parsed<S>): void { | ||
this.innerType.write(output, value); | ||
} | ||
|
||
sizeOf(value: Parsed<S>): number { | ||
return this.innerType.sizeOf(value); | ||
} | ||
sizeOf(value: Parsed<S> | typeof MaxValue): number { | ||
return this.innerType.sizeOf(value); | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,49 @@ | ||
import type { ISerialInput, ISerialOutput } from '../io'; | ||
import { IRefResolver, ISchema, IStableSchema, Schema } from './types'; | ||
import { | ||
IRefResolver, | ||
ISchema, | ||
IStableSchema, | ||
MaxValue, | ||
Schema, | ||
} from './types'; | ||
|
||
export class OptionalSchema<T> extends Schema<T|undefined> { | ||
private innerSchema: IStableSchema<T>; | ||
export class OptionalSchema<T> extends Schema<T | undefined> { | ||
private innerSchema: IStableSchema<T>; | ||
|
||
constructor(private readonly _innerUnstableSchema: ISchema<T>) { | ||
super(); | ||
constructor(private readonly _innerUnstableSchema: ISchema<T>) { | ||
super(); | ||
|
||
// In case this optional isn't part of a keyed chain, | ||
// let's assume the inner type is stable. | ||
this.innerSchema = _innerUnstableSchema as IStableSchema<T>; | ||
} | ||
// In case this optional isn't part of a keyed chain, | ||
// let's assume the inner type is stable. | ||
this.innerSchema = _innerUnstableSchema as IStableSchema<T>; | ||
} | ||
|
||
resolve(ctx: IRefResolver): void { | ||
this.innerSchema = ctx.resolve(this._innerUnstableSchema); | ||
} | ||
resolve(ctx: IRefResolver): void { | ||
this.innerSchema = ctx.resolve(this._innerUnstableSchema); | ||
} | ||
|
||
write(output: ISerialOutput, value: T|undefined): void { | ||
if (value !== undefined && value !== null) { | ||
output.writeBool(true); | ||
this.innerSchema.write(output, value); | ||
} | ||
else { | ||
output.writeBool(false); | ||
} | ||
write(output: ISerialOutput, value: T | undefined): void { | ||
if (value !== undefined && value !== null) { | ||
output.writeBool(true); | ||
this.innerSchema.write(output, value); | ||
} else { | ||
output.writeBool(false); | ||
} | ||
} | ||
|
||
read(input: ISerialInput): T|undefined { | ||
const valueExists = input.readBool(); | ||
|
||
if (valueExists) { | ||
return this.innerSchema.read(input); | ||
} | ||
|
||
return undefined; | ||
} | ||
read(input: ISerialInput): T | undefined { | ||
const valueExists = input.readBool(); | ||
|
||
sizeOf(value: T|undefined): number { | ||
if (value === undefined) | ||
return 1; | ||
|
||
return 1 + this.innerSchema.sizeOf(value); | ||
if (valueExists) { | ||
return this.innerSchema.read(input); | ||
} | ||
|
||
return undefined; | ||
} | ||
|
||
sizeOf(value: T | undefined | typeof MaxValue): number { | ||
if (value === undefined) return 1; | ||
|
||
return 1 + this.innerSchema.sizeOf(value); | ||
} | ||
} |
Oops, something went wrong.