import { Provable, ProvableHashable, ProvablePure, ProvableType, ToProvable, } from './provable-intf.js'; import type { Field } from '../wrapped.js'; import { createDerivers, NonMethods, InferProvable as GenericInferProvable, InferJson, InferredProvable as GenericInferredProvable, IsPure as GenericIsPure, NestedProvable as GenericNestedProvable, createHashInput, Constructor, InferValue, InferJsonNested, InferValueNested, InferProvableNested, } from '../../../bindings/lib/provable-generic.js'; import { Tuple } from '../../util/types.js'; import { GenericHashInput } from '../../../bindings/lib/generic.js'; // external API export { ProvableExtended, ProvableInferPureFrom, provable, provablePure, provableTuple, provableFromClass, provableExtends, }; // internal API export { NonMethods, HashInput, InferProvable, InferProvableType, InferJson, InferredProvable, IsPure, NestedProvable, mapValue, }; type ProvableExtension = { toInput: (x: T) => { fields?: Field[]; packed?: [Field, number][] }; toJSON: (x: T) => TJson; fromJSON: (x: TJson) => T; empty: () => T; }; type ProvableExtended = Provable & ProvableExtension; type ProvablePureExtended = ProvablePure & ProvableExtension; type InferProvable = GenericInferProvable; type InferProvableType = InferProvable>; type InferredProvable = GenericInferredProvable; type IsPure = GenericIsPure; type ProvableInferPureFrom = IsPure extends true ? ProvablePure : Provable; type HashInput = GenericHashInput; const HashInput = createHashInput(); type NestedProvable = GenericNestedProvable; const { provable } = createDerivers(); function provablePure( typeObj: A ): ProvablePureExtended, InferValue, InferJson> { return provable(typeObj, { isPure: true }) as any; } function provableTuple>(types: T): InferredProvable { return provable(types) as any; } function provableFromClass< A extends NestedProvable, T extends InferProvableNested, V extends InferValueNested, J extends InferJsonNested, >( Class: Constructor & { check?: (x: T) => void; empty?: () => T }, typeObj: A ): IsPure extends true ? ProvablePureExtended : ProvableExtended { let raw: ProvableExtended = provable(typeObj) as any; return { sizeInFields: raw.sizeInFields, toFields: raw.toFields, toAuxiliary: raw.toAuxiliary, fromFields(fields, aux) { return construct(Class, raw.fromFields(fields, aux)); }, check(value) { if (Class.check !== undefined) { Class.check(value); } else { raw.check(value); } }, toValue: raw.toValue, fromValue(x) { return construct(Class, raw.fromValue(x)); }, toInput: raw.toInput, toJSON: raw.toJSON, fromJSON(x) { return construct(Class, raw.fromJSON(x)); }, empty() { return Class.empty !== undefined ? Class.empty() : construct(Class, raw.empty()); }, } satisfies ProvableExtended as any; } function construct(Class: Constructor, value: Raw): T { let instance = Object.create(Class.prototype); return Object.assign(instance, value); } function provableExtends, T extends InferProvable, S extends T>( S: new (t: T) => S, base: A ) { return { sizeInFields() { return base.sizeInFields(); }, toFields(value: S | T) { return base.toFields(value); }, toAuxiliary(value?: S | T) { return base.toAuxiliary(value); }, fromFields(fields, aux) { return new S(base.fromFields(fields, aux)); }, check(value: S | T) { base.check(value); }, toValue(value: S | T) { return base.toValue(value); }, fromValue(value) { return new S(base.fromValue(value)); }, empty() { return new S(base.empty()); }, toInput(value: S | T) { return base.toInput(value); }, } satisfies ProvableHashable>; } function mapValue< A extends ProvableHashable, V extends InferValue, W, T extends InferProvable, >(provable: A, there: (x: V) => W, back: (x: W | T) => V | T): ProvableHashable { return { sizeInFields() { return provable.sizeInFields(); }, toFields(value) { return provable.toFields(value); }, toAuxiliary(value) { return provable.toAuxiliary(value); }, fromFields(fields, aux) { return provable.fromFields(fields, aux); }, check(value) { provable.check(value); }, toValue(value) { return there(provable.toValue(value)); }, fromValue(value) { return provable.fromValue(back(value)); }, empty() { return provable.empty(); }, toInput(value) { return provable.toInput(value); }, }; }