New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(buffer): add Node.js compatible Buffer module #11084
Conversation
Fixes TIMOB-26573
Tests:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did a first pass and this looks really solid! Just a few minor notes.
I'll continue to test this in my WebSocket/socket.io module.
const fillChar = bufToFillWith._tiBuffer[i % fillBufLength]; | ||
console.log(`going to use ${fillChar} to fill at index ${i + offset}`); | ||
this._tiBuffer[i + offset] = fillChar; | ||
console.log(`here's what it got set to: ${this._tiBuffer[i + offset]}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove debug logs
} else if (encoding === 'hex') { | ||
return Buffer.from(stringToHexBytes(value)); | ||
} | ||
const type = getTiCodecCharset(encoding); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Throw an uknown encoding error here if the codec map returns undefined.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
return newBuffer(value); | ||
} | ||
} | ||
throw new TypeError('The \'value\' argument must be of type: \'string\', \'Array\', \'Buffer\''); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That method checks using typeof versus a single type. So I can't use it here...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, damn! For some reason i thought that function includes more type checks than it actually does.
tests/Resources/buffer.addontest.js
Outdated
|
||
it('handles 2-byte utf-8 character fill', () => { | ||
const b = Buffer.allocUnsafe(3).fill('\u0222'); | ||
should(b[0]).eql(0xc8); // FIXME: get expected undefined to equal 200 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this still throw? Do we need to skip this and the following test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Outdated FIXME. I removed this and the others in this file
tests/Resources/buffer.addontest.js
Outdated
should(buf.readUInt16BE(1).toString(16)).eql('3456'); | ||
}); | ||
|
||
// it('returns signed value coerced to unsigned', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a note why this is commented out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I got lazy and didn't want to write the test properly :)
tests/Resources/buffer.addontest.js
Outdated
}, RangeError); | ||
}); | ||
|
||
// it('throws when trying to write values out of range', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, can you add a fixme note and explain why this is commented out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add it back and get it right. I got a bit fatigued of writing all these tests!
Co-Authored-By: Jan Vennemann <jan.vennemann@gmx.net>
Co-Authored-By: Jan Vennemann <jan.vennemann@gmx.net>
Co-Authored-By: Jan Vennemann <jan.vennemann@gmx.net>
@janvennemann Ok, I pushed changes to address the review comments. |
|
||
Buffer.poolSize = 8192; | ||
|
||
export default Buffer; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The export is not compatible with the node buffer
module this way. The core module exports it as Buffer
instead of default.
Some third-party node modules do the following for example:
var Buffer = require('buffer').Buffer;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch, pushing commits to fix this now
squash merged manually |
JIRA: https://jira.appcelerator.org/browse/TIMOB-26573
Description:
This adds a Node-compatible
buffer
module in JS.In Node, a
Buffer
represents a byte array (specifically an unsigned byte array). In Titanium,Ti.Buffer
represents the exact same concept. In both cases these APIs were created because JS engines did not yet have the concept, but have long ago added TypedArrays (or more specifically in this case, aUint8Array
).This shim is intended to expose Node's API, which is backed by a
Ti.Buffer
internally. It's important to note that this could result in performance issues as a result, because to support array style index setter/getters I also had to wrap instances in a JSProxy
. So to read/write specific bytes you end up going through a JS Proxy, then traversing our JS/native binding, grabbing the value natively, returning it across the JS/native binding layer and then back out the JS Proxy. So clearly on a per-byte level this isn't ideal. But obviously a number of operations are pure JS, and there are methods that support a little bit of "bulk" inserts to help avoid the penalties.I think long term we should investigate possibly doing a few things:
Ti.Buffer
, use a faster implementation that is backed byUint8Array
a la Browserify: https://github.com/feross/buffer/blob/master/index.jsUint8Array
for any Titanium APIs that take in aTi.Buffer
Ti.Buffer
afterwardsCaveats
This does not include:
.buffer
property#lastIndexOf()
#read/writeBigInt
method variants (we do not yet supportBigInt
)#transcode()
.INSPECT_MAX_BYTES
.kMaxLength
.constants.MAX_LENGTH
.constants.MAX_STRING_LENGTH
The last 5 methods/properties are special in that they're exposed by the module returned by
require('buffer')
but not buffer instances or the globalBuffer
object.I'm sure there are also other edge cases creating a Buffer from an ArrayBuffer/SharedArrayBuffer/Uint8Array that do not yet work.