1 // Copyright Joyent, Inc. and other Node contributors.
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21 // a duplex stream is just a stream that is both readable and writable.
22 // Since JS doesn't have multiple prototypal inheritance, this class
23 // prototypally inherits from Readable, and then parasitically from
28 var objectKeys = Object.keys || function (obj) {
31 for (var key in obj) {
40 module.exports = Duplex;
42 var Readable = require('./_stream_readable');
44 var Writable = require('./_stream_writable');
46 require('inherits')(Duplex, Readable);
49 // Allow the keys array to be GC'ed.
50 var keys = objectKeys(Writable.prototype);
52 for (var v = 0; v < keys.length; v++) {
54 if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];
58 function Duplex(options) {
59 if (!(this instanceof Duplex)) return new Duplex(options);
60 Readable.call(this, options);
61 Writable.call(this, options);
62 this.allowHalfOpen = true;
65 if (options.readable === false) this.readable = false;
66 if (options.writable === false) this.writable = false;
68 if (options.allowHalfOpen === false) {
69 this.allowHalfOpen = false;
70 this.once('end', onend);
75 Object.defineProperty(Duplex.prototype, 'writableHighWaterMark', {
76 // making it explicit this property is not enumerable
77 // because otherwise some prototype manipulation in
81 return this._writableState.highWaterMark;
84 Object.defineProperty(Duplex.prototype, 'writableBuffer', {
85 // making it explicit this property is not enumerable
86 // because otherwise some prototype manipulation in
90 return this._writableState && this._writableState.getBuffer();
93 Object.defineProperty(Duplex.prototype, 'writableLength', {
94 // making it explicit this property is not enumerable
95 // because otherwise some prototype manipulation in
99 return this._writableState.length;
101 }); // the no-half-open enforcer
104 // If the writable side ended, then we're ok.
105 if (this._writableState.ended) return; // no more data can be written.
106 // But allow more writes to happen in this tick.
108 process.nextTick(onEndNT, this);
111 function onEndNT(self) {
115 Object.defineProperty(Duplex.prototype, 'destroyed', {
116 // making it explicit this property is not enumerable
117 // because otherwise some prototype manipulation in
118 // userland will fail
120 get: function get() {
121 if (this._readableState === undefined || this._writableState === undefined) {
125 return this._readableState.destroyed && this._writableState.destroyed;
127 set: function set(value) {
128 // we ignore the value if the stream
129 // has not been initialized yet
130 if (this._readableState === undefined || this._writableState === undefined) {
132 } // backward compatibility, the user is explicitly
133 // managing destroyed
136 this._readableState.destroyed = value;
137 this._writableState.destroyed = value;