Skip to content
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

buffer: support boxed strings and toPrimitive #13725

Closed
wants to merge 1 commit into from

Conversation

jasnell
Copy link
Member

@jasnell jasnell commented Jun 16, 2017

Add support for Buffer.from(new String('...')) and Buffer.from({[Symbol.toPrimitive]() { return '...'; }})

const buf1 = Buffer.from(new String('this is a test'));

class Foo {
  [Symbol.toPrimitive]() {
    return 'this is a test';
  }
}
const buf2 = Buffer.from(new Foo());

/cc @bnoordhuis @addaleax

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines
Affected core subsystem(s)

buffer

@jasnell jasnell added the semver-minor PRs that contain new features and should be released in the next minor version. label Jun 16, 2017
@nodejs-github-bot nodejs-github-bot added the buffer Issues and PRs related to the buffer subsystem. label Jun 16, 2017
lib/buffer.js Outdated
@@ -170,18 +170,31 @@ Object.defineProperty(Buffer, Symbol.species, {
* Buffer.from(arrayBuffer[, byteOffset[, length]])
**/
Buffer.from = function(value, encodingOrOffset, length) {
if (value === undefined || value === null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

== null ?

lib/buffer.js Outdated

if (typeof value === 'number')
throw new TypeError('"value" argument must not be a number');

if (typeof value === 'string')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO we should be promoting this and the other more common cases to the top of this function. This is why typeof value === 'number' was at the very end for example.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, good point, I updated and shifted the number check back down a bit. It cannot be at the bottom like before because doing so causes the valueOf option to go into a recursion loop.

throw new TypeError(kFromErrorMsg);

if (typeof value === 'number')
throw new TypeError('"value" argument must not be a number');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it would be good to use internal/errors here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to be updating the buffer errors all at once very soon.

lib/buffer.js Outdated
if (typeof value === 'number')
throw new TypeError('"value" argument must not be a number');

const valueOf = value.valueOf();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should be more cautious here or not, in case someone passes say Object.create(null). Perhaps value.valueOf && value.valueOf() at the very least ?

lib/buffer.js Outdated
throw new TypeError('"value" argument must not be a number');
if (typeof value === 'object' &&
typeof value[Symbol.toPrimitive] === 'function') {
return Buffer.from(value[Symbol.toPrimitive](), encodingOrOffset, length);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should call value[Symbol.toPrimitive] with a hint argument of 'string', I would say

lib/buffer.js Outdated
const valueOf = value.valueOf();
if (valueOf !== value)
return Buffer.from(valueOf, encodingOrOffset, length);

var b = fromObject(value);
Copy link
Contributor

@mscdex mscdex Jun 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we're supposedly no longer bound by Crankshaft's inlining limitations, perhaps we might also move the isUint8Array() case from fromObject() into this function, right below the isAnyArrayBuffer() case?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm updating to handle the other suggestions, I'll look at this one separately.

@Fishrock123
Copy link
Contributor

Is there any real use to supporting new String('...')? I think we should try to dissuade users from using Primitive-Objects when possible.


```js
const buf = Buffer.from(new String('this is a test'));
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's just me, but I'm missing the outcome. Like:

buf.toString() === 'this is a test'

Or even:

console.log(buf)

outputs:

<Buffer 74 68 69 73 20 69 73 20 61 20 74 65 73 74>

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I understand your point here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You show the correct usage, but not the expected outcome. It feels incomplete, but I don't have a strong opinion.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except something @addaleax wrote somewhere, maybe we'll be able to run the snippets in the docs as a sort of acceptance test. For that we need some assertion on outcomes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, ok

lib/buffer.js Outdated
var b = fromObject(value);
if (b)
return b;

if (typeof value === 'number')
throw new TypeError('"value" argument must not be a number');
if (typeof value === 'object' &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tiny nit: you can try to access properties on any !(value === undefined || value === null) value so maybe just (typeof value[Symbol.toPrimitive] === 'function')?

@jasnell
Copy link
Member Author

jasnell commented Jun 17, 2017

@Fishrock123 ... it's more about principle of least-surprise. The lack of support for new String() surprised at least one user recently #13652. It's the kind of thing that users would likely expect to work, even if we wouldn't necessarily encourage them to use it much.

@jasnell jasnell force-pushed the buffer-from-boxed branch from 9baef7f to b38d925 Compare June 19, 2017 17:22
@jasnell
Copy link
Member Author

jasnell commented Jun 19, 2017

@mscdex
Copy link
Contributor

mscdex commented Jun 19, 2017

Looks like this needs rebasing and lint errors fixed.

Add support for `Buffer.from(new String('...'))` and
`Buffer.from({[Symbol.toPrimitive]() { return '...'; }})`
@jasnell
Copy link
Member Author

jasnell commented Jun 19, 2017

Ugh. The most recent commit on master broke linting and was force pushed 2 hours after landing. It appears that it was force pushed as I was submitting this which broke everything. Rebasing now and will restart it

@jasnell jasnell force-pushed the buffer-from-boxed branch from b38d925 to 9b4c8b2 Compare June 19, 2017 18:01
@jasnell
Copy link
Member Author

jasnell commented Jun 19, 2017

jasnell added a commit that referenced this pull request Jun 19, 2017
Add support for `Buffer.from(new String('...'))` and
`Buffer.from({[Symbol.toPrimitive]() { return '...'; }})`

PR-URL: #13725
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
@jasnell
Copy link
Member Author

jasnell commented Jun 19, 2017

Landed in 22cf25c

@jasnell jasnell closed this Jun 19, 2017
addaleax pushed a commit that referenced this pull request Jun 20, 2017
Add support for `Buffer.from(new String('...'))` and
`Buffer.from({[Symbol.toPrimitive]() { return '...'; }})`

PR-URL: #13725
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
@addaleax addaleax mentioned this pull request Jun 21, 2017
addaleax pushed a commit that referenced this pull request Jun 21, 2017
Add support for `Buffer.from(new String('...'))` and
`Buffer.from({[Symbol.toPrimitive]() { return '...'; }})`

PR-URL: #13725
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
addaleax pushed a commit that referenced this pull request Jun 24, 2017
Add support for `Buffer.from(new String('...'))` and
`Buffer.from({[Symbol.toPrimitive]() { return '...'; }})`

PR-URL: #13725
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
rvagg pushed a commit that referenced this pull request Jun 29, 2017
Add support for `Buffer.from(new String('...'))` and
`Buffer.from({[Symbol.toPrimitive]() { return '...'; }})`

PR-URL: #13725
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
addaleax pushed a commit that referenced this pull request Jul 11, 2017
Add support for `Buffer.from(new String('...'))` and
`Buffer.from({[Symbol.toPrimitive]() { return '...'; }})`

PR-URL: #13725
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
addaleax pushed a commit that referenced this pull request Jul 18, 2017
Add support for `Buffer.from(new String('...'))` and
`Buffer.from({[Symbol.toPrimitive]() { return '...'; }})`

PR-URL: #13725
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
@gibfahn
Copy link
Member

gibfahn commented Jan 15, 2018

Release team decided not to land on v6.x, if you disagree let us know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
buffer Issues and PRs related to the buffer subsystem. semver-minor PRs that contain new features and should be released in the next minor version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants