lib/src/support/bus/serial/SimpleCanonicalItemSerializer.ts

88 lines
3.1 KiB
TypeScript
Raw Normal View History

import {CanonicalItemClass} from '../../CanonicalReceiver'
import {BaseSerializer} from './BaseSerializer'
import {Awaitable, ErrorWithContext, JSONState, Rehydratable} from '../../../util'
import {Container, Inject, Injectable} from '../../../di'
import {Canon} from '../../../service/Canon'
import {ObjectSerializer} from './decorators'
/** State encoded by this class. */
export interface SimpleCanonicalItemSerialState extends JSONState {
rehydrate?: JSONState
canonicalIdentifier: string
}
/**
* A serializer implementation that serializes class instances derived from the Canon loading system.
* These instances must be CanonicalItemClass instances and take no constructor parameters.
* If the instance is Rehydratable, then the state will be (re-)stored.
*/
@ObjectSerializer()
@Injectable()
export class SimpleCanonicalItemSerializer<TActual extends CanonicalItemClass> extends BaseSerializer<TActual, SimpleCanonicalItemSerialState> {
@Inject()
protected readonly canon!: Canon
@Inject()
protected readonly container!: Container
protected decodeSerial(serial: SimpleCanonicalItemSerialState): Awaitable<TActual> {
const canon = this.canon.getFromFullyQualified(serial.canonicalIdentifier)
if ( !canon ) {
throw new ErrorWithContext('Unable to decode serialized payload: the canonical identifier was not found', {
serial,
})
}
if ( canon instanceof CanonicalItemClass ) {
if ( serial.rehydrate && typeof (canon as any).rehydrate === 'function' ) {
(canon as unknown as Rehydratable).rehydrate(serial.rehydrate)
}
return canon as TActual
} else if ( canon?.prototype instanceof CanonicalItemClass ) {
const inst = this.container.make(canon)
if ( serial.rehydrate && typeof (inst as any).rehydrate === 'function' ) {
(inst as unknown as Rehydratable).rehydrate(serial.rehydrate)
}
return inst as TActual
}
throw new ErrorWithContext('Attempted to instantiate serialized item into non-Canonical class', {
canon,
serial,
})
}
protected async encodeActual(actual: TActual): Promise<SimpleCanonicalItemSerialState> {
const ctor = actual.constructor as typeof CanonicalItemClass
const canonicalIdentifier = ctor.getFullyQualifiedCanonicalResolver()
if ( !canonicalIdentifier ) {
throw new ErrorWithContext('Unable to determine Canonical resolver for serialization.', [
actual,
])
}
const state: SimpleCanonicalItemSerialState = {
canonicalIdentifier,
}
if ( typeof (actual as any).dehydrate === 'function' ) {
state.rehydrate = await (actual as unknown as Rehydratable).dehydrate()
}
return state
}
protected getName(): string {
return '@extollo/lib:SimpleCanonicalItemSerializer'
}
matchActual(some: TActual): boolean {
return (
some instanceof CanonicalItemClass
&& some.constructor.length === 0
)
}
}