import { Value } from "./Value"; import { Option } from "./Option"; import { Vector } from "./Vector"; import { LinkedList, ConsLinkedList } from "./LinkedList"; import { WithEquality, areEqual, getHashCode } from "./Comparison"; import { toStringHelper } from "./SeqHelpers"; import { contractTrueEquality } from "./Contract"; /** * Contains a pair of two values, which may or may not have the same type. * Compared to the builtin typescript [T,U] type, we get equality semantics * and helper functions (like mapping and so on). * @param T the first item type * @param U the second item type */ export class Tuple2 implements Value { private constructor(private _fst: T, private _snd: U) {} /** * Build a pair of value from both values. */ static of(fst: T, snd: U) { return new Tuple2(fst,snd); } /** * Build a tuple2 from javascript array. Compared to [[Tuple2.ofPair]], * it checks the length of the array and will return [[None]] in case * the length isn't two. However the types of the elements aren't checked. */ static ofArray(pair: Array): Option> { if (pair && pair.length === 2) { return Option.of(new Tuple2(pair[0], pair[1])); } return Option.none>(); } /** * Build a tuple2 from javascript pair. * Also see [[Tuple2.ofArray]] */ static ofPair(pair: [T, U]): Tuple2 { return new Tuple2(pair[0], pair[1]); } /** * @hidden */ hasTrueEquality(): boolean { return Option.of(this.fst()).hasTrueEquality() && Option.of(this.snd()).hasTrueEquality(); } /** * Extract the first value from the pair */ fst(): T { return this._fst; } /** * Extract the second value from the pair */ snd(): U { return this._snd; } /** * Maps the first component of this tuple to a new value. */ map1(fn: (v:T)=>V): Tuple2 { return new Tuple2(fn(this._fst), this._snd); } /** * Maps the second component of this tuple to a new value. */ map2(fn: (v:U)=>V): Tuple2 { return new Tuple2(this._fst, fn(this._snd)); } /** * Make a new tuple by mapping both values inside this one. */ map(fn: (a:T,b:U)=> Tuple2): Tuple2 { return fn(this._fst, this._snd); } /** * Transform this value to another value type. * Enables fluent-style programming by chaining calls. */ transform(converter:(x:Tuple2)=>V): V { return converter(this); } /** * Two objects are equal if they represent the same value, * regardless of whether they are the same object physically * in memory. */ equals(other: Tuple2): boolean { if (other === this) { return true; } if (!other || !other._fst) { return false; } contractTrueEquality("Tuple2.equals", this, other); return areEqual(this._fst, other._fst) && areEqual(this._snd, other._snd); } /** * Get a number for that object. Two different values * may get the same number, but one value must always get * the same number. The formula can impact performance. */ hashCode(): number { return getHashCode(this._fst)*53 + getHashCode(this._snd); } /** * Convert the tuple to a javascript pair. * Compared to [[Tuple2.toArray]], it behaves the * same at runtime, the only difference is the * typescript type definition. */ toPair(): [T,U] { return [this._fst, this._snd]; } /** * Convert the tuple to a javascript array. * Compared to [[Tuple2.toPair]], it behaves the * same at runtime, the only difference is the * typescript type definition. */ toArray(): Array { return [this._fst, this._snd]; } /** * Convert the tuple to a vector. */ toVector(): Vector { return Vector.of(this._fst, this._snd); } /** * Convert the tuple to a linked list. */ toLinkedList(): ConsLinkedList { return LinkedList.of(this._fst, this._snd); } /** * Get a human-friendly string representation of that value. */ toString(): string { return `Tuple2(${toStringHelper(this._fst)}, ${toStringHelper(this._snd)})`; } /** * Used by the node REPL to display values. * Most of the time should be the same as toString() */ inspect(): string { return this.toString(); } }