{"id":20182995,"url":"https://github.com/emibcn/binary-object","last_synced_at":"2025-04-10T05:23:53.472Z","repository":{"id":37095424,"uuid":"336056650","full_name":"emibcn/binary-object","owner":"emibcn","description":"Manage binary data with JavaScript strictly typed Object-oriented programming","archived":false,"fork":false,"pushed_at":"2024-10-21T07:01:56.000Z","size":2184,"stargazers_count":18,"open_issues_count":8,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-10-21T09:57:36.660Z","etag":null,"topics":["binary-data","hacktoberfest","javascript","library"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/@3m1/binary-object","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/emibcn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-02-04T19:10:44.000Z","updated_at":"2024-10-21T07:00:24.000Z","dependencies_parsed_at":"2023-02-15T07:01:38.258Z","dependency_job_id":"c76fadc7-1bd4-4158-8b36-31d98ff4ccb7","html_url":"https://github.com/emibcn/binary-object","commit_stats":{"total_commits":295,"total_committers":6,"mean_commits":"49.166666666666664","dds":0.2067796610169491,"last_synced_commit":"d52c0cb8a6ce2c6ed82fb7cd64ded4df5df389b1"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emibcn%2Fbinary-object","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emibcn%2Fbinary-object/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emibcn%2Fbinary-object/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emibcn%2Fbinary-object/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/emibcn","download_url":"https://codeload.github.com/emibcn/binary-object/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248161732,"owners_count":21057643,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["binary-data","hacktoberfest","javascript","library"],"created_at":"2024-11-14T02:43:38.675Z","updated_at":"2025-04-10T05:23:53.441Z","avatar_url":"https://github.com/emibcn.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Coverage](https://raw.githubusercontent.com/emibcn/binary-object/badges/main/test-coverage.svg)\n[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg)](CODE_OF_CONDUCT.md)\n[![DeepSource](https://deepsource.io/gh/emibcn/binary-object.svg/?label=active+issues\u0026show_trend=true\u0026token=A5qLC8ie8rosf2uYf1MoGMRy)](https://deepsource.io/gh/emibcn/binary-object/?ref=repository-badge)\n\n# Binary Object\n\nManage binary data with strictly typed JavaScript Object-oriented programming.\n\n## Summary\n\n- [Install](#install)\n- [Usage](#usage)\n  - [First: polyfill if needed](#first-polyfill-if-needed)\n  - [Second: decorators or not](#second-decorators-or-not)\n  - [API](#api)\n  - [Examples](#examples)\n- [Memory owner](#memory-owner)\n- [Use cases](#use-cases)\n  - [WebAssembly](#webassembly)\n  - [Disable Garbage Collector (GC)](#disable-garbage-collector-gc)\n  - [Workers API](#workers-api)\n  - [Saving/restoring states](#savingrestoring-states)\n  - [Accessing binary data files](#accessing-binary-data-files)\n  - [Accessing binary APIs](#accessing-binary-apis)\n  - [Develop backend DB APIs](#develop-backend-db-apis)\n- [See also](#see-also)\n\n## Install\n\nWith `npm`:\n\n```shell\nnpm install binary-object\n```\n\nWith `yarn`:\n\n```shell\nyarn add binary-object\n```\n\n## Usage\n\n### First: polyfill if needed\n\nThis library uses `TextEncoder` and `TextDecoder` to transform text to and from binary data. These are JavaScript native functions, but Node lacks them. You need to polyfill them first:\n\n```javascript\nif (!(\"TextEncoder\" in global)) {\n  import(\"util\").then((nodeUtil) =\u003e {\n    global.TextEncoder = nodeUtil.TextEncoder;\n    global.TextDecoder = nodeUtil.TextDecoder;\n  });\n}\n```\n\nFor this to work on Node \u003e= 14, you need to install `util` first:\n\n```shell\nnpm install --save util\n```\n\n### Second: decorators or not\n\nThis library encourages the use of class member decorators, available in Typescript, but at a [stage 2 proposal](https://github.com/tc39/proposals#stage-2). To add it into your `Babel` configuration, you will need something like:\n\n```json\n    \"plugins\": [\n      \"@babel/plugin-transform-runtime\",\n      [ \"@babel/plugin-proposal-decorators\", { \"legacy\": true } ],\n      [ \"@babel/plugin-proposal-class-properties\", { \"loose\": true } ]\n    ]\n```\n\nIf you don't want to use decorators, you will need to use it like (not tested):\n\n```javascript\nclass MyBinaryClass extends Binary {\n  /* Functions/logic/statics */\n}\nObject.defineProperty(\n  MyBinaryClass.prototype,\n  \"someMember\",\n  binary(Types.Float32),\n);\n```\n\n### API\n\nSee autogenerated `jsdoc` API documentation at [this repo's GitHub Page](https://emibcn.github.io/binary-object).\n\n### Examples\n\n```javascript\nimport { Binary, binary, Types } from \"binary-object\";\n\n// Declare object shape\nclass BinaryTest extends Binary {\n  @binary(Types.Uint32)\n  id = 0;\n  @binary(Types.Float64)\n  testFloat = 0;\n\n  // Array of 10 low precision floating point numbers\n  @binary(Types.Array(Types.Float32, 10))\n  testFloatArray;\n\n  showId = () =\u003e console.log(`My id is ${this.id}`);\n}\n\n// Allocate memory\nconst binTest = new ArrayBuffer(BinaryTest.binarySize);\n\n// Instantiate memory parser\nconst proxyObject = new BinaryTest(binTest);\n\n// Use it\nproxyObject.id = 12345;\nproxyObject.testFloat = 7.8;\n\nexpect(proxyObject.id).toBe(12345);\nexpect(proxyObject.testFloat).toBe(7.8);\n```\n\nAccessing and modifying arrays and array elements also work:\n\n```javascript\nconst testArray = proxyObject.testFloatArray;\n\n// Iteratibility\nexpect([...testArray]).toEqual(new Array(10).fill(0));\n\n// Elements access and modification\nexpect(testArray[0]).toBe(0);\ntestArray[0] = 1;\nexpect(testArray[0]).toBe(1);\nexpect(testArray[1]).toBe(0);\ntestArray[1] = 2;\nexpect(testArray[0]).toBe(1);\nexpect(testArray[1]).toBe(2);\n\n// Modify full array\nconst newArr = [1, 0, 0, 0, 0, 0, 0, 0, 0, 1];\nproxyObject.testFloatArray = newArr;\nexpect([...testArray]).toEqual(newArr);\n```\n\nYou can define padded arrays for better performance and, maybe, enforced by API:\n\n```javascript\nconst type = Types.Uint32;\nconst length = 5;\nclass BinaryPadTest extends Binary {\n  @binary(Types.Uint8)\n  someMemberAtTheBegining;\n\n  // Here, `true` reffers to padding\n  @binary(Types.Array(type, length, true))\n  testArray;\n\n  @binary(Types.Uint8)\n  someMemberAtTheEnd;\n}\n\nconst binTest2 = new ArrayBuffer(BinaryPadTest.binarySize);\nconst testObj = new BinaryPadTest(binTest2);\n\n// The first byte of someMemberAtTheBegining forces to consume\n// a full testArray element before it (for padding)\nconst expectedSize = (length + 1) * type.bytes + 1;\nexpect(BinaryPadTest.binarySize).toBe(expectedSize);\nexpect(testObj.testArray).toBeInstanceOf(type.extractor); // Uint32Array\n```\n\nObject composition is also allowed:\n\n```javascript\nclass BinaryArrayOfNestedTest extends Binary {\n  // Array of 3 BinaryTest objects\n  @binary(Types.Array(Types.Struct(BinaryTest), 3))\n  testNested;\n\n  get id() {\n    return this.testNested[0].id;\n  }\n  set id(value) {\n    this.testNested[0].id = value;\n    return true;\n  }\n\n  @binary(Types.Uint32)\n  someNumber = 0;\n\n  showId = this.testNested[0].showId;\n}\n\nconst binTest2 = new ArrayBuffer(BinaryArrayOfNestedTest.binarySize);\nconst proxyNested = new BinaryArrayOfNestedTest(binTest2);\n```\n\nObject composition from different memory sources is also allowed:\n\n```javascript\nclass Position extends Binary {\n  @binary(Types.Uint32)\n  x;\n  @binary(Types.Uint32)\n  y;\n\n  static testCollision(pos1, pos2) {\n    ...\n  }\n\n  collision = (pos2) =\u003e this.constructor.testCollision(this, pos2);\n}\n\nclass Player extends Binary {\n  @binary( Types.Struct(Position) )\n  position;\n  @binary(Types.Float64)\n  life;\n\n  // Non managed binary data (like pointers)\n  bullets = [];\n}\n\nclass Bullet extends Binary {\n  @binary( Types.Struct(Position) )\n  position;\n  @binary(Types.Float64)\n  direction;\n}\n\nclass Game {\n  constructor() {\n    // malloc for players\n    this.binPlayers = new ArrayBuffer( Player.binarySize * 2 );\n    this.player1 = new Player( this.binPlayers );\n    this.player2 = new Player( this.binPlayers, Player.binarySize );\n\n    // malloc for bullets\n    this.maxBullets = 100;\n    this.binBullets = new ArrayBuffer( Bullet.binarySize * this.maxBullets );\n\n    // Optimize bullets by using a unique DataView for all of them\n    this.dvBullets = new DataView(this.binBullets);\n\n    // Half of the bullets for each player\n    Bullets.arrayFactory(\n      this.dvBullets,\n      maxBullets / 2,\n      0,\n      player1.bullets);\n    Bullets.arrayFactory(\n      this.dvBullets,\n      maxBullets / 2,\n      maxBullets / 2,\n      player2.bullets);\n  }\n\n  // You can move Bullets using a parallel worker or a WASM code block\n\n  // Sometimes, check if a bullet touched a victim\n  testTouched(attacker, victim) {\n    const {position: {collision}} = victim;\n    const touched = attacker.bullets.some( ({position}) =\u003e collision(position) );\n  }\n}\n\n```\n\nTransform your binary data into a JSON string:\n\n```javascript\nconsole.log(JSON.stringify(proxyNested));\n```\n\nAssign data from JS objects:\n\n```javascript\nproxyNested.testNested = { testFloatArray: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1] };\nexpect([...proxyNested.testNested.testFloatArray]).toEqual([\n  0, 0, 0, 0, 0, 0, 0, 0, 0, 1,\n]);\n```\n\nAllocate and parse a big memory chunk as array of objects:\n\n```javascript\nconst iterations = 5e5;\nconst binTest3 = new ArrayBuffer(BinaryTest.binarySize * iterations);\nconst dv3 = new DataView(binTest3);\nconst bObjList = new Array(iterations);\nfor (let i = 0; i \u003c iterations; i++) {\n  bObjList.push(new BinaryTest(dv3, BinaryTest.binarySize * i));\n}\nbObjList.forEach((obj, index) =\u003e (obj.id = `i${index}`));\nconst ids = bObjList.map(({ id }) =\u003e id);\n```\n\n## Memory owner\n\nThis library does not aims to own the memory, allowing to use it in different ways. The memory can be allocated from a parallel worker, from the WebAssembly code or from another library or API which can\nbe consumed using `ArrayBuffer` or `SharedBuffer`. It's recommended to wrap this library with the one managing the memory.\n\n**Note:** Opting in into managing your own memory (as in C) requires you to understand what you are doing at a low level. Things like dynamic array sizes or text manipulation can be a pain if you don't\nunderstand the basics (not to say about endianness or memory padding). There are several standards and known ways to manage the memory. This library aims to make it much easier to parse it (read and write),\nbut you'll still need to know how it works. Specifically, this libs does not aims to own the memory pieces: you'll need to create/allocate/move/copy/reallocate/free them around instantiating the JS binary objects.\n\n## Use cases\n\nThe environments where direct memory management would be desirable are minimal in JS. Still, there are some edge cases where it could be benefficial or mandatory to do so.\n\n### WebAssembly\n\nWebAssembly allows coding in some low level language (like C, C++ or Rust) and compiling to some binary code which can be executed by a JS interpreter (with WebAssembly API, of course).\n\nThe code compiled into WebAssembly can use dedicated libraries to communicate with the JS code. It allows accessing the DOM (thus, the `window` object), but also sharing pieces of memory\nusing `WebAssembly.Memory`. Using that, you could write complex but very fast code to do heavy calculations in your compiled code, and trigger some kind of JS re-render using the currently\ncalculated values at some time or frame-rate.\n\n### Disable Garbage Collector (GC)\n\nAs app states is mostly managed by the `ArrayBuffer` (except some JS internal caches), you can minimize GC works, which will run your game (app) much smoothly without unexpected background GC tasks.\n\n### Workers API\n\nSimilar to the WebAssembly use case, some one could create a `SharedBuffer` and use it from different Workers, allowing your app to use more than one CPU. For example in a game: you could have\nthe main worker which updates the `DOM` (or a `canvas` or a OpenGL) using the data from the buffer, while having several workers calculating 3D collisions.\n\n### Saving/restoring states\n\nAs all the data is in a single memory piece, you can easily save it to somewhere and load it later to restore the state. This could be benefficial for games, as well as AIs, 3D renderers, scientific\ncalculations, password crackers, etc.\n\n### Accessing binary data files\n\nDynamic binary reading, processing and writing (to server or directly to user), like images, audio, video, medical data (DICOM), etc.\n\n### Accessing binary APIs\n\nYou could take full advantage of browsers USB and/or Bluetooth APIs, but also you could easily communicate against binary API servers or IoT. Though, as those are usually read-only or\nstream based, you would preffer using `DataStreams.js` instead.\n\n### Develop backend DB APIs\n\nSome libraries allows maintaining shared pieces of memory between the backend app and the database. This lib could help developing Node database middlewares.\n\n## See also\n\nThere are several JS projects aiming to handle binary data:\n\n- [buffer-backed-object](https://github.com/GoogleChromeLabs/buffer-backed-object): creates objects that are backed by an ArrayBuffer\n- [@bnaya/objectbuffer](https://www.npmjs.com/package/@bnaya/objectbuffer) ([source code](https://github.com/Bnaya/objectbuffer/)): JavaScript Object like api, backed by an arraybuffer\n- [DataStream.js](https://github.com/kig/DataStream.js): library for reading data from ArrayBuffers\n- [Restructure](https://www.npmjs.com/package/restructure)\n- [Restructure (next)](https://www.npmjs.com/package/restructure-next)\n- [buffercodec](https://www.npmjs.com/package/buffercodec)\n- [Buffer Plus](https://www.npmjs.com/package/buffer-plus)\n- [Binary Protocol](https://www.npmjs.com/package/binary-protocol)\n- [Binary-parser](https://www.npmjs.com/package/binary-parser)\n- [@yotamshacham/schema](https://www.npmjs.com/package/@yotamshacham/schema)\n- [Structron](https://www.npmjs.com/package/structron)\n- [cppmsg](https://www.npmjs.com/package/cppmsg)\n- [bin-protocol](https://www.npmjs.com/package/bin-protocol)\n- [byte-data](https://www.npmjs.com/package/byte-data)\n- [binobject](https://www.npmjs.com/package/binobject)\n- [Binarcular](https://www.npmjs.com/package/binarcular)\n- [Uttori Data Tools](https://www.npmjs.com/package/@uttori/data-tools)\n- [@avro/types](https://www.npmjs.com/package/@avro/types)\n- [Structurae](https://www.npmjs.com/package/structurae)\n- [@thi.ng/unionstruct](https://www.npmjs.com/package/@thi.ng/unionstruct)\n- [Typed Array Buffer Schema](https://www.npmjs.com/package/@geckos.io/typed-array-buffer-schema)\n- [@sighmir/bstruct](https://www.npmjs.com/package/@sighmir/bstruct)\n- [binary-parser-encoder](https://www.npmjs.com/package/binary-parser-encoder)\n- [binary-encoder](https://www.npmjs.com/package/binary-encoder)\n- [c-struct](https://www.npmjs.com/package/c-struct)\n- [binary-transfer](https://www.npmjs.com/package/binary-transfer)\n- [Superbuffer](https://www.npmjs.com/package/superbuffer)\n- [@binary-files/structjs](https://www.npmjs.com/package/@binary-files/structjs)\n- [js Binary Schema Parser](https://www.npmjs.com/package/js-binary-schema-parser)\n- [jDataView/jBinary](https://github.com/jDataView/jBinary)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femibcn%2Fbinary-object","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Femibcn%2Fbinary-object","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femibcn%2Fbinary-object/lists"}