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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | 25x 25x 25x 25x 25x 25x 25x 25x 25x 5x 8x 8x 3x 4x 5x 5x 5x 3x 3x 3x 2x 3x 3x 5x 5x 8x 1x 7x 7x 3x 3x 4x 7x 7x 4x 4x 4x 4x 4x 4x 4x 3x 4x 3x 3x 3x 1x 1x 1x 2x 2x 2x 2x 2x 2x 5x 5x 5x 5x 5x | import { AutoCloseOne } from "@jonloucks/contracts-ts/api/AutoClose";
import { AutoOpen, guard as isAutoOpen } from "@jonloucks/contracts-ts/api/AutoOpen";
import { Promisor } from "@jonloucks/contracts-ts/api/Promisor";
import { OptionalType, RequiredType, isPresent } from "@jonloucks/contracts-ts/api/Types";
import { AtomicBoolean } from "@jonloucks/contracts-ts/auxiliary/AtomicBoolean";
import { AtomicInteger } from "@jonloucks/contracts-ts/auxiliary/AtomicInteger";
import { AtomicReference } from "@jonloucks/contracts-ts/auxiliary/AtomicReference";
import { promisorCheck } from "@jonloucks/contracts-ts/auxiliary/Checks";
import { IllegalStateException } from "@jonloucks/contracts-ts/auxiliary/IllegalStateException";
import { create as createAtomicBoolean } from "./AtomicBoolean.impl";
import { create as createAtomicInteger } from "./AtomicInteger.impl";
import { create as createAtomicReference } from "./AtomicReference.impl";
import { create as createAutoCloseOne } from "./AutoCloseOne.impl";
/**
* Factory to create an Life Cycle promisor implementation
*
* @param referent the source promisor
* @param <T> the type of deliverable
* @returns the new Life Cycle Promisor implementation
*/
export function create<T>(referent: Promisor<T>): RequiredType<Promisor<T>> {
return LifeCyclePromisorImpl.internalCreate<T>(referent);
}
// ---- Implementation details below ----
/**
* Implementation of a Life Cycle Promisor
* @param <T> the type of deliverable
*/
class LifeCyclePromisorImpl<T> implements Promisor<T> {
public demand(): OptionalType<T> {
const currentDeliverable: AtomicReference<T> = createAtomicReference<T>();
if (this.getCurrentDeliverable(currentDeliverable)) {
return currentDeliverable.get();
}
return this.createDeliverableIfNeeded();
}
public incrementUsage(): number {
let currentUsage = this.usageCounter.incrementAndGet();
this.referent.incrementUsage();
return currentUsage;
}
public decrementUsage(): number {
let currentUsage = this.usageCounter.decrementAndGet();
try {
if (currentUsage == 0) {
this.closeDeliverable();
}
} finally {
this.referent.decrementUsage();
}
return currentUsage;
}
static internalCreate<T>(referentPromisor: Promisor<T>): RequiredType<Promisor<T>> {
return new LifeCyclePromisorImpl<T>(referentPromisor);
}
private constructor(referentPromisor: Promisor<T>) {
this.referent = promisorCheck(referentPromisor);
}
private getCurrentDeliverable(placeholder: AtomicReference<T>): boolean {
if (this.usageCounter.get() == 0) {
throw new IllegalStateException("Usage count is zero.");
}
this.maybeRethrowOpenException();
if (this.isDeliverableAcquired.get()) {
placeholder.set(this.atomicDeliverable.get());
return true;
}
return false;
}
private maybeRethrowOpenException(): void {
const thrown: unknown = this.openException.get();
Iif (isPresent(thrown)) {
throw thrown;
}
}
private createDeliverableIfNeeded(): OptionalType<T> {
Iif (this.isDeliverableAcquired.get()) {
return this.atomicDeliverable.get();
} else {
return this.createDeliverable();
}
}
private createDeliverable(): OptionalType<T> {
this.openException.set(null);
const currentDeliverable: OptionalType<T> = this.referent.demand();
this.atomicDeliverable.set(currentDeliverable);
this.isDeliverableAcquired.set(true);
this.openDeliverable(currentDeliverable);
return currentDeliverable;
}
private openDeliverable(deliverable: OptionalType<T>): void {
if (isPresent(deliverable) && isAutoOpen(deliverable)) {
const autoOpen: AutoOpen = deliverable;
try {
this.closer.set(autoOpen.autoOpen());
} catch (thrown) {
this.openException.set(thrown);
this.isDeliverableAcquired.set(false);
throw thrown;
}
}
}
private closeDeliverable(): void {
Eif (this.isDeliverableAcquired.get()) {
const deliverable: OptionalType<T> | null = this.atomicDeliverable.get();
try {
this.closer.close();
} finally {
this.atomicDeliverable.compareAndSet(deliverable, null);
this.isDeliverableAcquired.set(false);
}
}
}
private readonly usageCounter: AtomicInteger = createAtomicInteger();
private readonly referent: Promisor<T>;
private readonly isDeliverableAcquired: AtomicBoolean = createAtomicBoolean();
private readonly atomicDeliverable: AtomicReference<T> = createAtomicReference<T>();
private readonly openException: AtomicReference<unknown> = createAtomicReference<unknown>();
private readonly closer: AutoCloseOne = createAutoCloseOne();
}
|