import { Encoder, Preservable } from "./encoder"; import { Tag } from "./constants"; import { AsPreserve, PreserveOn } from "./symbols"; import { Value } from "./values"; import { GenericEmbedded } from "./embedded"; export type FloatType = 'Single' | 'Double'; export const FloatType = Symbol.for('FloatType'); export abstract class Float { readonly value: number; constructor(value: number | Float) { this.value = typeof value === 'number' ? value : value.value; } toString() { return this.asPreservesText(); } equals(other: any): boolean { return Object.is(other.constructor, this.constructor) && (other.value === this.value); } hashCode(): number { return (this.value | 0); // TODO: something better? } abstract asPreservesText(): string; abstract get [FloatType](): FloatType; static isFloat = (x: any): x is Float => x?.[FloatType] !== void 0; static isSingle = (x: any): x is SingleFloat => x?.[FloatType] === 'Single'; static isDouble = (x: any): x is DoubleFloat => x?.[FloatType] === 'Double'; } export function floatValue(f: any): number { if (typeof f === 'number') { return f; } else if (Float.isFloat(f)) { return f.value; } else { return NaN; } } export class SingleFloat extends Float implements Preservable { [AsPreserve](): Value { return this; } [PreserveOn](encoder: Encoder) { encoder.state.emitbyte(Tag.Float); encoder.state.makeroom(4); encoder.state.view.setFloat32(encoder.state.index, this.value, false); encoder.state.index += 4; } get [FloatType](): 'Single' { return 'Single'; } asPreservesText(): string { return '' + this.value + 'f'; } } export function Single(value: number | Float): SingleFloat { return new SingleFloat(value); } export class DoubleFloat extends Float implements Preservable { [AsPreserve](): Value { return this; } [PreserveOn](encoder: Encoder) { encoder.state.emitbyte(Tag.Double); encoder.state.makeroom(8); encoder.state.view.setFloat64(encoder.state.index, this.value, false); encoder.state.index += 8; } get [FloatType](): 'Double' { return 'Double'; } asPreservesText(): string { return '' + this.value; } } export function Double(value: number | Float): DoubleFloat { return new DoubleFloat(value); }