···11-export function extractNum(params: {
11+export function extractBits(params: {
22 input: number;
33 extractedNumLengthBits: number;
44 leastSignificantBit: number;
···12121313 if (params.reverseResultBits) {
1414 result = reverseBits(result, params.extractedNumLengthBits);
1515+ }
1616+ return result;
1717+}
1818+1919+/**
2020+ * Provide bit groups in order from least significant to most significant
2121+ */
2222+export function combineBits(
2323+ bitGroups: { lengthBits: number; value: number }[],
2424+): number {
2525+ let result = 0;
2626+ let nextBit = 0;
2727+ for (const bitGroup of bitGroups) {
2828+ result |= bitGroup.value << nextBit;
2929+ nextBit += bitGroup.lengthBits;
1530 }
1631 return result;
1732}
+51
src/util/prompts.ts
···11import type { PromptValidator } from "@topcli/prompts";
22+import { getMaxUnsignedInt } from "./bit-manipulation.ts";
2334// TODO(Harper): Delete once https://github.com/TopCli/prompts/pull/151 is released
45export type ValidationResponse =
···2122 },
2223 };
2324}
2525+2626+export function createIntPromptValidator(
2727+ validate?: (input: number) => ValidationResponse,
2828+) {
2929+ if (validate == undefined) {
3030+ validate = () => ({ isValid: true });
3131+ }
3232+3333+ return createStringPromptValidator((input) => {
3434+ // Number.parseInt() truncates floats, but we want to reject them
3535+ const inputNumber = Number.parseFloat(input);
3636+ if (Number.isNaN(inputNumber)) {
3737+ return { isValid: false, error: "Input was not a number" };
3838+ }
3939+ if (!Number.isInteger(inputNumber)) {
4040+ return { isValid: false, error: "Input was not an integer" };
4141+ }
4242+ return validate(inputNumber);
4343+ });
4444+}
4545+4646+export function createUintPromptValidator(
4747+ uintLengthBits: number,
4848+ errorMsg?: string,
4949+) {
5050+ return createIntPromptValidator((input) => {
5151+ if (input < getMaxUnsignedInt(uintLengthBits)) {
5252+ return { isValid: true } as const;
5353+ } else {
5454+ return {
5555+ isValid: false,
5656+ error:
5757+ errorMsg ?? `Input does not fit in ${uintLengthBits} bits`,
5858+ } as const;
5959+ }
6060+ });
6161+}
6262+6363+export const nonNegativeIntPromptValidator = createIntPromptValidator(
6464+ (input) => {
6565+ if (input >= 0) {
6666+ return { isValid: true } as const;
6767+ } else {
6868+ return {
6969+ isValid: false,
7070+ error: `Input was negative`,
7171+ } as const;
7272+ }
7373+ },
7474+);