UNPKG

@radixdlt/atom

Version:

Container for CRUD instructions known as 'Particles' that are sent to the Radix decentralized ledger

263 lines (235 loc) 7.67 kB
import { AnyDownParticle, AnySpunParticle, AnyUpParticle, DownParticle, ParticleBase, Spin, SpunParticleT, SpunParticleBase, UpParticle, } from './_types' import { isSpin } from './meta/spin' import { err, ok, Result } from 'neverthrow' import { DSONEncoding, DSONPrimitive, JSONEncoding, taggedObjectDecoder, } from '@radixdlt/data-formats' import { SERIALIZER_KEY } from '../_types' import { JSONDecoding } from '../utils' const SERIALIZER = 'radix.spun_particle' const JSONDecoder = taggedObjectDecoder( SERIALIZER, SERIALIZER_KEY, )((input: SpunParticleBase) => ok(anySpunParticle(input))) const jsonDecoding = JSONDecoding.withDecoders(JSONDecoder).create< // eslint-disable-next-line @typescript-eslint/no-explicit-any SpunParticleT<any> >() /* eslint-disable max-params */ const anySpunParticlesEquals = ( lhs: SpunParticleBase, rhs: SpunParticleBase, ): boolean => { return ( lhs.spin === rhs.spin && lhs.particle.equals(rhs.particle) && rhs.particle.equals(lhs.particle) ) } /* eslint-enable max-params */ /** * Creates an AnySpunParticle (type-erased SpunParticle) with a specified spin. * * @param spunParticleBase {SpunParticleBase} A particle of any type of to give a spin. * @returns {AnySpunParticle} an AnySpunParticle (type-erased SpunParticle) with a specified spin. */ export const anySpunParticle = ( spunParticleBase: SpunParticleBase, ): AnySpunParticle => ({ ...spunParticleBase, ...JSONEncoding(SERIALIZER)({ particle: spunParticleBase.particle, spin: spunParticleBase.spin, }), ...DSONEncoding(SERIALIZER)({ particle: spunParticleBase.particle, spin: DSONPrimitive(spunParticleBase.spin), }), equals: (other: SpunParticleBase): boolean => anySpunParticlesEquals(spunParticleBase, other), downedAsAny: (): Result<AnyDownParticle, Error> => spunParticleBase.spin === Spin.UP ? ok(anyDownParticle(spunParticleBase.particle)) : err(new Error('Cannot down a particle with spin Down')), }) /** * Creates a typed SpunParticle with a specified spin. * * @param particle {P} A particle of typed type `P` to give a spin. * @param spin {Spin} The spun of the particle * @returns {SpunParticleT<P>} a typed SpunParticle with a specified spin. * @template P a specific type of particle, that **is a** `ParticleBase` */ export const spunParticle = <P extends ParticleBase>( input: Readonly<{ spin: Spin particle: P }>, ): SpunParticleT<P> => { const anySpun = anySpunParticle(input) return { ...anySpun, particle: input.particle, eraseToAny: () => anySpun, downed: (): Result<DownParticle<P>, Error> => input.spin === Spin.UP ? ok(downParticle(input.particle)) : err(new Error('Cannot down a particle with spin Down')), } } /** * Creates a typed UpParticle, a container for typed particle with the at compile time known Spin.UP. * * @param particle {P} A particle of typed type `P` to give the spin UP. * @returns {UpParticle<P>} a typed UpParticle, a container for typed particle with the at compile time known Spin.UP. * @template P a specific type of particle, that **is a** `ParticleBase` */ export const upParticle = <P extends ParticleBase>( particle: P, ): UpParticle<P> => { const spin = Spin.UP const spun = spunParticle({ particle, spin }) return { ...spun, spin, toSpunParticle: () => spun, eraseToAnyUp: () => anyUpParticle(particle), } } /** * Creates a typed DownParticle, a container for typed particle with the at compile time known Spin.Down. * * @param particle {P} A particle of typed type `P` to give the spin DOWN. * @returns {DownParticle<P>} a typed DownParticle, a container for typed particle with the at compile time known Spin.Down. * @template P a specific type of particle, that **is a** `ParticleBase` */ export const downParticle = <P extends ParticleBase>( particle: P, ): DownParticle<P> => { const spin = Spin.DOWN const spun = spunParticle({ particle, spin }) return { ...spun, spin, toSpunParticle: () => spun, eraseToAnyDown: () => anyDownParticle(particle), } } /** * Creates a typed SpunParticle with Spin.UP. * * @param particle {P} A particle of typed type `P` to give the spin UP. * @returns {SpunParticleT<P>} a typed SpunParticle with a spin UP. * @template P a specific type of particle, that **is a** `ParticleBase` */ export const spunUpParticle = <P extends ParticleBase>( particle: P, ): SpunParticleT<P> => upParticle(particle).toSpunParticle() /** * Creates a typed SpunParticle with Spin.DOWN. * * @param particle {P} A particle of typed type `P` to give the spin DOWN. * @returns {SpunParticleT<P>} a typed SpunParticle with a spin DOWN. * @template P a specific type of particle, that **is a** `ParticleBase` */ export const spunDownParticle = <P extends ParticleBase>( particle: P, ): SpunParticleT<P> => downParticle(particle).toSpunParticle() /** * Creates an AnyUpParticle (type-erased UpParticle) with the at compile time known spin UP. * * @param particle {ParticleBase} A particle of any type of to give the spin UP. * @returns {AnyUpParticle} an AnyUpParticle (type-erased UpParticle) with the at compile time known spin UP. */ export const anyUpParticle = (particle: ParticleBase): AnyUpParticle => { const spin = Spin.UP const anySpun = anySpunParticle({ particle, spin }) return { ...anySpun, spin, toAnySpunParticle: () => anySpun, } } /** * Creates an AnyDownParticle (type-erased DownParticle) with the at compile time known spin DOWN. * * @param particle {ParticleBase} A particle of any type of to give the spin DOWN. * @returns {AnyDownParticle} an AnyDownParticle (type-erased DownParticle) with the at compile time known spin DOWN. */ export const anyDownParticle = (particle: ParticleBase): AnyDownParticle => { const spin = Spin.DOWN const anySpun = anySpunParticle({ particle, spin }) return { ...anySpun, spin, toAnySpunParticle: () => anySpun, } } export const asAnyUpParticle = ( spunParticle: SpunParticleBase, ): Result<AnyUpParticle, Error> => { if (spunParticle.spin !== Spin.UP) { return err(new Error('Particle does not have spin UP.')) } return ok(anyUpParticle(spunParticle.particle)) } export const asAnyDownParticle = ( spunParticle: SpunParticleBase, ): Result<AnyDownParticle, Error> => { if (spunParticle.spin !== Spin.DOWN) { return err(new Error('Particle does not have spin DOWN.')) } return ok(anyDownParticle(spunParticle.particle)) } export const asUpParticle = <P extends ParticleBase>( spunParticle: SpunParticleT<P>, ): Result<UpParticle<P>, Error> => { if (spunParticle.spin !== Spin.UP) { return err(new Error('Particle does not have spin UP.')) } return ok(upParticle(spunParticle.particle)) } export const asDownParticle = <P extends ParticleBase>( spunParticle: SpunParticleT<P>, ): Result<DownParticle<P>, Error> => { if (spunParticle.spin !== Spin.DOWN) { return err(new Error('Particle does not have spin DOWN.')) } return ok(downParticle(spunParticle.particle)) } const isParticleBase = (something: unknown): something is ParticleBase => { const inspection = something as ParticleBase return inspection.equals !== undefined } // eslint-disable-next-line complexity export const isAnySpunParticle = ( something: unknown, ): something is AnySpunParticle => { const inspection = something as AnySpunParticle return ( inspection.spin !== undefined && isSpin(inspection.spin) && inspection.particle !== undefined && isParticleBase(inspection.particle) && inspection.equals !== undefined && inspection.downedAsAny() !== undefined ) } export const SpunParticle = { ...jsonDecoding, JSONDecoder, SERIALIZER, }