Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | 26x 26x 26x 26x 26x 551x 26x 26x 19x 551x 537x 14x 1182x 551x 537x 537x 537x 536x 1x 1x 1x 536x 537x 551x 458x 551x 549x 458x 456x 456x 456x 456x 456x 551x 551x 551x 551x 551x | import { Idempotent, Config } from "@jonloucks/contracts-ts/auxiliary/Idempotent";
import { IdempotentState } from "@jonloucks/contracts-ts/auxiliary/IdempotenState";
import { AUTO_CLOSE_NONE, AutoClose, inlineAutoClose } from "@jonloucks/contracts-ts/api/AutoClose";
import { Open, typeToOpen } from "@jonloucks/contracts-ts/api/Open";
import { presentCheck } from "@jonloucks/contracts-ts/auxiliary/Checks";
import { AtomicBoolean } from "@jonloucks/contracts-ts/auxiliary/AtomicBoolean";
import { create as createAtomicBoolean } from "./AtomicBoolean.impl";
/**
* Create a new Idempotent
*
* @param config the idempotent configuration
* @return the new Idempotent
*/
export function create(config: Config): Idempotent {
return IdempotentImpl.internalCreate(config);
}
// ---- Implementation details below ----
const IS_CLOSED: boolean = false;
const IS_OPEN: boolean = true;
class IdempotentImpl implements Idempotent {
// Idempotent.getState
getState(): IdempotentState {
return this.#idempotentState;
}
// Idempotent.open
open(): AutoClose {
if (this.transitionToOpen()) {
return this.firstOpen();
} else {
return AUTO_CLOSE_NONE;
}
}
// Idempotent.isOpen
isOpen(): boolean {
return this.#flag.get() === IS_OPEN;
}
static internalCreate(config: Config): Idempotent {
return new IdempotentImpl(config);
}
private firstOpen(): AutoClose {
this.#idempotentState = "OPENING";
try {
this.#closeDelegate = this.openDelegate();
this.#idempotentState = "OPENED";
} catch (thrown) {
this.#flag.set(IS_CLOSED);
this.#idempotentState = "OPENABLE";
throw thrown;
}
return this.#firstClose;
}
private openDelegate(): AutoClose {
return presentCheck(this.#delegate.open(), "Close must be present.");
}
private transitionToOpen(): boolean {
return this.#flag.compareAndSet(IS_CLOSED, IS_OPEN);
}
private transitionToClosed(): boolean {
return this.#flag.compareAndSet(IS_OPEN, IS_CLOSED);
}
private constructor(config: Config) {
this.#delegate = typeToOpen(config.open);
this.#firstClose = inlineAutoClose(() => {
if (this.transitionToClosed()) {
this.#idempotentState = "CLOSING";
try {
this.#closeDelegate?.close();
} finally {
this.#closeDelegate = undefined;
this.#idempotentState = "CLOSED";
}
}
});
}
readonly #delegate: Open;
readonly #firstClose: AutoClose;
readonly #flag: AtomicBoolean = createAtomicBoolean(IS_CLOSED);
#closeDelegate: AutoClose | undefined = undefined;
#idempotentState: IdempotentState = "OPENABLE";
}
|