Skip to content

Instantly share code, notes, and snippets.

@igrep
Last active April 19, 2023 10:23
Show Gist options
  • Save igrep/a7d82ab5a6e38d0573ca1454a22ceabf to your computer and use it in GitHub Desktop.
Save igrep/a7d82ab5a6e38d0573ca1454a22ceabf to your computer and use it in GitHub Desktop.
Runtime borrow checker for JavaScript
export interface Borrowed<X> {
unsafeBorrow<Result>(use: (x: X) => Result): [Borrowed<X>, Result];
get isBorrowed(): boolean;
}
export class AlreadyBorrowedError extends Error {
override name = "AlreadyBorrowedError";
}
export function unsafeBorrowed<X>(x: X): Borrowed<X> {
let alreadyBorrowed = false;
const b = {
// This is unsafe because it cannot prevent the `x` object from escaping from the scope of `use`.
// So you should use this with a proper wrapper function.
unsafeBorrow<Result>(use: (x: X) => Result): [Borrowed<X>, Result] {
if (alreadyBorrowed) {
throw new AlreadyBorrowedError();
}
const r = use(x);
alreadyBorrowed = true;
return [unsafeBorrowed(x), r];
},
get isBorrowed(): boolean {
return alreadyBorrowed;
},
};
return b;
}
export function borrowed<X>(x: X): Borrowed<X> {
return unsafeBorrowed(structuredClone(x));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment