import { Stream } from '../../../stream/Stream.js';
import { cloneMethod, hasCloneMethod } from '../../symbols.js';
export class Shrinkable {
    constructor(value_, shrink = () => Stream.nil()) {
        this.value_ = value_;
        this.shrink = shrink;
        this.hasToBeCloned = hasCloneMethod(value_);
        this.readOnce = false;
        Object.defineProperty(this, 'value', { get: this.getValue });
    }
    getValue() {
        if (this.hasToBeCloned) {
            if (!this.readOnce) {
                this.readOnce = true;
                return this.value_;
            }
            return this.value_[cloneMethod]();
        }
        return this.value_;
    }
    applyMapper(mapper) {
        if (this.hasToBeCloned) {
            const out = mapper(this.value);
            if (out instanceof Object) {
                out[cloneMethod] = () => mapper(this.value);
            }
            return out;
        }
        return mapper(this.value);
    }
    map(mapper) {
        return new Shrinkable(this.applyMapper(mapper), () => this.shrink().map((v) => v.map(mapper)));
    }
    filter(refinement) {
        const refinementOnShrinkable = (s) => {
            return refinement(s.value);
        };
        return new Shrinkable(this.value, () => this.shrink()
            .filter(refinementOnShrinkable)
            .map((v) => v.filter(refinement)));
    }
}
