import { Tag } from "./constants"; import { stringify } from "./text"; import { Value } from "./values"; import type { GenericEmbedded } from "./embedded"; import type { Encoder, Preservable } from "./encoder"; import type { Writer, PreserveWritable } from "./writer"; 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 stringify(this); } 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 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, PreserveWritable { __as_preserve__(): Value { return this; } static __from_preserve__(v: Value): undefined | SingleFloat { return Float.isSingle(v) ? v : void 0; } __preserve_on__(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; } __preserve_text_on__(w: Writer) { w.state.pieces.push('' + this.value + 'f'); } get [FloatType](): 'Single' { return 'Single'; } } export function Single(value: number | Float): SingleFloat { return new SingleFloat(value); } export class DoubleFloat extends Float implements Preservable, PreserveWritable { __as_preserve__(): Value { return this; } static __from_preserve__(v: Value): undefined | DoubleFloat { return Float.isDouble(v) ? v : void 0; } __preserve_on__(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; } __preserve_text_on__(w: Writer) { w.state.pieces.push('' + this.value); } get [FloatType](): 'Double' { return 'Double'; } } export function Double(value: number | Float): DoubleFloat { return new DoubleFloat(value); }