Skip to content

Commit 4d484f2

Browse files
i-kovalyovmcollina
authored andcommitted
Fixed Stream decode C0 byte (nil) processing error (#68)
* Fixed Stream decode processing error: after C0 byte (nil) stream switched to "End of stream state", added test. Minor changes made in modules formatting to satisfy modules formatting rules checked in tests. * Added stream decoder wrap option, default value is false for compatibility reasons. When wrap is true decoded items are passed in form of {value: data} instead of data. Using wrap=true for decoder stream allows decoding of C0 byte (nil). * Added wrap option for decoder and encoder streams. When wrap = true decoder stream outputs {value:data} instead of data, encoder stream encodes data extracted from {value:data}. * Added tests for encoder stream with wrap options, encoder/decoder streams chain with wrap options. Wrap option for encoder/decoder streams documented in readme.md * encoder property _unwrap renamed to _wrap. Minor changes in documentation for wrap option of encoder/decoder.
1 parent 01275c8 commit 4d484f2

File tree

3 files changed

+93
-3
lines changed

3 files changed

+93
-3
lines changed

README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,17 +177,25 @@ This is just a commodity that calls
177177
-------------------------------------------------------
178178
<a name="encoder"></a>
179179

180-
### encoder()
180+
### encoder(options)
181181

182182
Builds a stream in object mode that encodes msgpack.
183183

184+
Supported options:
185+
* `wrap`, objects should be passed to encoder in wrapped object {value: data}. Wrap option should be used if you need to pass null to encoder.
186+
187+
184188
-------------------------------------------------------
185189
<a name="decoder"></a>
186190

187-
### decoder()
191+
### decoder(options)
188192

189193
Builds a stream in object mode that decodes msgpack.
190194

195+
Supported options:
196+
* `wrap`, decoded objects returned in wrapped object {value: data}. Wrap option should be used if stream contains msgpack nil.
197+
198+
191199
LevelUp Support
192200
---------------
193201

lib/streams.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ function Encoder (opts) {
2525
}
2626

2727
Base.call(this, opts)
28+
this._wrap = ('wrap' in opts) && opts.wrap
2829
}
2930

3031
inherits(Encoder, Base)
@@ -33,7 +34,7 @@ Encoder.prototype._transform = function (obj, enc, done) {
3334
var buf = null
3435

3536
try {
36-
buf = this._msgpack.encode(obj).slice(0)
37+
buf = this._msgpack.encode(this._wrap ? obj.value : obj).slice(0)
3738
} catch (err) {
3839
this.emit('error', err)
3940
return done()
@@ -53,6 +54,7 @@ function Decoder (opts) {
5354
Base.call(this, opts)
5455

5556
this._chunks = bl()
57+
this._wrap = ('wrap' in opts) && opts.wrap
5658
}
5759

5860
inherits(Decoder, Base)
@@ -64,6 +66,9 @@ Decoder.prototype._transform = function (buf, enc, done) {
6466

6567
try {
6668
var result = this._msgpack.decode(this._chunks)
69+
if (this._wrap) {
70+
result = {value: result}
71+
}
6772
this.push(result)
6873
} catch (err) {
6974
if (err instanceof this._msgpack.IncompleteBufferError) {

test/streams.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,80 @@ test('concatenated buffers work', function (t) {
182182

183183
encoder.end()
184184
})
185+
186+
test('nil processing works', function (t) {
187+
t.plan(3)
188+
189+
var pack = msgpack()
190+
var decoder = pack.decoder({wrap: true})
191+
var decodedItemIndex = 0
192+
193+
decoder.on('data', function (chunk) {
194+
decodedItemIndex++
195+
t.deepEqual(chunk.value, decodedItemIndex === 1 ? null : false)
196+
})
197+
198+
decoder.on('end', function () {
199+
t.equal(decodedItemIndex, 2)
200+
})
201+
202+
decoder.write(new Buffer([0xc0, 0xc2]))
203+
decoder.end()
204+
})
205+
206+
test('encoder wrap mode works', function (t) {
207+
t.plan(1)
208+
209+
var pack = msgpack()
210+
var encoder = pack.encoder({wrap: true})
211+
var decoder = pack.decoder()
212+
var data = { hello: 'world' }
213+
var wrappedData = {value: data}
214+
215+
encoder.pipe(decoder)
216+
217+
decoder.on('data', function (chunk) {
218+
t.deepEqual(chunk, data)
219+
})
220+
221+
encoder.end(wrappedData)
222+
})
223+
224+
test('encoder/decoder wrap mode must send an object through', function (t) {
225+
t.plan(1)
226+
227+
var pack = msgpack()
228+
var encoder = pack.encoder({wrap: true})
229+
var decoder = pack.decoder({wrap: true})
230+
var data = {value: { hello: 'world' }}
231+
232+
encoder.pipe(decoder)
233+
234+
decoder.on('data', function (chunk) {
235+
t.deepEqual(chunk, data)
236+
})
237+
238+
encoder.end(data)
239+
})
240+
241+
test('encoder pack null', function (t) {
242+
t.plan(2)
243+
var pack = msgpack()
244+
var encoder = pack.encoder({wrap: true})
245+
var decoder = pack.decoder({wrap: true})
246+
247+
encoder.pipe(decoder)
248+
249+
var decodedItemIndex = 0
250+
decoder.on('data', function (chunk) {
251+
decodedItemIndex++
252+
t.deepEqual(chunk.value, null)
253+
})
254+
255+
decoder.on('end', function () {
256+
t.equal(decodedItemIndex, 1)
257+
})
258+
259+
encoder.write({value: null})
260+
encoder.end()
261+
})

0 commit comments

Comments
 (0)