"use strict";
/**
 * Serde runtime helpers for macroforge Serialize/Deserialize macros.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.PendingRef = exports.DeserializeContext = exports.SerializeContext = void 0;

// ============================================================================
// Serialization Context
// ============================================================================

var SerializeContext;
(function (SerializeContext) {
    function create() {
        const ids = new WeakMap();
        let nextId = 0;
        return {
            getId: (obj) => ids.get(obj),
            register: (obj) => {
                const id = nextId++;
                ids.set(obj, id);
                return id;
            },
        };
    }
    SerializeContext.create = create;
})(SerializeContext || (exports.SerializeContext = SerializeContext = {}));

// ============================================================================
// Deserialization Context
// ============================================================================

var DeserializeContext;
(function (DeserializeContext) {
    function create() {
        const registry = new Map();
        const patches = [];
        const toFreeze = [];
        return {
            register: (id, instance) => {
                registry.set(id, instance);
            },
            getOrDefer: (refId) => {
                if (registry.has(refId)) {
                    return registry.get(refId);
                }
                return PendingRef.create(refId);
            },
            assignOrDefer: (target, prop, value) => {
                if (PendingRef.is(value)) {
                    target[prop] = null;
                    patches.push({ target, prop, refId: value.id });
                }
                else {
                    target[prop] = value;
                }
            },
            addPatch: (target, prop, refId) => {
                patches.push({ target, prop, refId });
            },
            trackForFreeze: (obj) => {
                toFreeze.push(obj);
            },
            applyPatches: () => {
                for (const { target, prop, refId } of patches) {
                    if (!registry.has(refId)) {
                        throw new Error(`Unresolved reference: __ref ${refId}`);
                    }
                    target[prop] = registry.get(refId);
                }
            },
            freezeAll: () => {
                for (const obj of toFreeze) {
                    Object.freeze(obj);
                }
            },
        };
    }
    DeserializeContext.create = create;
})(DeserializeContext || (exports.DeserializeContext = DeserializeContext = {}));

// ============================================================================
// Pending Reference Marker
// ============================================================================

var PendingRef;
(function (PendingRef) {
    function create(id) {
        return { __pendingRef: true, id };
    }
    PendingRef.create = create;
    function is(value) {
        return (value !== null &&
            typeof value === "object" &&
            value.__pendingRef === true &&
            typeof value.id === "number");
    }
    PendingRef.is = is;
})(PendingRef || (exports.PendingRef = PendingRef = {}));
