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
|
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var {
findPlaceholders,
getPath,
} = require("resource://devtools/shared/protocol/utils.js");
var { types } = require("resource://devtools/shared/protocol/types.js");
/**
* Manages a response template.
*
* @param object template
* The response template.
* @construcor
*/
var Response = function (template = {}) {
this.template = template;
if (this.template instanceof RetVal && this.template.isArrayType()) {
throw Error("Arrays should be wrapped in objects");
}
const placeholders = findPlaceholders(template, RetVal);
if (placeholders.length > 1) {
throw Error("More than one RetVal specified in response");
}
const placeholder = placeholders.shift();
if (placeholder) {
this.retVal = placeholder.placeholder;
this.path = placeholder.path;
}
};
Response.prototype = {
/**
* Write a response for the given return value.
*
* @param val ret
* The return value.
* @param object ctx
* The object writing the response.
*/
write(ret, ctx) {
// Consider that `template` is either directly a `RetVal`,
// or a dictionary with may be one `RetVal`.
if (this.template instanceof RetVal) {
return this.template.write(ret, ctx);
}
const result = {};
for (const key in this.template) {
const value = this.template[key];
if (value instanceof RetVal) {
result[key] = value.write(ret, ctx);
} else {
throw new Error(
"Response can only be a `RetVal` instance or an object " +
"with one property being a `RetVal` instance."
);
}
}
return result;
},
/**
* Read a return value from the given response.
*
* @param object packet
* The response packet.
* @param object ctx
* The object reading the response.
*/
read(packet, ctx) {
if (!this.retVal) {
return undefined;
}
const v = getPath(packet, this.path);
return this.retVal.read(v, ctx);
},
};
exports.Response = Response;
/**
* Placeholder for return values in a response template.
*
* @param type type
* The return value should be marshalled as this type.
*/
var RetVal = function (type) {
this._type = type;
// Prevent force loading all RetVal types by accessing it only when needed
loader.lazyGetter(this, "type", function () {
return types.getType(type);
});
};
RetVal.prototype = {
write(v, ctx) {
return this.type.write(v, ctx);
},
read(v, ctx) {
return this.type.read(v, ctx);
},
isArrayType() {
// `_type` should always be a string, but a few incorrect RetVal calls
// pass `0`. See Bug 1677703.
return typeof this._type === "string" && this._type.startsWith("array:");
},
};
// Outside of protocol.js, RetVal is called as factory method, without the new keyword.
exports.RetVal = function (type) {
return new RetVal(type);
};
|