"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.takeAllUpTo_ = exports.takeAllUpTo = exports.takeAll = exports.take = exports.size = exports.shutdown = exports.offerAll_ = exports.offerAll = exports.offerTo_ = exports.offerTo = exports.offer_ = exports.offer = exports.isShutdown = exports.capacity = exports.awaitShutdown = exports.unsafePollAll = exports.unsafeOfferAll = exports.unsafePollN = exports.unsafeRemove = exports.unsafeCompleteTakers = exports.unsafeCompletePromise = exports.SlidingStrategy = exports.DroppingStrategy = void 0;
// ets_tracing: off
const ChunkFilter = __importStar(require("../Collections/Immutable/Chunk/api/filter"));
const Chunk = __importStar(require("../Collections/Immutable/Chunk/core"));
const T = __importStar(require("./effect"));
const P = __importStar(require("./promise"));
const xqueue_1 = require("./xqueue");
class DroppingStrategy {
    handleSurplus(_as, _queue, _takers, _isShutdown) {
        return T.succeed(false);
    }
    unsafeOnQueueEmptySpace(_queue) {
        //
    }
    get shutdown() {
        return T.unit;
    }
    get surplusSize() {
        return 0;
    }
}
exports.DroppingStrategy = DroppingStrategy;
class SlidingStrategy {
    handleSurplus(as, queue, takers, _isShutdown) {
        return T.succeedWith(() => {
            this.unsafeSlidingOffer(queue, as);
            unsafeCompleteTakers(this, queue, takers);
            return true;
        });
    }
    unsafeOnQueueEmptySpace(_queue) {
        //
    }
    get shutdown() {
        return T.unit;
    }
    get surplusSize() {
        return 0;
    }
    unsafeSlidingOffer(queue, as) {
        let bs = as;
        while (Chunk.size(bs) > 0) {
            if (queue.capacity === 0) {
                return;
            }
            // poll 1 and retry
            queue.poll(undefined);
            if (queue.offer(Chunk.unsafeGet_(bs, 0))) {
                bs = Chunk.drop_(bs, 1);
            }
        }
    }
}
exports.SlidingStrategy = SlidingStrategy;
function unsafeCompletePromise(p, a) {
    return P.unsafeDone(T.succeed(a))(p);
}
exports.unsafeCompletePromise = unsafeCompletePromise;
function unsafeCompleteTakers(strategy, queue, takers) {
    let keepPolling = true;
    while (keepPolling && !queue.isEmpty) {
        const taker = takers.poll(undefined);
        if (taker != null) {
            const element = queue.poll(undefined);
            if (element != null) {
                unsafeCompletePromise(taker, element);
                strategy.unsafeOnQueueEmptySpace(queue);
            }
            else {
                unsafeOfferAll(takers, Chunk.prepend_(unsafePollAll(takers), taker));
            }
            keepPolling = true;
        }
        else {
            keepPolling = false;
        }
    }
}
exports.unsafeCompleteTakers = unsafeCompleteTakers;
function unsafeRemove(q, a) {
    ChunkFilter.filter_(unsafeOfferAll(q, unsafePollAll(q)), (b) => a !== b);
}
exports.unsafeRemove = unsafeRemove;
function unsafePollN(q, max) {
    let j = 0;
    let as = Chunk.empty();
    while (j < max) {
        const p = q.poll(undefined);
        if (p != null) {
            as = Chunk.append_(as, p);
        }
        else {
            return as;
        }
        j += 1;
    }
    return as;
}
exports.unsafePollN = unsafePollN;
function unsafeOfferAll(q, as) {
    let bs = as;
    while (Chunk.size(bs) > 0) {
        if (!q.offer(Chunk.unsafeGet_(bs, 0))) {
            return bs;
        }
        else {
            bs = Chunk.drop_(bs, 1);
        }
    }
    return bs;
}
exports.unsafeOfferAll = unsafeOfferAll;
function unsafePollAll(q) {
    let as = Chunk.empty();
    while (!q.isEmpty) {
        as = Chunk.append_(as, q.poll(undefined));
    }
    return as;
}
exports.unsafePollAll = unsafePollAll;
/**
 * Waits until the queue is shutdown.
 * The `IO` returned by this method will not resume until the queue has been shutdown.
 * If the queue is already shutdown, the `IO` will resume right away.
 */
