0

I was provided a function like this

function toHexString(bytes) {
    const a =  bytes.map(function (byte) {
        console.log("--------------------")
        const parsedValue = ("00" + (byte & 0xFF).toString(16)).slice(-2)
        console.log(parsedValue)
        console.log(typeof parsedValue)
        console.log("--------------------")
        return ("00" + (byte & 0xFF).toString(16)).slice(-2);
    });
    console.log(a)
}
toHexString(Buffer.from("2241f2", 'hex'))

Here is the log response of it

--------------------
22
string
--------------------
--------------------
41
string
--------------------
--------------------
f2
string
--------------------

<Buffer 16 29 00>

I actually thought it gonna provide me 2241f2 in the response but it is not. Can you guys explain it to me why is that ?

If possible, Can you re-create it with a for loop to help me understand it better ?


My try using loop

const a = Buffer.from("2241f2", 'hex')
const b= []
for (let byte of a) {
    b.push(("00" + (byte & 0xFF).toString(16)).slice(-2))
}
console.log(b)

Result

[ '22', '41', 'f2' ]
Chau Loi
  • 1,106
  • 1
  • 14
  • 36
  • actually trying to understand the base code here @Touffy – Chau Loi Jan 18 '23 at 10:11
  • Alright. Fine. gog's answer should get you started. – Touffy Jan 18 '23 at 10:45
  • Can you clarify a few things : are you doing this in Node.js, and are you trying to replicate the functionality of Buffer.toString('hex') ? if so, would you update your question to reflect that ? – Touffy Jan 18 '23 at 15:39

2 Answers2

0

The result of .map is always of the same type as the source, therefore, when you use Buffer.map, the object it creates will be a Buffer too and everything you return from the callback is converted back to the underlying data type, i.e. bytes.

You can observe the same behaviour with typed arrays as well:

const uint8 = new Uint8Array([1, 2, 3]);
const hellos = uint8.map(x => 'hello');
console.log(hellos); // surprise

To get a regular array from a mapper, you have to invoke Array.map specifically:

const a =  [].map.call(bytes, function (byte) {
   fine to return strings here
})

or use a loop instead:

const a = []
for (let byte of bytes)
   a.push(...convert byte to string...)
gog
  • 10,367
  • 2
  • 24
  • 38
  • for example if I am using a simple loop, from the response of each loop what I should do next to have the similar result as above ? – Chau Loi Jan 18 '23 at 10:36
  • `Array.from` actually makes this nicer (you can pass it a mapping function as second argument, like this: `Array.from(bytes, byte => /* code that returns a string */)`) – Touffy Jan 18 '23 at 10:42
  • You are referencing the ECMA specs for the `Array` mapping function. However, a `Buffer` is not an `Array`, so an implementation would actually be completely free how to implement it. In fact there are competing implementations, see the link from my answer. – collapsar Jan 18 '23 at 10:47
  • You are correct that Node.js *could* have designed Buffers differently, but they didn't, and pointing out alternative Buffers doesn't explain in any way the observed behaviour. – Touffy Jan 18 '23 at 10:49
  • I try to do it using for loop, but it does not give me the correct answer, mind you review it @gog ? – Chau Loi Jan 18 '23 at 10:50
  • @Touffy I do not know why you insist that your point is the focus of my answer. I suggest to read it again. In a narrow sense the implementation in node.js does not matter here as the question is neither tagged that way nor does its body suggest the node.js environment (granted, it is a natural assumption that node.js is pertinent here. However, when referencing the ECMA standard the restriction to nod.js should be made explicit, best with a link into the node.js docs where it mentions the subclassing: https://nodejs.org/api/buffer.html#buffer) – collapsar Jan 18 '23 at 11:06
-1

In your mapping function you receive 'bytes' (in the sense of Buffer elements) and return strings.

However, you should preserve types here.

Change

return ("00" + (byte & 0xFF).toString(16)).slice(-2);

to

return byte & 0xff;

and everything will be fine.

If your mapping involves changing the datatypes of the elements during the mapping, expect the result to be undefined in principle - in fact it does depend on the implementation. In the node.js runtime proper you observe the behavior you describe, this substitute produces the desired output with your original code (use ethereumjs.Buffer.Buffer instead of Buffer).

collapsar
  • 17,010
  • 4
  • 35
  • 61
  • Your suggestion is just an identity (since we're iterating on bytes, they'll always be less than 0xFF). I don't think OP wants a Buffer at all as an output (see the function name). – Touffy Jan 18 '23 at 10:36
  • My suggestion is the way to go if the OP wants to employ the `map` method of the buffer object (for whatever reason, which I cannot second-guess). Your are right that what he likely wants is a simple call of Buffer's `.toString("hex")` method. – collapsar Jan 18 '23 at 10:43
  • @Touffy No, the url is correct. It is an ethereum implementation of the Buffer abstraction. See [this accepted SO answer](https://stackoverflow.com/a/71764951) – collapsar Jan 18 '23 at 10:45
  • I am amazed (not in a good way) that some people would think several kilobytes of minified code is an appropriate response to something you can solve in one line, but anyway, I don't see how that's relevant. The question is not "make it work", it's "why doesn't it work as I expect". – Touffy Jan 18 '23 at 10:50
  • 1
    @Touffy I am amazed that people criticizing other contributors' answers do not even deign to read them. The link simply illustrates the claim that other implementations exist by referring to one specimen. This is no substantial part of the answer given. – collapsar Jan 18 '23 at 10:53
  • @Touffy The main part of my answer is giving a high-level explanation 'why it does not work'. The explanation also implies that a more detailed explanation would require looking at source code of runtime implementations. I honestly do not see your point, in particular as you obviously haven't reviewed the accepted answer with the same scrutiny, as that answer is blatantly false as it refers to the `Array` object instead of `Buffer`. I suggest to move furtherer discussion to chat. – collapsar Jan 18 '23 at 10:57
  • A more general and relevant criticism of your answer is that it doesn't answer the question, contrary to your claim in the previous comment. While I agree with you that gog's is inaccurate and incomplete, at least he tries to explain. – Touffy Jan 18 '23 at 11:00
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/251234/discussion-between-collapsar-and-touffy). – collapsar Jan 18 '23 at 11:08