File size: 5,293 Bytes
5641073
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Orphan = void 0;
const tslib_1 = require("tslib");
const debug_1 = tslib_1.__importDefault(require("debug"));
const errors_1 = require("../../errors");
const util_1 = require("../../util");
const list_element_size_1 = require("../list-element-size");
const object_size_1 = require("../object-size");
const pointer_1 = require("./pointer");
const pointer_type_1 = require("./pointer-type");
const trace = debug_1.default("capnp:orphan");
trace("load");
// Technically speaking this class doesn't need to be generic, but the extra type checking enforced by this helps to
// make sure you don't accidentally adopt a pointer of the wrong type.
/**
 * An orphaned pointer. This object itself is technically a pointer to the original pointer's content, which was left
 * untouched in its original message. The original pointer data is encoded as attributes on the Orphan object, ready to
 * be reconstructed once another pointer is ready to adopt it.
 *
 * @export
 * @class Orphan
 * @extends {Pointer}
 * @template T
 */
class Orphan {
    constructor(src) {
        const c = pointer_1.getContent(src);
        this.segment = c.segment;
        this.byteOffset = c.byteOffset;
        this._capnp = {};
        // Read vital info from the src pointer so we can reconstruct it during adoption.
        this._capnp.type = pointer_1.getTargetPointerType(src);
        switch (this._capnp.type) {
            case pointer_type_1.PointerType.STRUCT:
                this._capnp.size = pointer_1.getTargetStructSize(src);
                break;
            case pointer_type_1.PointerType.LIST:
                this._capnp.length = pointer_1.getTargetListLength(src);
                this._capnp.elementSize = pointer_1.getTargetListElementSize(src);
                if (this._capnp.elementSize === list_element_size_1.ListElementSize.COMPOSITE) {
                    this._capnp.size = pointer_1.getTargetCompositeListSize(src);
                }
                break;
            case pointer_type_1.PointerType.OTHER:
                this._capnp.capId = pointer_1.getCapabilityId(src);
                break;
            default:
                // COVERAGE: Unreachable code.
                /* istanbul ignore next */
                throw new Error(errors_1.PTR_INVALID_POINTER_TYPE);
        }
        // Zero out the source pointer (but not the contents!).
        pointer_1.erasePointer(src);
    }
    /**
     * Adopt (move) this orphan into the target pointer location. This will allocate far pointers in `dst` as needed.
     *
     * @param {T} dst The destination pointer.
     * @returns {void}
     */
    _moveTo(dst) {
        if (this._capnp === undefined) {
            throw new Error(util_1.format(errors_1.PTR_ALREADY_ADOPTED, this));
        }
        // TODO: Implement copy semantics when this happens.
        if (this.segment.message !== dst.segment.message) {
            throw new Error(util_1.format(errors_1.PTR_ADOPT_WRONG_MESSAGE, this, dst));
        }
        // Recursively wipe out the destination pointer first.
        pointer_1.erase(dst);
        const res = pointer_1.initPointer(this.segment, this.byteOffset, dst);
        switch (this._capnp.type) {
            case pointer_type_1.PointerType.STRUCT:
                pointer_1.setStructPointer(res.offsetWords, this._capnp.size, res.pointer);
                break;
            case pointer_type_1.PointerType.LIST: {
                let offsetWords = res.offsetWords;
                if (this._capnp.elementSize === list_element_size_1.ListElementSize.COMPOSITE) {
                    offsetWords--; // The tag word gets skipped.
                }
                pointer_1.setListPointer(offsetWords, this._capnp.elementSize, this._capnp.length, res.pointer, this._capnp.size);
                break;
            }
            case pointer_type_1.PointerType.OTHER:
                pointer_1.setInterfacePointer(this._capnp.capId, res.pointer);
                break;
            /* istanbul ignore next */
            default:
                throw new Error(errors_1.PTR_INVALID_POINTER_TYPE);
        }
        this._capnp = undefined;
    }
    dispose() {
        // FIXME: Should this throw?
        if (this._capnp === undefined) {
            trace("not disposing an already disposed orphan", this);
            return;
        }
        switch (this._capnp.type) {
            case pointer_type_1.PointerType.STRUCT:
                this.segment.fillZeroWords(this.byteOffset, object_size_1.getWordLength(this._capnp.size));
                break;
            case pointer_type_1.PointerType.LIST: {
                const byteLength = pointer_1.getListByteLength(this._capnp.elementSize, this._capnp.length, this._capnp.size);
                this.segment.fillZeroWords(this.byteOffset, byteLength);
                break;
            }
            default:
                // Other pointer types don't actually have any content.
                break;
        }
        this._capnp = undefined;
    }
    toString() {
        return util_1.format("Orphan_%d@%a,type:%s", this.segment.id, this.byteOffset, this._capnp && this._capnp.type);
    }
}
exports.Orphan = Orphan;
//# sourceMappingURL=orphan.js.map