function awaitShutdown(self) {
    ;
    return self.awaitShutdown;
}
exports.awaitShutdown = awaitShutdown;
/**
 * How many elements can hold in the queue
 */
function capacity(self) {
    ;
    return self.capacity;
}
exports.capacity = capacity;
/**
 * `true` if `shutdown` has been called.
 */
function isShutdown(self) {
    ;
    return self.isShutdown;
}
exports.isShutdown = isShutdown;
/**
 * Places one value in the queue.
 *
 * @ets_data_first offer_
 */
function offer(a) {
    return (self) => offer_(self, a);
}
exports.offer = offer;
/**
 * Places one value in the queue.
 */
function offer_(self, a) {
    ;
    return self.offer(a);
}
exports.offer_ = offer_;
/**
 * Places one value in the queue.
 *
 * @ets_data_first offerTo_
 */
function offerTo(self) {
    return (a) => offer_(self, a);
}
exports.offerTo = offerTo;
/**
 * Places one value in the queue.
 *
 * @ets_data_first offerTo_
 */
function offerTo_(a, self) {
    return offer_(self, a);
}
exports.offerTo_ = offerTo_;
/**
 * For Bounded Queue: uses the `BackPressure` Strategy, places the values in the queue and always returns true.
 * If the queue has reached capacity, then
 * the fiber performing the `offerAll` will be suspended until there is room in
 * the queue.
 *
 * For Unbounded Queue:
 * Places all values in the queue and returns true.
 *
 * For Sliding Queue: uses `Sliding` Strategy
 * If there is room in the queue, it places the values otherwise it removes the old elements and
 * enqueues the new ones. Always returns true.
 *
 * For Dropping Queue: uses `Dropping` Strategy,
 * It places the values in the queue but if there is no room it will not enqueue them and return false.
 *
 * @ets_data_first offerAll_
 */
function offerAll(as) {
    return (self) => offerAll_(self, as);
}
exports.offerAll = offerAll;
/**
 * For Bounded Queue: uses the `BackPressure` Strategy, places the values in the queue and always returns true.
 * If the queue has reached capacity, then
 * the fiber performing the `offerAll` will be suspended until there is room in
 * the queue.
 *
 * For Unbounded Queue:
 * Places all values in the queue and returns true.
 *
 * For Sliding Queue: uses `Sliding` Strategy
 * If there is room in the queue, it places the values otherwise it removes the old elements and
 * enqueues the new ones. Always returns true.
 *
 * For Dropping Queue: uses `Dropping` Strategy,
 * It places the values in the queue but if there is no room it will not enqueue them and return false.
 */
function offerAll_(self, as) {
    ;
    return self.offerAll(as);
}
exports.offerAll_ = offerAll_;
/**
 * Interrupts any fibers that are suspended on `offer` or `take`.
 * Future calls to `offer*` and `take*` will be interrupted immediately.
 */
function shutdown(self) {
    ;
    return self.shutdown;
}
exports.shutdown = shutdown;
/**
 * Retrieves the size of the queue, which is equal to the number of elements
 * in the queue. This may be negative if fibers are suspended waiting for
 * elements to be added to the queue.
 */
function size(self) {
    ;
    return self.size;
}
exports.size = size;
/**
 * Removes the oldest value in the queue. If the queue is empty, this will
 * return a computation that resumes when an item has been added to the queue.
 */
function take(self) {
    ;
    return self.take;
}
exports.take = take;
/**
 * Removes all the values in the queue and returns the list of the values. If the queue
 * is empty returns empty list.
 */
function takeAll(self) {
    ;
    return self.takeAll;
}
exports.takeAll = takeAll;
/**
 * Takes up to max number of values in the queue.
 *
 * @ets_data_first takeAllUpTo_
 */
function takeAllUpTo(n) {
    return (self) => takeAllUpTo_(self, n);
}
exports.takeAllUpTo = takeAllUpTo;
/**
 * Takes up to max number of values in the queue.
 */
function takeAllUpTo_(self, n) {
    ;
    return self.takeUpTo(n);
}
exports.takeAllUpTo_ = takeAllUpTo_;
//# sourceMappingURL=core.js.map