| 62 | }; |
| 63 | |
| 64 | class AlphaRank implements RankLike { |
| 65 | constructor(private readonly value: number) {} |
| 66 | |
| 67 | toString(): string { |
| 68 | return encodeAlphaRank(this.value); |
| 69 | } |
| 70 | |
| 71 | genPrev(): RankLike { |
| 72 | if (this.value <= 0) { |
| 73 | throw new Error("Cannot generate rank before minimum alpha rank"); |
| 74 | } |
| 75 | return new AlphaRank(this.value - 1); |
| 76 | } |
| 77 | |
| 78 | genNext(): RankLike { |
| 79 | if (this.value >= ALPHA_RANK_MAX) { |
| 80 | throw new Error("Cannot generate rank after maximum alpha rank"); |
| 81 | } |
| 82 | return new AlphaRank(this.value + 1); |
| 83 | } |
| 84 | |
| 85 | between(other: RankLike): RankLike { |
| 86 | const otherValue = decodeAlphaRank(other.toString()); |
| 87 | if (otherValue === null) { |
| 88 | throw new Error("Cannot generate alpha midpoint against a non-alpha rank"); |
| 89 | } |
| 90 | const lower = Math.min(this.value, otherValue); |
| 91 | const upper = Math.max(this.value, otherValue); |
| 92 | const midpoint = Math.floor((lower + upper) / 2); |
| 93 | if (midpoint <= lower || midpoint >= upper) { |
| 94 | throw new Error("No alpha rank gap available"); |
| 95 | } |
| 96 | return new AlphaRank(midpoint); |
| 97 | } |
| 98 | |
| 99 | isMax(): boolean { |
| 100 | return this.value >= ALPHA_RANK_MAX; |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | function encodeAlphaRank(value: number): string { |
| 105 | let remaining = Math.max(0, Math.min(ALPHA_RANK_MAX, Math.floor(value))); |
nothing calls this directly
no outgoing calls
no test coverage detected