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

Support a number as key in object when packing as MAP? #187

Open
majianjia opened this issue Aug 19, 2021 · 7 comments
Open

Support a number as key in object when packing as MAP? #187

majianjia opened this issue Aug 19, 2021 · 7 comments

Comments

@majianjia
Copy link

majianjia commented Aug 19, 2021

Hi,

I am developing a protocol in a resource constrain platform and suffer from very limited bandwidth.
We are using map(integer: any) to transfer messages.

However, this lib only packs objects as map() while the "key" in the object is required to be a string.
Using string adds at least additional 2 bytes compared to the integer, while the map(integer: bool or integer) can be only 3 bytes.

I understand this request is not commonly used in the web dev, but it is very useful for us to reduce the bandwidth.

Thanks,

@gfx
Copy link
Member

gfx commented Aug 20, 2021

You can already use an Array as the data source of encode(), so once you "translate" your objects into arrays before passing them to encode(), the encoded objects will get smaller (and IIUC that's what ProtocolBuffers does).

@majianjia
Copy link
Author

Thanks for the reply, I will try this method.

@benatkin
Copy link

I think this is important for interoperability, especially with Python, where integer keys are very common in maps.

To support I would perhaps have three: one that uses plain objects, one that uses Map, and one that calls a function asking whether to use a plain object or a Map when serializing/deserializing.

@3da
Copy link

3da commented Nov 22, 2023

I have the same issue. Would be fine if we could annotate fields in some TS interface and then it translated automatically into an object with such interface.

@yayiyao
Copy link

yayiyao commented Jan 10, 2024

same question. Object will automatically convert keys into string type, and Map objects are not supported. How to solve?

object or Map need to encode:

{ 1: 'hello', 2: 'world' }

@Aetherus
Copy link

Aetherus commented Jan 17, 2024

This is extremely important when encoding sparse arrays with very large indices, e.g. {45319: "foo", 97813: "bar"} and {[123, 321]: 0.1, [222, 333]: 0.2}

@Yotsubal
Copy link

I use this code to approach this issue, by creating custom encoder

  var Hex = "816501"; // {101: 1}

  var MsgPackEncoder = require("@msgpack/msgpack").Encoder
  var MsgPack_encoderWithNumberMap = (value, options) => {
      const encoder = new MsgPackEncoder(options);
      encoder.encodeMap = (object, depth) => {
        const keys = Object.keys(object);
        if (encoder.sortKeys) {
            keys.sort();
        }
        const size = encoder.ignoreUndefined ? encoder.countWithoutUndefined(object, keys) : keys.length;
        if (size < 16) {
            // fixmap
            encoder.writeU8(0x80 + size);
        }
        else if (size < 0x10000) {
            // map 16
            encoder.writeU8(0xde);
            encoder.writeU16(size);
        }
        else if (size < 0x100000000) {
            // map 32
            encoder.writeU8(0xdf);
            encoder.writeU32(size);
        }
        else {
            throw new Error(`Too large map object: ${size}`);
        }
        for (const key of keys) {
            const value = object[key];
            if (!(encoder.ignoreUndefined && value === undefined)) {
              // Check if Key String is a number
              if(Number(key) == key) {
                encoder.encodeNumber(Number(key));
              } else {
                encoder.encodeString(key);
              }
              encoder.doEncode(value, depth + 1);
            }
        }
      }
      return encoder.encodeSharedRef(value);
  }

  var B1 = msgPack.decode(Buffer.from(Hex, "hex"))
  var B2 = MsgPack_encoderWithNumberMap(B1, {})
  var B3 = msgPack.encode(B1, {})
  
  console.log(Buffer.from(B2).toString("hex") == Hex) // true - 816501 
  console.log(Buffer.from(B3).toString("hex") == Hex) // false - 81a331303101

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants