{"_id":"packet","_rev":"26-c72c470696bf85d1c52c892d17204c16","name":"packet","dist-tags":{"latest":"0.0.7","canary":"1.0.0-alpha.4"},"versions":{"0.0.1":{"name":"packet","version":"0.0.1","author":{"name":"Alan Gutierrez"},"directories":{"lib":"./lib"},"main":"./lib/packet","_id":"packet@0.0.1","engines":{"node":"*"},"_nodeSupported":true,"_npmVersion":"0.2.7-2","_nodeVersion":"v0.3.1-pre","dist":{"tarball":"https://registry.npmjs.org/packet/-/packet-0.0.1.tgz","shasum":"7bde58025efb4ce248aea49d6f342d64d54e8525","integrity":"sha512-RwXaglFO4Uf/cUFZO7fc+auKBo1xUFJeYSuCGa/USBHp99vDG4gagj0eFgQY7IDmw8nYsK1Q0IrVBqA4KdhimA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDoTUgaPUH7usyIvrLMtw1NwDNfTe4iN7DqVxKGrBj9EwIgECld23hYBfXEurxEMw0OBmwB4i1x6dw89GH+erEDwWY="}]}},"0.0.2":{"name":"packet","version":"0.0.2","author":{"name":"Alan Gutierrez"},"main":"./lib/packet","_id":"packet@0.0.2","engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"0.3.18","_nodeVersion":"v0.4.4","directories":{"lib":"./lib"},"files":[""],"_defaultsLoaded":true,"dist":{"shasum":"032c87a0e620827ce1ddf9a3fae392d09960ebe9","tarball":"https://registry.npmjs.org/packet/-/packet-0.0.2.tgz","integrity":"sha512-xXdO6si1SFqytvqi90jzErchoC5vdth6DDaSK6uKUuP4KoedDXWCYl22F77XGIczOyFx61kNSBqz19IdE42whg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDp/I5iFsXQEDeWvys6NB5jgz+LISx0pKbRW9jN79zeeAIgBRV+pEYtdxTmLGu8ZB2BOuUYIx9lkeXZsBqLhjRGmn8="}]}},"0.0.3":{"name":"packet","description":"Pure JavaScript evented binary parsers and serializers for Node.js.","version":"0.0.3","keywords":["packet","pack","binary","network","structure","async","asynchronous","javascript"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"devDependencies":{"proof":"0.0.15"},"scripts":{"test":"proof t/*/*.t"},"dependencies":{},"licenses":[{"type":"MIT","url":"http://github.com/bigeasy/packet/raw/master/LICENSE"}],"homepage":"https://github.com/bigeasy/packet","repository":{"type":"git","url":"http://github.com/bigeasy/packet.git"},"_id":"packet@0.0.3","dist":{"shasum":"0644bbc6b9e08201416ca914f7ce6abcfc83bb86","tarball":"https://registry.npmjs.org/packet/-/packet-0.0.3.tgz","integrity":"sha512-84xtWFuYaYUybwoJ9gl0Kp4CZaWHq1JnID68ik+bqx4qbmq7/JlwFGoq/2FFu/719c2zSFF7OQedXfEWb4XcaA==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIF9wbpCTpRXA8K+yValT+Kv8a60cyOoZt3cxAc6ug+BpAiBcqfXtXSpCq13tw3SV/LKBGep3JrwdIhInv3o3ykCLbQ=="}]},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{}},"0.0.4":{"name":"packet","description":"Pure JavaScript evented binary parsers and serializers for Node.js.","version":"0.0.4","keywords":["packet","pack","binary","network","structure","async","asynchronous","javascript"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"devDependencies":{"proof":"0.0.15"},"scripts":{"test":"proof t/*/*.t.js"},"dependencies":{},"licenses":[{"type":"MIT","url":"http://github.com/bigeasy/packet/raw/master/LICENSE"}],"homepage":"https://github.com/bigeasy/packet","repository":{"type":"git","url":"http://github.com/bigeasy/packet.git"},"_id":"packet@0.0.4","dist":{"shasum":"f04197c22952469ab1c5796ef1711dec30d73ea9","tarball":"https://registry.npmjs.org/packet/-/packet-0.0.4.tgz","integrity":"sha512-05aSk9gUfhXhpiVYHsWain4s0IfMmokN/N0ROcbBRMsAMRs7AlZB5AySN/kklf76llxqLO87UG8/b19ZW162MQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHMOhg4CuJBd2y8/BXigncHfxpd38yTGW5K5rQVcv/OmAiAg8xZYuleOkACrRYsK+ealyfGtofmcEQqZJNGJxhSXfw=="}]},"_npmVersion":"1.1.65","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{}},"0.0.6":{"name":"packet","description":"Pure JavaScript evented binary parsers and serializers for Node.js.","version":"0.0.6","keywords":["packet","pack","binary","network","structure","async","asynchronous","javascript"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"devDependencies":{"proof":"0.0.30"},"scripts":{"test":"proof platform win32 && proof test */*/*.t.js || t/test"},"dependencies":{},"licenses":[{"type":"MIT","url":"http://github.com/bigeasy/packet/raw/master/LICENSE"}],"homepage":"https://github.com/bigeasy/packet","repository":{"type":"git","url":"http://github.com/bigeasy/packet.git"},"contributors":[{"name":"J. Ryan Stinnett","email":"jryans@gmail.com"}],"bugs":{"url":"https://github.com/bigeasy/packet/issues"},"_id":"packet@0.0.6","dist":{"shasum":"3ca96bcf65f2da62fa340db09239d79c0cc30e4a","tarball":"https://registry.npmjs.org/packet/-/packet-0.0.6.tgz","integrity":"sha512-TdFl5Z4EoOeXTQfvaGmJSBsTPrAJyCcoge9qncpvoDzrRVWKXfO/PSC4q5XhB59LA2dki0BKgt55Iq55MxCXzQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIF6vbuwiyyHDP3wzhJCbfXPk9pGgOGXp2tYmdCU3V4MGAiEAhMBsv++JYnQmTffmee3g9AzxI+/sj8qClsnPGXMjJQU="}]},"_from":".","_npmVersion":"1.2.30","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"directories":{}},"0.0.7":{"name":"packet","version":"0.0.7","author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"description":"Pure JavaScript evented binary parsers and serializers for Node.js.","keywords":["packet","pack","binary","network","structure","async","asynchronous","javascript"],"homepage":"https://github.com/bigeasy/packet","bugs":{"url":"https://github.com/bigeasy/packet/issues"},"devDependencies":{"proof":"0.0.50","uglify-js":"~1.3"},"dependencies":{"programmatic":"0.0.8"},"repository":{"type":"git","url":"http://github.com/bigeasy/packet.git"},"contributors":[{"name":"J. Ryan Stinnett","email":"jryans@gmail.com"},{"name":"Ben Hockey","email":"neonstalwart@gmail.com"},{"name":"Greg Ose","email":"neonstalwart@gmail.com","url":"http://nullmethod.com/"},{"name":"Aaron Qian","email":"aq1018@gmail.com"},{"name":"Demarius Chrite","email":"chrite.demarius@gmail.com","url":"https://github.com/demarius"}],"license":"MIT","scripts":{"test":"proof platform win32 && proof test */*/*.t.js || t/test"},"gitHead":"0cab0323415de6d4b2d1e535ca455ad7c49d512f","_id":"packet@0.0.7","_shasum":"bc3e2ae338891ef9cd0a339caa5c66c26b3af028","_from":".","_npmVersion":"1.4.28","_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"dist":{"shasum":"bc3e2ae338891ef9cd0a339caa5c66c26b3af028","tarball":"https://registry.npmjs.org/packet/-/packet-0.0.7.tgz","integrity":"sha512-o83Ca6dr8qNuioY3RF0LxGZY6o8vuYfKBHHCzQx+5Ia+PWqWJKAPlIxe4SJJunVwhvYhyhX5lQBiSE8rR2rRjg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC3+ISW79/HZayFEPuFjiRlhvhm4A+76YPFH3peOixF2QIgZbxIENF9hjR0boYBUzZ7vheCHDUfJkxMOXUW53TZN/w="}]},"directories":{}},"1.0.0-alpha.0":{"name":"packet","version":"1.0.0-alpha.0","description":"Pure JavaScript evented binary parsers and serializers for Node.js.","keywords":["packet","pack","binary","network","structure","async","asynchronous","javascript"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"contributors":[{"name":"J. Ryan Stinnett","email":"jryans@gmail.com"},{"name":"Ben Hockey","email":"neonstalwart@gmail.com"},{"name":"Greg Ose","email":"neonstalwart@gmail.com","url":"http://nullmethod.com/"},{"name":"Aaron Qian","email":"aq1018@gmail.com"},{"name":"Demarius Chrite","email":"chrite.demarius@gmail.com","url":"https://github.com/demarius"}],"homepage":"https://github.com/bigeasy/packet","bugs":{"url":"https://github.com/bigeasy/packet/issues"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/bigeasy/packet.git"},"dependencies":{"fast-deep-equal":"3.1.3","programmatic":"2.0.0-alpha.9"},"devDependencies":{"extant":"^2.0.0-alpha.0","proof":"^9.0.3"},"main":"packet.js","scripts":{"test":"proof -n --allow-natives-syntax test/*/*.t.js"},"nyc":{"exclude":["test/**","!test/generated","inlines.js"]},"readme":"[![Actions Status](https://github.com/bigeasy/packet/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/packet/actions)\n[![codecov](https://codecov.io/gh/bigeasy/packet/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/packet)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA comparator function builder.\n\n| What          | Where                                         |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/packet/issues/1    |\n| Documentation | https://bigeasy.github.io/packet              |\n| Source        | https://github.com/bigeasy/packet             |\n| Issues        | https://github.com/bigeasy/packet/issues      |\n| CI            | https://travis-ci.org/bigeasy/packet          |\n| Coverage:     | https://codecov.io/gh/bigeasy/packet          |\n| License:      | MIT                                           |\n\n\n```\nnpm install packet\n```\n\nIncremental binary parsers and serializers for Node.js.\n\n### Diary\n\nIn the middle of the final rewrite after many years of learning about Node.js.\n\nCurrently working in the `compose` folder to create compiled parsers based on\nthe work in `composer`.\n\n### Continue\n\nPacket creates **pre-compiled**, **pure-JavaScript**, **binary parsers** and\n**serializers** that are **incremental** through a binary pattern language that\nis **declarative** and very **expressive**.\n\nRewrite pending.\n\nPacket simplifies the construction an maintenance of libraries that convert\nbinary to JavaScript and back. The name Packet may make you think that it is\ndesigned solely for binary network protocols, but it is also great for reading\nand writing binary file formats.\n\n**Incremental** &mdash; Node packet creates incremental parsers and serializers\nthat are almost as fast as the parser you'd write by hand, but a lot easier to\ndefine and maintain.\n\n**Declarative** &mdash; Packet defines a binary structure using a pattern\nlanguage inspired by Perl's `pack`. The binary patterns are used to define both\nparsers and serializers. If you have a protocol specification, or even just a C\nheader file with structures that define your binary data, you can probably\ntranslate that directly into Packet patterns.\n\nFor parsers, you associate the patterns to callbacks invoked with captured\nvalues when the pattern is extracted from the stream. For serializers you simply\ngive the values to write along with the pattern to follow when writing them.\n\n**Expressive** &mdash; The pattern language can express\n\n  * signed and unsigned integers,\n  * endianess of singed and unsigned integers,\n  * floats and doubles,\n  * fixed length arrays of characters or numbers,\n  * length encoded strings of characters or numbers,\n  * zero terminated strings of characters or numbers,\n  * said strings terminated any fixed length terminator you specify,\n  * padding of said strings with any padding value you specify,\n  * signed and unsigned integers extracted from bit packed integers,\n  * conditions based on bit patterns\n  * character encodings,\n  * custom transformations,\n  * and pipelines of character encodings and custom transformations.\n\n### Limitations\n\n**Parsing not searching** &mdash; Packet is not a pattern matching library. It\ndoes not search binary streams for patterns. Packet is used for parsing\nwell-defined streams of binary data.\n\n**8-bit boundaries** &mdash; I'm unable to think of an example in contemporary\ncomputing that doesn't align to an 8-bit boundary, but the world is big and I am\nsmall, so I plan on being surprised. I can also imagine that someone might want\nto unleash Packet on legacy data someday, from way back when a byte was whatever\na computer manufacturer said it was.\n\nTherefore, It's worth noting that Packet parses 8-bit bytes and expects bytes to\nalign to an 8-bit boundary. Packet can parse 7-bit ASCII formats like `tar`\narchives, because they are 8-bit aligned with the top bit ignored. Packet can\nalso parse and serialize bit packed integers, so it does support awkward integer\nsizes, but within an 8-bit aligned integer.\n\n## Installing\n\nInstall Packet using NPM.\n\n```\nnpm install packet\n```\n\nThe source is available on [GitHub](https://github.com/bigeasy/packet).\n\n## Parsers and Serializers\n\nPacket defines a binary format using a binary pattern language inspired by\nPerl's `pack` function. The pattern language is used in a `Parser` to define the\nparameters passed to callback when enough bytes are read from the input stream\nto satisfy the pattern. The pattern language is used in a `Serializer` to define\nhow JavaScript primitives passed to the `serialize` method are written to\nstream.\n\n### Patterns\n\nPatterns are a series of element declarations joined by commas.\n\n```javascript\nparser.extract(\"length: b16, address: b32, name: b8z\", function (object) {\n  console.log(object.length, object.address, object.name);\n});\nparser.parse([ 0x01, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00 ]);\n```\n\nYou can also name the elements in a pattern. If named, parsers will be create an\nobject to pass to callbacks, serializers will serialize an object's properties.\n\n```javascript\nparser.extract(\"b16 => length, b32 => address, b8z => name\", function (record) {\n  console.log(record);\n});\nparser.parse([ 0x01, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00 ]);\n```\n\nUnnamed elements are good for short, simple patterns. For longer patterns it is\neasier to have a parser build an object for you.\n\nThe following example shows a complicated pattern, the invariable portion of an\nIP header, the first 20 bytes before options, if any.\n\n```javascript\n// Define an IP header pattern using a joined array to explode the pattern.\nparser.packet('ip', 'b8{version: b4, headerLength: b4},         \\\n                     typeOfService: b8,                         \\\n                     length: b16,                               \\\n                     identification: b16,                       \\\n                     b16{flags: b3, fragmentOffset: b13},       \\\n                     timeToLive: b8,                            \\\n                     protocol: b8,                              \\\n                     checksum: b16,                             \\\n                     sourceAddress: b32,                        \\\n                     destinationAddress: b32                    \\\n                    ');\n\n// The pattern is then used to defined parser and serializer actions.\nparser.extract(\"ip\", function (header) {\n  console.log(header);\n});\nparser.parse(buffer);\n```\n\nBoth parsers and serializers can define patterns using the `packet` method. The\n`packet` method allows you to pre-compile patterns.\n\n```javascript\n// Create a parser and define a header.\nvar parser = require('packet').createParser();\nparser.packet(\"header\", \"b8 => type, b16 => length, b32 => extra\");\nparser.packet(\"data\", \"b16 => sequence, b16 => crc\");\n\n// Now you can define your serializer using your parser as a prototype. The\n// serializer will inherit the parser's packet definitions.\nvar serializer = parser.createSerializer();\n```\n\nParsers and serializers maintain internal state so that they can be used\nincrementally. If you're going to parse streams incrementally, you're going to\nneed a parser for each stream your parsing. Same goes for serializers and\nserializing.\n\nWhen parsing/serializing incrementally create new parsers and serializers using\nthe prototype pattern above.\n\n```javascript\n// Create a serializer and define a header.\nvar serializer = require(\"packet\").createSerializer();\nserializer.packet(\"header\", \"b8 => type, b16 => length, b32 => extra\");\nserializer.packet(\"data\", \"b16 => sequence, b16 => crc\");\n\n// Now you can define parsers for a using the serializer as a prototype.\nnet.createServer(function (socket) {\n  var parser = serializer.createParser();\n  socket.on(\"data\", function (buffer) {\n    parser.parse(buffer);\n  });\n  parser.extract(\"header\", function (header) {\n    console.log(header);\n  });\n});\n```\n\n### Parsers\n\nParsers parse a buffer extracting a specified pattern. The pattern is specified\nusing the `extract` method. The `extract` method accept either a pattern or the\nname a pre-compiled pattern.\n\nAfter the pattern has been specified, the parser will extract the data from one\nor more buffers according to the specified pattern.\n\nWhen the pattern specified by `extract` has been read from the series of\nbuffers, it will invoke a callback with the extracted values. The `extract`\ncallback has the option of calling the `extract` method specifying a subsequent\npattern for the parser to extract. When the callback returns, the parser will\nimmediately continue to parse the newly specified pattern from the series of\nbuffers.\n\nThe parser callback receives the values either as positioned function arguments\nor as an object. How the callback is invoked is based on the pattern and the\n[arity](http://en.wikipedia.org/wiki/Arity) of the callback function.\n\nTo receive an object in the callback, we defined named elements. When the\npattern has at least one named element, and the callback has only a single\nargument, an object is passed to the callback containing the values using the\nelement names as keys.\n\nUnnamed elements are excluded, but there's no good reason not name them. Use a\nskip pattern to skip over unwanted bytes instead.\n\nYou can still get positioned arguments using a named pattern. Just provide a\ncallback with more than one argument and it will be invoked with the extract\nvalues as parameters.\n\nA callback for a pattern without any named elements is always invoked with\nvalues as parameters regardless of arity.\n\n### Serializers\n\nFirst you call `serialize` with a pattern and arguments to serialize, then you\ncall `write` with a series of buffers.\n\n## Binary Pattern Fields\n\nThe binary pattern language is used to specify the fields binary structures in\ndata streams, using a comma separated field pattern.\n\n### Big-Endian Byte Ordering\n\nTo define a big-endian byte ordering for a field, prefix the bit size with `b`.\n\n```yaml\nmnemonic: The letter `b` stands for big-endian.\nexamples:\n  -\n    pattern: world: b16\n    object:\n      word: 256\n    description: Big-endian 32 bit number.\n  -\n    pattern: byte: b8\n    object:\n      byte: 1\n    description: Endianess of a single byte is irrelevant.\n  -\n    pattern: word: l16, byte: b8\n    object:\n      word: 1\n      byte: 1\n    parsed: 0x01, 0x00, 0x01\n```\n\n**Mnemonic**: The letter `b` stands for big-endian.\n\n```javascript\n\"b16\"             // Big-endian 32 bit number.\n\"b8\"              // Endianess of a single byte is irrelevant.\n\"l16, b8\"         // Big-endian 16 bit integer followed by a byte.\n```\n\n### Little-Endian Byte Ordering\n\nTo define a little-endian byte ordering for a field, prefix the bit size with `l`.\n\n**Mnemonic**: The letter `l` stands for little-endian.\n\n```javascript\n\"l32\"             // Little-endian 32 bit integer.\n\"l8\"              // Endianess of a single byte is irrelevant.\n\"l16, b8\"         // Little endian 16 bit integer followed by a byte.\n```\n\n### Skipping Bytes\n\nYou can skip over bytes your pattern with `x`.\n\n**Mnemonic**: The letter `x` means to cross-out, which is kind of like skipping.\n\n```javascript\n\"b8, x16, l16\"    // A byte, two skipped bytes, and a little-endian 16 bit\n                  // integer.\n```\n\n### Signed Versus Unsigned Integers\n\nAll numbers are assumed to be unsigned, unless prefixed by a negative symbol.\n\n**Mnemonic**: The `-` symbol indicates the possibility of negative numbers.\n\n```javascript\n\"-b32\"            // Big-endian 32 bit signed integer.\n\"-l32\"            // Little-endian 32 bit signed integer.\n\"b32\"             // Big-endian 32 bit unsigned integer.\n```\n\n### IEEE 754 Floating Point Numbers\n\nThe number type for JavaScript is the  64 bit IEEE 754 floating point. Packet\ncan read write 64 bit and 32 bit IEEE 754 floating point numbers.\n\nTo indicated that the type is a floating point number, use the `f` type suffix.\nThis is indicated with a `f` suffix.\n\n**Mnemonic**: The letter `f` stands for\n*floating-point*.\n\n```javascript\n\"b64f\"            // Big-endian 64 bit IEEE 754 double floating point number.\n\"l32f\"            // Little-endian 32 bit IEEE 754 single floating point number.\n```\n\nThe floating-point numbers can be stored in little-endian or big-endian byte order.\n\n### Arrays of Raw Bytes\n\nA value will be converted to a big-endian array of bytes if followed by an `a`\nsuffix.\n\n**Mnemonic**: The letter `a` stands for *array*.\n\n```javascript\n\"l128a\"           // Unsigned little-endian 128 bit integer as big-endian array\n                  // of bytes.\n```\n\nNote that big-endian means that the most significant byte is at index `0` of the\narray.\n\nThis can be surprising if you're expecting the significance of the bytes will\nincrease with the index of the array, but then that's what little-endian is all\nabout. (Big-endian orders like Arabic numerals, while little-endian orders like\noffsets into memory.)\n\nIf you'd prefer a little-endian array, simply call `reverse` on the array passed\nto you.\n\n### Arrays of Common Types\n\nIt is often the case that a binary format contains an array of values. The most\ncommon case are arrays of bytes representing ASCII or UTF-8 strings.\n\nArrays are specified with an subscript and a count.\n\n**Mnemonic**: The square brackets are used as array subscripts in JavaScript,\nand used to declare array length in other C dialect languages.\n\n```javascript\n\"b32[4]\"          // An array of four big-endian 32 bit numbers.\n\"b8[16]\"          // An array of 16 bytes.\n```\n\nThe array notation produces an array of the type before the subscript.\n\n### Zero Terminated Arrays\n\nZero terminated series are specified with a `z` qualifier.\n\nYou can specify both termination and width together. Why would you need this?\nThis occurs in underlying C structures when there is a fixed width character\narray in a structure, but the structure still contains a zero terminated string.\n\n**Upcoming**: Chose your own terminator.\n\n**Mnemonic**: The letter `z` stands for zero.\n\n```javascript\n\"l16z\"            // Little-endian 16 bit numbers terminated by a zero value.\n\"b8z\"             // Byte string terminated by zero.\n\"b8[12]z\"         // Byte string terminated by zero in a field 12 bytes long.\n```\n\n### Array Padding\n\nYou can specify a padding value immediately after the array brackets using curly\nbraces. This should be the numeric value, or character code for padding. If you\nwant to zero pad, use `0`. If you want to pad with ASCII spaces use `32`.\n\n**Mnemonic**: Curly braces are used to define array literals in C.\n\n```javascript\n\"b16[12]{0}\"      // Array of 12 big-endian 16 bit integers, zero padded.\n\"b8[12]{32}z\"     // Byte string terminated by zero in a field 12 bytes long\n                  // ascii space padded.\n```\n### Length Encoded Arrays\n\nLength encoded arrays are specified by joining a count type and a value type\nwith a forward slash character `/`.\n\n**Mnemonic**: Inspired by Perl's `pack`, which uses the slash to separate count\nand type.\n\n```javascript\n\"b8/b8\"           // Length encoded byte array with a byte length.\n\"l16/b8\"          // Length encoded byte array with 16 bit little-endian length.\n```\n\n### Bit Packed Integers\n\nIntegers are often divided into smaller integers through a process called bit\npacking. Bit packing is specified by following an integer specification with\na curly brace enclosed series series of integers patterns whose total size in\nbits equals the size of the packed integer.\n\nPacked integers are always big-endian and can be either singed or unsigned.\n\n**Mnemonic** Curly braces are used to define structures in C and bit packing is\nkind of like a structure.\n\n```javascript\n\"b16{b3,x6,-b7}\"  // A 16 bit big-endian integer divided into a 3-bit integer,\n                  // 6 skipped bits, and a signed 7-bit integer.\n```\n\nYou can also name the packed fields.\n\n```javascript\n\"b16{b3 => type, x6, -b7 => count}\"\n```\n\n### Alternate Patterns\n\nA common pattern in binary formats is using the value of a byte, or the high\norder bits of a byte to specify the type of data to follow. [Length Encoded\nArrays](#length-encoded-arrays) are one example of this practice, where a\nan integer count indicates the length of a following string or array.\n\nWith an alternate pattern, **Packet** will extract an integer from the byte\nstream, then choose a pattern based on the value of that integer. The pattern is\napplied at the index where the integer used to choose the pattern was extracted.\nThat is, the bytes used to choose the pattern are included when the pattern is\napplied. It is a peek and switch.\n\nAlternate patterns are grouped by parenthesis `(` and `)` and delimited by pipes\n`|`. Each alternative maps a match to a pattern separated by a colon `:`.\n\n**Mnemonic** &mdash; Parenthesis and pipes are used to indicate alternation in\nregular expressions, while colons are used to delineate switch options in C.\n\n```javascript\n// MySQL length coded binary; if the byte is less than 252, use the byte value,\n// otherwise the byte value indicates the length of the following word.\n\"b8(0-251: b8 | 252: x8, b16 | 253: x8, b24 | 254: x8, b64)\"\n```\n\nConditions are either a value to match exactly or a range of values. **Packet**\ntests each condition is tested in order. **Packet** uses the alternation of the\nfirst condition to match the extracted integer is used. An alternate without a\ncondition will always match. This is used to specify a default pattern.\n\n```javascript\n// Simpiler, but will also match 255 which is invalid, which is fine if you test\n// the value in your callback.\n\"b8(252: x8, b16 | 253: x8, b24 | 254: x8, b64 | b8)\"\n```\n\nThe values can be expressed in binary, decimal or hexadecimal.\n\n### Bitwise Alternate Patterns\n\nYou can also indicate a branch based on set bits by prefixing the value with an\nampersand. **Packet** will use the value as a bit mask. If the result of a\nlogical *and* with the bit mask equals the bit mask, then **Packet** use use\nthat alternative.\n\n**Mnemonic** The `&` performs a logical and in C and is used to check to see if\nbits in a bit mask are set.\n\n```javascript\n\"b8(&0x80: b16{x1,b15} | b8)\"   // A 15-bit word if the first bit is set,\n                                // otherwise a byte.\n```\n\nBitwise conditions cannot be used in to choose a pattern for serialization. Upon\nserialization, the field value is a JavaScript number, not an stream of bytes.\nThe bit flag simply does not exist.\n\nInstead, we need to perform a range check to determine which pattern. To delimit\nalternate tests for reading and writing, we use a slash in the condition.\n\n```javascript\n// A 15-bit word if the first bit is set, otherwise a byte.\n\"b8(&0x80/0x80-0xffff: b16{x1{1},b15} | b8)\"\n```\n\n### Multi-Field Alternate Patterns\n\nAlternate patterns can define either a single field or multiple field.\nAlternate patterns can contain bit-packed patterns, but they cannot contain\nstill more alternate patterns.\n\n```javascript\n// Two alternate patterns with a different number of fields.\n\"b8(&0x80/1: b16{b1, b15}, b16|b32{b1, b31})\"\n```\n\nIn the above example, the serialization test would be applied to the field value\nin the position of the `b1` field for either alternate.\n\n### Named Alternate Patterns\n\nNames can be applied either to the entire alternation if the alternation\nproduces a single field, or else to individual members of the alternate\npatterns.\n\n```\n// A single field mapped to a name.\n\"b8(&0x80/0x80-0xffff: b16{x1{1},b15} | b8) => number\"\n```\n\nWhen serializing named multi-field patterns, for each alternate, **Packet** will\nuse the first value of the property in the alternate for the serialization\ncondition. **Packet** reads the property from the object we're serializing. If\nthe value is not null, it is tested against the serialization condition. If it\nis null, the test is skipped. We use the first alternate whose object property\nis not null and whose serialization condition matches the object property.\n\n```javascript\n// Multi-field alternates mapped to names.\n\"b8(&0x80/1: b16{b1 => control, b15 => type}, x16|b32{b1 => control, b31 => sequence})\"\n```\n\n### Transforms\n\nOften there are transformations that you need to perform on an field to get\nit to its final state. You may need to convert a byte array to string of a\nparticular character encoding, for example. This is done with a transformation\nfunctions which are specified with a transformation pipeline.\n\nIf the transformation is a fixed transformation, you can perform the\ntransformation by defining a pipeline. A pipeline defines one or more\ntransformations that are invoked on the value after parsing and before\nserialization. The transformations can accept scalar JavaScript parameters.\n\n```javascript\nfunction str(encoding, name, field, parsing, value) {\n    if (parsing) {\n        var buffer = new Buffer(array.length)\n        for (var i = 0; i &lt; value.length; i++) {\n            buffer[i] = value[i];\n        }\n        var length = value.length\n        if (field.terminator) {\n            length += field.terminator.length;\n        }\n        return buffer.toString(encoding, 0, length);\n    } else {\n        if (field.terminator) {\n            value += field.terminator;\n        }\n        return new Buffer(value, encoding);\n    }\n}\n```\n\nNow you can use the transform in your pattern.\n\n```javascript\n\"b8z|str('ascii')\"      // An ascii string terminated by zero.\n\"b8z|str('ascii'), b16\" // An ascii string terminated by zero followed by a\n                        // big-endian 16 bit integer.\n```\n\nThe `str` transform is defined by default. The transform names are purposely\nterse to fit with the brevity of the pattern language.\n\n## Error Messages\n\nError messages for pattern parsing.\n\n * **invalid pattern at N** &mdash; The characters starting at the specified\n   index is unexpected the pattern is invalid. The invalid character may not be\n   at the specified index, but shortly there after, such as unmatched braces.\n * **bit field overflow at N** &mdash; The sum of the bit size of bit field\n   elements is greater than the size of the containing element. The sum of the\n   bit size of bit field elements must equal the size of the containing element.\n * **bit field underflow at N** &mdash; The sum of the bit size of bit field\n   elements is less than the size of the containing element. The sum of the bit\n   size of bit field elements must equal the size of the containing element.\n * **bit size must be non-zero at N** &mdash; Encountered element with a bit size of\n   zero. Element size must be a non-zero value.\n * **bits must be divisible by 8 at N** &mdash; Encountered element with a bit\n   size that is not divisible by 8. If an element is not a bit field element, it\n   must align to an 8-bit boundary.\n * **floats can only be 32 or 64 bits at N** &mdash; Encountered a float element\n   with an unsupported bit size. Only 32 and 64 bit floats are supported.\n * **\"array length must be non-zero at N** &mdash; Encountered an array length\n   of zero. Arrays must have a non-zero length.\n\n## Change Log\n\nChanges for each release.\n\n### Version 0.0.6\n\nWed Jul  3 21:52:20 UTC 2013\n\n * Implement `Serializer.offsetsOf`. #87. #85. #86. #63.\n * Objects primary, positional arguments secondary. #84.\n * Reset namedness of `Parser`. #83.\n * Serialize and parsed a named length encoded array. #82.\n * Increase test coverage.  #77. #69. #68. #67. #66.\n * Test text to float conversion. #66.\n * Remove `n` syntax from README. @jryans. #64.\n * Remove detection of `n` synonym for `b`.\n * Remove asterisk to indicate wildcard condition. #33.\n * `Parser.parse` returns bytes read. #60.\n * Report coverage to Coveralls. #61.\n * Rename `pattern` to `field`. #57.\n * Massive tidy after change in enclosed objects.\n\n### Version 0.0.5\n\nFri Mar  1 03:05:15 UTC 2013\n\n * Chunked serialization bug fixes. #59. #58. #55.\n * Move supporting libraries to root directory. #44.\n * Spell check `README.md` and remove dead features. #32. #55.\n * Implement `sizeOf` property for serializer. #37.\n * Fix minimum number value. #54.\n\n### Version 0.0.4\n\nMon Nov  6 04:50:16 UTC 2012.\n\n * Create parsers and serializers from prototypes. #53.\n * Parse patterns with Win32 CRLF. #51. (Greg Ose <greg@nullmethod.com>)\n * Copy cached pattern for alternation rewriting. #50.\n * Flatten alternation prior to serialization. #34.\n * Add `.js` suffix to tests. #49.\n * Convert to closure style. #40, #47, #39, #38, #27.\n * Remove pausing from `Parser`. #46.\n * Implement `reset` for serializer. #43.\n * Single letter field names. #45.\n * Remove streams from API. #41.\n\n### Version 0.0.3\n\nFri Aug 17 00:40:37 UTC 2012.\n\n * Fix Packet in NPM. #12.\n * Serialize alternate structures. #31.\n * Test serialization of words. #20.\n * Serializer not exported by `index.js`.\n * Named patterns reset buffer offset. #29.\n * Allow spaces before alternation condition. #28.\n * Create a markdown `README.md`. #18.\n * Build on Node 0.8 at Travis CI. #23.\n * Fix too greedy match of bit packing pattern. #19.\n * Skip leading whitespace in pattern. #15.\n\n## Contributors\n\n  * [Ben Hockey](https://github.com/neonstalwart)\n  * [Aaron Qian](https://github.com/aq1018)\n","readmeFilename":"README.md","gitHead":"6d0105c5265d74b7b65c72e5ac0c9d9d7718083e","_id":"packet@1.0.0-alpha.0","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-7QbBp19FgdJdNEW7SEhtIH6Ph4GCITyQ6paKHGiFgX065YDLyMQdmeffRW8lytflfRQtnUXo0PiHiUw8aL6Agg==","shasum":"1a51a739e40b52024c32cc05c4e7e9c51305f238","tarball":"https://registry.npmjs.org/packet/-/packet-1.0.0-alpha.0.tgz","fileCount":746,"unpackedSize":1127483,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgWLihCRA9TVsSAnZWagAAowIP/2wh0MFsc2ynWQ2QvgC+\nYDCkarBgiPRdDlTj1yxXgk0C4OeDC5JzIMbmVifLoK2Evu5WgjXDS/05qtiq\nu63GPZrbg8RcKEre85Ph+IZzJ1HEouBx58CkCOc6gPgrWWkQvqB8jBnjLK06\nv8Rh7EqSkXYPtw2ystgwuJUhD7wj3NPtBM/+10aZ+Hxpk4F4XA8NLJUPJ40V\neAsS2kC9g5zpp3hMMnxjaFEUmVyS9LNjvk6nQJnfeMix+RE2maOk3nFGDYki\nSTJ3lnvXNlZJgBZF1LWQveCii00tFyY5iH+BjKD07/MZBVAV0IUoo72dyHbL\nxP7Iti7M1+UfkinJ6MXvKYxAXBBX80SGBjS7/rwG4RbY76mnYOMIhVK2nonV\nGuZfhNLnNhJ7uU/DJXQJ4LIMNbgIoKRuXVUB60XnrZZxJMzUQO/WZdpC4K5Y\ntg6LGhfV1XCIbKmDtG7RvYmNgP7Sc0a82CcEeDqmDu3qLRIBB35D3B5kLK6Z\n+wdhG8orsDFMyHer/Kbq4Zob/G+W1hBKV2Fu+OSM7Y2FmbVBBYR8utI2BvDU\nFaipT5NBI6NCwW4TUb8hH1C+68MRq7lW8t8PftKZutAg3CySA2yn+jc5jt76\njYp3gNSGwiYb/Zdkv8MAavRW4Hwx9ElxGkLAYW1wi1eYz3MKhwkw+flKXjmt\nM1MB\r\n=KT8u\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBfNc+MupoAeMCC2mfDm/VplyZyoeY3Oj6cS5HTwxP8PAiB5Rp9FZPE9gGSULs7diuB+ETZCwUWf/jyJQKp+LuFgWQ=="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/packet_1.0.0-alpha.0_1616427168653_0.3373201579617444"},"_hasShrinkwrap":false},"1.0.0-alpha.1":{"name":"packet","version":"1.0.0-alpha.1","description":"Pure JavaScript evented binary parsers and serializers for Node.js.","keywords":["packet","pack","binary","network","structure","async","asynchronous","javascript"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"contributors":[{"name":"J. Ryan Stinnett","email":"jryans@gmail.com"},{"name":"Ben Hockey","email":"neonstalwart@gmail.com"},{"name":"Greg Ose","email":"neonstalwart@gmail.com","url":"http://nullmethod.com/"},{"name":"Aaron Qian","email":"aq1018@gmail.com"},{"name":"Demarius Chrite","email":"chrite.demarius@gmail.com","url":"https://github.com/demarius"}],"homepage":"https://github.com/bigeasy/packet","bugs":{"url":"https://github.com/bigeasy/packet/issues"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/bigeasy/packet.git"},"dependencies":{"fast-deep-equal":"3.1.3","programmatic":"2.0.0-alpha.9"},"devDependencies":{"extant":"^2.0.0-alpha.0","proof":"^9.0.3"},"main":"packet.js","scripts":{"test":"proof -n --allow-natives-syntax test/*/*.t.js"},"nyc":{"exclude":["test/**","!test/generated","inlines.js"]},"readme":"[![Actions Status](https://github.com/bigeasy/packet/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/packet/actions)\n[![codecov](https://codecov.io/gh/bigeasy/packet/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/packet)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA comparator function builder.\n\n| What          | Where                                         |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/packet/issues/1    |\n| Documentation | https://bigeasy.github.io/packet              |\n| Source        | https://github.com/bigeasy/packet             |\n| Issues        | https://github.com/bigeasy/packet/issues      |\n| CI            | https://travis-ci.org/bigeasy/packet          |\n| Coverage:     | https://codecov.io/gh/bigeasy/packet          |\n| License:      | MIT                                           |\n\n\n```\nnpm install packet\n```\n\nIncremental binary parsers and serializers for Node.js.\n\n### Diary\n\nIn the middle of the final rewrite after many years of learning about Node.js.\n\nCurrently working in the `compose` folder to create compiled parsers based on\nthe work in `composer`.\n\n### Continue\n\nPacket creates **pre-compiled**, **pure-JavaScript**, **binary parsers** and\n**serializers** that are **incremental** through a binary pattern language that\nis **declarative** and very **expressive**.\n\nRewrite pending.\n\nPacket simplifies the construction an maintenance of libraries that convert\nbinary to JavaScript and back. The name Packet may make you think that it is\ndesigned solely for binary network protocols, but it is also great for reading\nand writing binary file formats.\n\n**Incremental** &mdash; Node packet creates incremental parsers and serializers\nthat are almost as fast as the parser you'd write by hand, but a lot easier to\ndefine and maintain.\n\n**Declarative** &mdash; Packet defines a binary structure using a pattern\nlanguage inspired by Perl's `pack`. The binary patterns are used to define both\nparsers and serializers. If you have a protocol specification, or even just a C\nheader file with structures that define your binary data, you can probably\ntranslate that directly into Packet patterns.\n\nFor parsers, you associate the patterns to callbacks invoked with captured\nvalues when the pattern is extracted from the stream. For serializers you simply\ngive the values to write along with the pattern to follow when writing them.\n\n**Expressive** &mdash; The pattern language can express\n\n  * signed and unsigned integers,\n  * endianess of singed and unsigned integers,\n  * floats and doubles,\n  * fixed length arrays of characters or numbers,\n  * length encoded strings of characters or numbers,\n  * zero terminated strings of characters or numbers,\n  * said strings terminated any fixed length terminator you specify,\n  * padding of said strings with any padding value you specify,\n  * signed and unsigned integers extracted from bit packed integers,\n  * conditions based on bit patterns\n  * character encodings,\n  * custom transformations,\n  * and pipelines of character encodings and custom transformations.\n\n### Limitations\n\n**Parsing not searching** &mdash; Packet is not a pattern matching library. It\ndoes not search binary streams for patterns. Packet is used for parsing\nwell-defined streams of binary data.\n\n**8-bit boundaries** &mdash; I'm unable to think of an example in contemporary\ncomputing that doesn't align to an 8-bit boundary, but the world is big and I am\nsmall, so I plan on being surprised. I can also imagine that someone might want\nto unleash Packet on legacy data someday, from way back when a byte was whatever\na computer manufacturer said it was.\n\nTherefore, It's worth noting that Packet parses 8-bit bytes and expects bytes to\nalign to an 8-bit boundary. Packet can parse 7-bit ASCII formats like `tar`\narchives, because they are 8-bit aligned with the top bit ignored. Packet can\nalso parse and serialize bit packed integers, so it does support awkward integer\nsizes, but within an 8-bit aligned integer.\n\n## Installing\n\nInstall Packet using NPM.\n\n```\nnpm install packet\n```\n\nThe source is available on [GitHub](https://github.com/bigeasy/packet).\n\n## Parsers and Serializers\n\nPacket defines a binary format using a binary pattern language inspired by\nPerl's `pack` function. The pattern language is used in a `Parser` to define the\nparameters passed to callback when enough bytes are read from the input stream\nto satisfy the pattern. The pattern language is used in a `Serializer` to define\nhow JavaScript primitives passed to the `serialize` method are written to\nstream.\n\n### Patterns\n\nPatterns are a series of element declarations joined by commas.\n\n```javascript\nparser.extract(\"length: b16, address: b32, name: b8z\", function (object) {\n  console.log(object.length, object.address, object.name);\n});\nparser.parse([ 0x01, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00 ]);\n```\n\nYou can also name the elements in a pattern. If named, parsers will be create an\nobject to pass to callbacks, serializers will serialize an object's properties.\n\n```javascript\nparser.extract(\"b16 => length, b32 => address, b8z => name\", function (record) {\n  console.log(record);\n});\nparser.parse([ 0x01, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00 ]);\n```\n\nUnnamed elements are good for short, simple patterns. For longer patterns it is\neasier to have a parser build an object for you.\n\nThe following example shows a complicated pattern, the invariable portion of an\nIP header, the first 20 bytes before options, if any.\n\n```javascript\n// Define an IP header pattern using a joined array to explode the pattern.\nparser.packet('ip', 'b8{version: b4, headerLength: b4},         \\\n                     typeOfService: b8,                         \\\n                     length: b16,                               \\\n                     identification: b16,                       \\\n                     b16{flags: b3, fragmentOffset: b13},       \\\n                     timeToLive: b8,                            \\\n                     protocol: b8,                              \\\n                     checksum: b16,                             \\\n                     sourceAddress: b32,                        \\\n                     destinationAddress: b32                    \\\n                    ');\n\n// The pattern is then used to defined parser and serializer actions.\nparser.extract(\"ip\", function (header) {\n  console.log(header);\n});\nparser.parse(buffer);\n```\n\nBoth parsers and serializers can define patterns using the `packet` method. The\n`packet` method allows you to pre-compile patterns.\n\n```javascript\n// Create a parser and define a header.\nvar parser = require('packet').createParser();\nparser.packet(\"header\", \"b8 => type, b16 => length, b32 => extra\");\nparser.packet(\"data\", \"b16 => sequence, b16 => crc\");\n\n// Now you can define your serializer using your parser as a prototype. The\n// serializer will inherit the parser's packet definitions.\nvar serializer = parser.createSerializer();\n```\n\nParsers and serializers maintain internal state so that they can be used\nincrementally. If you're going to parse streams incrementally, you're going to\nneed a parser for each stream your parsing. Same goes for serializers and\nserializing.\n\nWhen parsing/serializing incrementally create new parsers and serializers using\nthe prototype pattern above.\n\n```javascript\n// Create a serializer and define a header.\nvar serializer = require(\"packet\").createSerializer();\nserializer.packet(\"header\", \"b8 => type, b16 => length, b32 => extra\");\nserializer.packet(\"data\", \"b16 => sequence, b16 => crc\");\n\n// Now you can define parsers for a using the serializer as a prototype.\nnet.createServer(function (socket) {\n  var parser = serializer.createParser();\n  socket.on(\"data\", function (buffer) {\n    parser.parse(buffer);\n  });\n  parser.extract(\"header\", function (header) {\n    console.log(header);\n  });\n});\n```\n\n### Parsers\n\nParsers parse a buffer extracting a specified pattern. The pattern is specified\nusing the `extract` method. The `extract` method accept either a pattern or the\nname a pre-compiled pattern.\n\nAfter the pattern has been specified, the parser will extract the data from one\nor more buffers according to the specified pattern.\n\nWhen the pattern specified by `extract` has been read from the series of\nbuffers, it will invoke a callback with the extracted values. The `extract`\ncallback has the option of calling the `extract` method specifying a subsequent\npattern for the parser to extract. When the callback returns, the parser will\nimmediately continue to parse the newly specified pattern from the series of\nbuffers.\n\nThe parser callback receives the values either as positioned function arguments\nor as an object. How the callback is invoked is based on the pattern and the\n[arity](http://en.wikipedia.org/wiki/Arity) of the callback function.\n\nTo receive an object in the callback, we defined named elements. When the\npattern has at least one named element, and the callback has only a single\nargument, an object is passed to the callback containing the values using the\nelement names as keys.\n\nUnnamed elements are excluded, but there's no good reason not name them. Use a\nskip pattern to skip over unwanted bytes instead.\n\nYou can still get positioned arguments using a named pattern. Just provide a\ncallback with more than one argument and it will be invoked with the extract\nvalues as parameters.\n\nA callback for a pattern without any named elements is always invoked with\nvalues as parameters regardless of arity.\n\n### Serializers\n\nFirst you call `serialize` with a pattern and arguments to serialize, then you\ncall `write` with a series of buffers.\n\n## Binary Pattern Fields\n\nThe binary pattern language is used to specify the fields binary structures in\ndata streams, using a comma separated field pattern.\n\n### Big-Endian Byte Ordering\n\nTo define a big-endian byte ordering for a field, prefix the bit size with `b`.\n\n```yaml\nmnemonic: The letter `b` stands for big-endian.\nexamples:\n  -\n    pattern: world: b16\n    object:\n      word: 256\n    description: Big-endian 32 bit number.\n  -\n    pattern: byte: b8\n    object:\n      byte: 1\n    description: Endianess of a single byte is irrelevant.\n  -\n    pattern: word: l16, byte: b8\n    object:\n      word: 1\n      byte: 1\n    parsed: 0x01, 0x00, 0x01\n```\n\n**Mnemonic**: The letter `b` stands for big-endian.\n\n```javascript\n\"b16\"             // Big-endian 32 bit number.\n\"b8\"              // Endianess of a single byte is irrelevant.\n\"l16, b8\"         // Big-endian 16 bit integer followed by a byte.\n```\n\n### Little-Endian Byte Ordering\n\nTo define a little-endian byte ordering for a field, prefix the bit size with `l`.\n\n**Mnemonic**: The letter `l` stands for little-endian.\n\n```javascript\n\"l32\"             // Little-endian 32 bit integer.\n\"l8\"              // Endianess of a single byte is irrelevant.\n\"l16, b8\"         // Little endian 16 bit integer followed by a byte.\n```\n\n### Skipping Bytes\n\nYou can skip over bytes your pattern with `x`.\n\n**Mnemonic**: The letter `x` means to cross-out, which is kind of like skipping.\n\n```javascript\n\"b8, x16, l16\"    // A byte, two skipped bytes, and a little-endian 16 bit\n                  // integer.\n```\n\n### Signed Versus Unsigned Integers\n\nAll numbers are assumed to be unsigned, unless prefixed by a negative symbol.\n\n**Mnemonic**: The `-` symbol indicates the possibility of negative numbers.\n\n```javascript\n\"-b32\"            // Big-endian 32 bit signed integer.\n\"-l32\"            // Little-endian 32 bit signed integer.\n\"b32\"             // Big-endian 32 bit unsigned integer.\n```\n\n### IEEE 754 Floating Point Numbers\n\nThe number type for JavaScript is the  64 bit IEEE 754 floating point. Packet\ncan read write 64 bit and 32 bit IEEE 754 floating point numbers.\n\nTo indicated that the type is a floating point number, use the `f` type suffix.\nThis is indicated with a `f` suffix.\n\n**Mnemonic**: The letter `f` stands for\n*floating-point*.\n\n```javascript\n\"b64f\"            // Big-endian 64 bit IEEE 754 double floating point number.\n\"l32f\"            // Little-endian 32 bit IEEE 754 single floating point number.\n```\n\nThe floating-point numbers can be stored in little-endian or big-endian byte order.\n\n### Arrays of Raw Bytes\n\nA value will be converted to a big-endian array of bytes if followed by an `a`\nsuffix.\n\n**Mnemonic**: The letter `a` stands for *array*.\n\n```javascript\n\"l128a\"           // Unsigned little-endian 128 bit integer as big-endian array\n                  // of bytes.\n```\n\nNote that big-endian means that the most significant byte is at index `0` of the\narray.\n\nThis can be surprising if you're expecting the significance of the bytes will\nincrease with the index of the array, but then that's what little-endian is all\nabout. (Big-endian orders like Arabic numerals, while little-endian orders like\noffsets into memory.)\n\nIf you'd prefer a little-endian array, simply call `reverse` on the array passed\nto you.\n\n### Arrays of Common Types\n\nIt is often the case that a binary format contains an array of values. The most\ncommon case are arrays of bytes representing ASCII or UTF-8 strings.\n\nArrays are specified with an subscript and a count.\n\n**Mnemonic**: The square brackets are used as array subscripts in JavaScript,\nand used to declare array length in other C dialect languages.\n\n```javascript\n\"b32[4]\"          // An array of four big-endian 32 bit numbers.\n\"b8[16]\"          // An array of 16 bytes.\n```\n\nThe array notation produces an array of the type before the subscript.\n\n### Zero Terminated Arrays\n\nZero terminated series are specified with a `z` qualifier.\n\nYou can specify both termination and width together. Why would you need this?\nThis occurs in underlying C structures when there is a fixed width character\narray in a structure, but the structure still contains a zero terminated string.\n\n**Upcoming**: Chose your own terminator.\n\n**Mnemonic**: The letter `z` stands for zero.\n\n```javascript\n\"l16z\"            // Little-endian 16 bit numbers terminated by a zero value.\n\"b8z\"             // Byte string terminated by zero.\n\"b8[12]z\"         // Byte string terminated by zero in a field 12 bytes long.\n```\n\n### Array Padding\n\nYou can specify a padding value immediately after the array brackets using curly\nbraces. This should be the numeric value, or character code for padding. If you\nwant to zero pad, use `0`. If you want to pad with ASCII spaces use `32`.\n\n**Mnemonic**: Curly braces are used to define array literals in C.\n\n```javascript\n\"b16[12]{0}\"      // Array of 12 big-endian 16 bit integers, zero padded.\n\"b8[12]{32}z\"     // Byte string terminated by zero in a field 12 bytes long\n                  // ascii space padded.\n```\n### Length Encoded Arrays\n\nLength encoded arrays are specified by joining a count type and a value type\nwith a forward slash character `/`.\n\n**Mnemonic**: Inspired by Perl's `pack`, which uses the slash to separate count\nand type.\n\n```javascript\n\"b8/b8\"           // Length encoded byte array with a byte length.\n\"l16/b8\"          // Length encoded byte array with 16 bit little-endian length.\n```\n\n### Bit Packed Integers\n\nIntegers are often divided into smaller integers through a process called bit\npacking. Bit packing is specified by following an integer specification with\na curly brace enclosed series series of integers patterns whose total size in\nbits equals the size of the packed integer.\n\nPacked integers are always big-endian and can be either singed or unsigned.\n\n**Mnemonic** Curly braces are used to define structures in C and bit packing is\nkind of like a structure.\n\n```javascript\n\"b16{b3,x6,-b7}\"  // A 16 bit big-endian integer divided into a 3-bit integer,\n                  // 6 skipped bits, and a signed 7-bit integer.\n```\n\nYou can also name the packed fields.\n\n```javascript\n\"b16{b3 => type, x6, -b7 => count}\"\n```\n\n### Alternate Patterns\n\nA common pattern in binary formats is using the value of a byte, or the high\norder bits of a byte to specify the type of data to follow. [Length Encoded\nArrays](#length-encoded-arrays) are one example of this practice, where a\nan integer count indicates the length of a following string or array.\n\nWith an alternate pattern, **Packet** will extract an integer from the byte\nstream, then choose a pattern based on the value of that integer. The pattern is\napplied at the index where the integer used to choose the pattern was extracted.\nThat is, the bytes used to choose the pattern are included when the pattern is\napplied. It is a peek and switch.\n\nAlternate patterns are grouped by parenthesis `(` and `)` and delimited by pipes\n`|`. Each alternative maps a match to a pattern separated by a colon `:`.\n\n**Mnemonic** &mdash; Parenthesis and pipes are used to indicate alternation in\nregular expressions, while colons are used to delineate switch options in C.\n\n```javascript\n// MySQL length coded binary; if the byte is less than 252, use the byte value,\n// otherwise the byte value indicates the length of the following word.\n\"b8(0-251: b8 | 252: x8, b16 | 253: x8, b24 | 254: x8, b64)\"\n```\n\nConditions are either a value to match exactly or a range of values. **Packet**\ntests each condition is tested in order. **Packet** uses the alternation of the\nfirst condition to match the extracted integer is used. An alternate without a\ncondition will always match. This is used to specify a default pattern.\n\n```javascript\n// Simpiler, but will also match 255 which is invalid, which is fine if you test\n// the value in your callback.\n\"b8(252: x8, b16 | 253: x8, b24 | 254: x8, b64 | b8)\"\n```\n\nThe values can be expressed in binary, decimal or hexadecimal.\n\n### Bitwise Alternate Patterns\n\nYou can also indicate a branch based on set bits by prefixing the value with an\nampersand. **Packet** will use the value as a bit mask. If the result of a\nlogical *and* with the bit mask equals the bit mask, then **Packet** use use\nthat alternative.\n\n**Mnemonic** The `&` performs a logical and in C and is used to check to see if\nbits in a bit mask are set.\n\n```javascript\n\"b8(&0x80: b16{x1,b15} | b8)\"   // A 15-bit word if the first bit is set,\n                                // otherwise a byte.\n```\n\nBitwise conditions cannot be used in to choose a pattern for serialization. Upon\nserialization, the field value is a JavaScript number, not an stream of bytes.\nThe bit flag simply does not exist.\n\nInstead, we need to perform a range check to determine which pattern. To delimit\nalternate tests for reading and writing, we use a slash in the condition.\n\n```javascript\n// A 15-bit word if the first bit is set, otherwise a byte.\n\"b8(&0x80/0x80-0xffff: b16{x1{1},b15} | b8)\"\n```\n\n### Multi-Field Alternate Patterns\n\nAlternate patterns can define either a single field or multiple field.\nAlternate patterns can contain bit-packed patterns, but they cannot contain\nstill more alternate patterns.\n\n```javascript\n// Two alternate patterns with a different number of fields.\n\"b8(&0x80/1: b16{b1, b15}, b16|b32{b1, b31})\"\n```\n\nIn the above example, the serialization test would be applied to the field value\nin the position of the `b1` field for either alternate.\n\n### Named Alternate Patterns\n\nNames can be applied either to the entire alternation if the alternation\nproduces a single field, or else to individual members of the alternate\npatterns.\n\n```\n// A single field mapped to a name.\n\"b8(&0x80/0x80-0xffff: b16{x1{1},b15} | b8) => number\"\n```\n\nWhen serializing named multi-field patterns, for each alternate, **Packet** will\nuse the first value of the property in the alternate for the serialization\ncondition. **Packet** reads the property from the object we're serializing. If\nthe value is not null, it is tested against the serialization condition. If it\nis null, the test is skipped. We use the first alternate whose object property\nis not null and whose serialization condition matches the object property.\n\n```javascript\n// Multi-field alternates mapped to names.\n\"b8(&0x80/1: b16{b1 => control, b15 => type}, x16|b32{b1 => control, b31 => sequence})\"\n```\n\n### Transforms\n\nOften there are transformations that you need to perform on an field to get\nit to its final state. You may need to convert a byte array to string of a\nparticular character encoding, for example. This is done with a transformation\nfunctions which are specified with a transformation pipeline.\n\nIf the transformation is a fixed transformation, you can perform the\ntransformation by defining a pipeline. A pipeline defines one or more\ntransformations that are invoked on the value after parsing and before\nserialization. The transformations can accept scalar JavaScript parameters.\n\n```javascript\nfunction str(encoding, name, field, parsing, value) {\n    if (parsing) {\n        var buffer = new Buffer(array.length)\n        for (var i = 0; i &lt; value.length; i++) {\n            buffer[i] = value[i];\n        }\n        var length = value.length\n        if (field.terminator) {\n            length += field.terminator.length;\n        }\n        return buffer.toString(encoding, 0, length);\n    } else {\n        if (field.terminator) {\n            value += field.terminator;\n        }\n        return new Buffer(value, encoding);\n    }\n}\n```\n\nNow you can use the transform in your pattern.\n\n```javascript\n\"b8z|str('ascii')\"      // An ascii string terminated by zero.\n\"b8z|str('ascii'), b16\" // An ascii string terminated by zero followed by a\n                        // big-endian 16 bit integer.\n```\n\nThe `str` transform is defined by default. The transform names are purposely\nterse to fit with the brevity of the pattern language.\n\n## Error Messages\n\nError messages for pattern parsing.\n\n * **invalid pattern at N** &mdash; The characters starting at the specified\n   index is unexpected the pattern is invalid. The invalid character may not be\n   at the specified index, but shortly there after, such as unmatched braces.\n * **bit field overflow at N** &mdash; The sum of the bit size of bit field\n   elements is greater than the size of the containing element. The sum of the\n   bit size of bit field elements must equal the size of the containing element.\n * **bit field underflow at N** &mdash; The sum of the bit size of bit field\n   elements is less than the size of the containing element. The sum of the bit\n   size of bit field elements must equal the size of the containing element.\n * **bit size must be non-zero at N** &mdash; Encountered element with a bit size of\n   zero. Element size must be a non-zero value.\n * **bits must be divisible by 8 at N** &mdash; Encountered element with a bit\n   size that is not divisible by 8. If an element is not a bit field element, it\n   must align to an 8-bit boundary.\n * **floats can only be 32 or 64 bits at N** &mdash; Encountered a float element\n   with an unsupported bit size. Only 32 and 64 bit floats are supported.\n * **\"array length must be non-zero at N** &mdash; Encountered an array length\n   of zero. Arrays must have a non-zero length.\n\n## Change Log\n\nChanges for each release.\n\n### Version 0.0.6\n\nWed Jul  3 21:52:20 UTC 2013\n\n * Implement `Serializer.offsetsOf`. #87. #85. #86. #63.\n * Objects primary, positional arguments secondary. #84.\n * Reset namedness of `Parser`. #83.\n * Serialize and parsed a named length encoded array. #82.\n * Increase test coverage.  #77. #69. #68. #67. #66.\n * Test text to float conversion. #66.\n * Remove `n` syntax from README. @jryans. #64.\n * Remove detection of `n` synonym for `b`.\n * Remove asterisk to indicate wildcard condition. #33.\n * `Parser.parse` returns bytes read. #60.\n * Report coverage to Coveralls. #61.\n * Rename `pattern` to `field`. #57.\n * Massive tidy after change in enclosed objects.\n\n### Version 0.0.5\n\nFri Mar  1 03:05:15 UTC 2013\n\n * Chunked serialization bug fixes. #59. #58. #55.\n * Move supporting libraries to root directory. #44.\n * Spell check `README.md` and remove dead features. #32. #55.\n * Implement `sizeOf` property for serializer. #37.\n * Fix minimum number value. #54.\n\n### Version 0.0.4\n\nMon Nov  6 04:50:16 UTC 2012.\n\n * Create parsers and serializers from prototypes. #53.\n * Parse patterns with Win32 CRLF. #51. (Greg Ose <greg@nullmethod.com>)\n * Copy cached pattern for alternation rewriting. #50.\n * Flatten alternation prior to serialization. #34.\n * Add `.js` suffix to tests. #49.\n * Convert to closure style. #40, #47, #39, #38, #27.\n * Remove pausing from `Parser`. #46.\n * Implement `reset` for serializer. #43.\n * Single letter field names. #45.\n * Remove streams from API. #41.\n\n### Version 0.0.3\n\nFri Aug 17 00:40:37 UTC 2012.\n\n * Fix Packet in NPM. #12.\n * Serialize alternate structures. #31.\n * Test serialization of words. #20.\n * Serializer not exported by `index.js`.\n * Named patterns reset buffer offset. #29.\n * Allow spaces before alternation condition. #28.\n * Create a markdown `README.md`. #18.\n * Build on Node 0.8 at Travis CI. #23.\n * Fix too greedy match of bit packing pattern. #19.\n * Skip leading whitespace in pattern. #15.\n\n## Contributors\n\n  * [Ben Hockey](https://github.com/neonstalwart)\n  * [Aaron Qian](https://github.com/aq1018)\n","readmeFilename":"README.md","gitHead":"6bc8eebe863239c000bf7fbd1137166e6a8e2f06","_id":"packet@1.0.0-alpha.1","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-3ub7/2uqLWScnEFZKDzoIEZBcXopKrWGKC7EeHlL2tzLikcLkniYcjezEAhzxoHxtD2lWqG4H8GwKMLQ14BNJA==","shasum":"78515808aaa1ad5e9b1e524080bc1e9f1f13249b","tarball":"https://registry.npmjs.org/packet/-/packet-1.0.0-alpha.1.tgz","fileCount":40,"unpackedSize":282267,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgWLjNCRA9TVsSAnZWagAASuYQAJEh0wcuaF4u7Q0suY63\nZi1jSr/wkIo8W+fEB6uJBIrQrjzcR72ZqjDDFgz98o26/Fm1jWGlDx7a9I10\n/YTkjJrUqiB7QApG4WV4ZhmLfwQzQfl7vf/u3D/KmXQQ7GqpcpsloETx/0LM\ny+IEtvLwKtlc+Rtrag6e1CrqDqFHXtNo4t9SzsU2KaUgexVryAabHpp3a4Vg\nEUiTPqjltBCdECThsLbPv6NMqZfr2dxb14VRI6o5xFXjvdGd/z36G5jUUwa6\nQlyRHF/nz2pWNpkuxEmCx2B3C69xcsjyw18I5Srx0VOzb+c651XLOWZpfabp\nlhKKEtPRSCzsQxul9d43e0lxtudTsyoWlpvYiVBjJzsh/pJefArgObY+igKq\nc28Finu6y0sxpNVHBNXd29UcxeS/i1cRGSY1aZz6lEG8XtC5Lf2FLhULvLty\npRP9Za4Upg75rzz/fC9cRBHs3CwglSwYR59YgYCvUsvbVY3+HHdzpa4BDR29\npWDcl3ZZgrys+vQRbFPhAejstAEXbZ3ewVp2Ib96QtJypI3PH1mrKCLOUp5i\nVo6PfgPHSctl5iBoIrQEU7TarxQTndOnN+a6ltjGqgIdOc6HD2c1AqzFNTWg\nHeVyoDuLLLk3KLqil9+jMOr+BtyK9oSBD3NHmcj6kMxa8GkfcyvnfHo2QIk2\nXRnN\r\n=zsEo\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHYd3mSnSWQIXgP6V67BqM4MEY9VmJ5f3O5kyl2nnYpSAiEA4Egz2s0hquWSS4gMVu4I3JIOfFoC/CPEQDbRQoCIxzg="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/packet_1.0.0-alpha.1_1616427212846_0.4361655130010178"},"_hasShrinkwrap":false},"1.0.0-alpha.2":{"name":"packet","version":"1.0.0-alpha.2","description":"Pure JavaScript evented binary parsers and serializers for Node.js.","keywords":["packet","pack","binary","network","structure","async","asynchronous","javascript"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"contributors":[{"name":"J. Ryan Stinnett","email":"jryans@gmail.com"},{"name":"Ben Hockey","email":"neonstalwart@gmail.com"},{"name":"Greg Ose","email":"neonstalwart@gmail.com","url":"http://nullmethod.com/"},{"name":"Aaron Qian","email":"aq1018@gmail.com"},{"name":"Demarius Chrite","email":"chrite.demarius@gmail.com","url":"https://github.com/demarius"}],"homepage":"https://github.com/bigeasy/packet","bugs":{"url":"https://github.com/bigeasy/packet/issues"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/bigeasy/packet.git"},"dependencies":{"fast-deep-equal":"3.1.3","programmatic":"2.0.0-alpha.9"},"devDependencies":{"extant":"^2.0.0-alpha.0","proof":"^9.0.3"},"main":"packet.js","scripts":{"test":"proof -n --allow-natives-syntax test/*/*.t.js"},"nyc":{"exclude":["test/**","!test/generated","inlines.js"]},"readme":"[![Actions Status](https://github.com/bigeasy/packet/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/packet/actions)\n[![codecov](https://codecov.io/gh/bigeasy/packet/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/packet)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA comparator function builder.\n\n| What          | Where                                         |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/packet/issues/1    |\n| Documentation | https://bigeasy.github.io/packet              |\n| Source        | https://github.com/bigeasy/packet             |\n| Issues        | https://github.com/bigeasy/packet/issues      |\n| CI            | https://travis-ci.org/bigeasy/packet          |\n| Coverage:     | https://codecov.io/gh/bigeasy/packet          |\n| License:      | MIT                                           |\n\n\n```\nnpm install packet\n```\n\nIncremental binary parsers and serializers for Node.js.\n\n### Diary\n\nIn the middle of the final rewrite after many years of learning about Node.js.\n\nCurrently working in the `compose` folder to create compiled parsers based on\nthe work in `composer`.\n\n### Continue\n\nPacket creates **pre-compiled**, **pure-JavaScript**, **binary parsers** and\n**serializers** that are **incremental** through a binary pattern language that\nis **declarative** and very **expressive**.\n\nRewrite pending.\n\nPacket simplifies the construction an maintenance of libraries that convert\nbinary to JavaScript and back. The name Packet may make you think that it is\ndesigned solely for binary network protocols, but it is also great for reading\nand writing binary file formats.\n\n**Incremental** &mdash; Node packet creates incremental parsers and serializers\nthat are almost as fast as the parser you'd write by hand, but a lot easier to\ndefine and maintain.\n\n**Declarative** &mdash; Packet defines a binary structure using a pattern\nlanguage inspired by Perl's `pack`. The binary patterns are used to define both\nparsers and serializers. If you have a protocol specification, or even just a C\nheader file with structures that define your binary data, you can probably\ntranslate that directly into Packet patterns.\n\nFor parsers, you associate the patterns to callbacks invoked with captured\nvalues when the pattern is extracted from the stream. For serializers you simply\ngive the values to write along with the pattern to follow when writing them.\n\n**Expressive** &mdash; The pattern language can express\n\n  * signed and unsigned integers,\n  * endianess of singed and unsigned integers,\n  * floats and doubles,\n  * fixed length arrays of characters or numbers,\n  * length encoded strings of characters or numbers,\n  * zero terminated strings of characters or numbers,\n  * said strings terminated any fixed length terminator you specify,\n  * padding of said strings with any padding value you specify,\n  * signed and unsigned integers extracted from bit packed integers,\n  * conditions based on bit patterns\n  * character encodings,\n  * custom transformations,\n  * and pipelines of character encodings and custom transformations.\n\n### Limitations\n\n**Parsing not searching** &mdash; Packet is not a pattern matching library. It\ndoes not search binary streams for patterns. Packet is used for parsing\nwell-defined streams of binary data.\n\n**8-bit boundaries** &mdash; I'm unable to think of an example in contemporary\ncomputing that doesn't align to an 8-bit boundary, but the world is big and I am\nsmall, so I plan on being surprised. I can also imagine that someone might want\nto unleash Packet on legacy data someday, from way back when a byte was whatever\na computer manufacturer said it was.\n\nTherefore, It's worth noting that Packet parses 8-bit bytes and expects bytes to\nalign to an 8-bit boundary. Packet can parse 7-bit ASCII formats like `tar`\narchives, because they are 8-bit aligned with the top bit ignored. Packet can\nalso parse and serialize bit packed integers, so it does support awkward integer\nsizes, but within an 8-bit aligned integer.\n\n## Installing\n\nInstall Packet using NPM.\n\n```\nnpm install packet\n```\n\nThe source is available on [GitHub](https://github.com/bigeasy/packet).\n\n## Parsers and Serializers\n\nPacket defines a binary format using a binary pattern language inspired by\nPerl's `pack` function. The pattern language is used in a `Parser` to define the\nparameters passed to callback when enough bytes are read from the input stream\nto satisfy the pattern. The pattern language is used in a `Serializer` to define\nhow JavaScript primitives passed to the `serialize` method are written to\nstream.\n\n### Patterns\n\nPatterns are a series of element declarations joined by commas.\n\n```javascript\nparser.extract(\"length: b16, address: b32, name: b8z\", function (object) {\n  console.log(object.length, object.address, object.name);\n});\nparser.parse([ 0x01, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00 ]);\n```\n\nYou can also name the elements in a pattern. If named, parsers will be create an\nobject to pass to callbacks, serializers will serialize an object's properties.\n\n```javascript\nparser.extract(\"b16 => length, b32 => address, b8z => name\", function (record) {\n  console.log(record);\n});\nparser.parse([ 0x01, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00 ]);\n```\n\nUnnamed elements are good for short, simple patterns. For longer patterns it is\neasier to have a parser build an object for you.\n\nThe following example shows a complicated pattern, the invariable portion of an\nIP header, the first 20 bytes before options, if any.\n\n```javascript\n// Define an IP header pattern using a joined array to explode the pattern.\nparser.packet('ip', 'b8{version: b4, headerLength: b4},         \\\n                     typeOfService: b8,                         \\\n                     length: b16,                               \\\n                     identification: b16,                       \\\n                     b16{flags: b3, fragmentOffset: b13},       \\\n                     timeToLive: b8,                            \\\n                     protocol: b8,                              \\\n                     checksum: b16,                             \\\n                     sourceAddress: b32,                        \\\n                     destinationAddress: b32                    \\\n                    ');\n\n// The pattern is then used to defined parser and serializer actions.\nparser.extract(\"ip\", function (header) {\n  console.log(header);\n});\nparser.parse(buffer);\n```\n\nBoth parsers and serializers can define patterns using the `packet` method. The\n`packet` method allows you to pre-compile patterns.\n\n```javascript\n// Create a parser and define a header.\nvar parser = require('packet').createParser();\nparser.packet(\"header\", \"b8 => type, b16 => length, b32 => extra\");\nparser.packet(\"data\", \"b16 => sequence, b16 => crc\");\n\n// Now you can define your serializer using your parser as a prototype. The\n// serializer will inherit the parser's packet definitions.\nvar serializer = parser.createSerializer();\n```\n\nParsers and serializers maintain internal state so that they can be used\nincrementally. If you're going to parse streams incrementally, you're going to\nneed a parser for each stream your parsing. Same goes for serializers and\nserializing.\n\nWhen parsing/serializing incrementally create new parsers and serializers using\nthe prototype pattern above.\n\n```javascript\n// Create a serializer and define a header.\nvar serializer = require(\"packet\").createSerializer();\nserializer.packet(\"header\", \"b8 => type, b16 => length, b32 => extra\");\nserializer.packet(\"data\", \"b16 => sequence, b16 => crc\");\n\n// Now you can define parsers for a using the serializer as a prototype.\nnet.createServer(function (socket) {\n  var parser = serializer.createParser();\n  socket.on(\"data\", function (buffer) {\n    parser.parse(buffer);\n  });\n  parser.extract(\"header\", function (header) {\n    console.log(header);\n  });\n});\n```\n\n### Parsers\n\nParsers parse a buffer extracting a specified pattern. The pattern is specified\nusing the `extract` method. The `extract` method accept either a pattern or the\nname a pre-compiled pattern.\n\nAfter the pattern has been specified, the parser will extract the data from one\nor more buffers according to the specified pattern.\n\nWhen the pattern specified by `extract` has been read from the series of\nbuffers, it will invoke a callback with the extracted values. The `extract`\ncallback has the option of calling the `extract` method specifying a subsequent\npattern for the parser to extract. When the callback returns, the parser will\nimmediately continue to parse the newly specified pattern from the series of\nbuffers.\n\nThe parser callback receives the values either as positioned function arguments\nor as an object. How the callback is invoked is based on the pattern and the\n[arity](http://en.wikipedia.org/wiki/Arity) of the callback function.\n\nTo receive an object in the callback, we defined named elements. When the\npattern has at least one named element, and the callback has only a single\nargument, an object is passed to the callback containing the values using the\nelement names as keys.\n\nUnnamed elements are excluded, but there's no good reason not name them. Use a\nskip pattern to skip over unwanted bytes instead.\n\nYou can still get positioned arguments using a named pattern. Just provide a\ncallback with more than one argument and it will be invoked with the extract\nvalues as parameters.\n\nA callback for a pattern without any named elements is always invoked with\nvalues as parameters regardless of arity.\n\n### Serializers\n\nFirst you call `serialize` with a pattern and arguments to serialize, then you\ncall `write` with a series of buffers.\n\n## Binary Pattern Fields\n\nThe binary pattern language is used to specify the fields binary structures in\ndata streams, using a comma separated field pattern.\n\n### Big-Endian Byte Ordering\n\nTo define a big-endian byte ordering for a field, prefix the bit size with `b`.\n\n```yaml\nmnemonic: The letter `b` stands for big-endian.\nexamples:\n  -\n    pattern: world: b16\n    object:\n      word: 256\n    description: Big-endian 32 bit number.\n  -\n    pattern: byte: b8\n    object:\n      byte: 1\n    description: Endianess of a single byte is irrelevant.\n  -\n    pattern: word: l16, byte: b8\n    object:\n      word: 1\n      byte: 1\n    parsed: 0x01, 0x00, 0x01\n```\n\n**Mnemonic**: The letter `b` stands for big-endian.\n\n```javascript\n\"b16\"             // Big-endian 32 bit number.\n\"b8\"              // Endianess of a single byte is irrelevant.\n\"l16, b8\"         // Big-endian 16 bit integer followed by a byte.\n```\n\n### Little-Endian Byte Ordering\n\nTo define a little-endian byte ordering for a field, prefix the bit size with `l`.\n\n**Mnemonic**: The letter `l` stands for little-endian.\n\n```javascript\n\"l32\"             // Little-endian 32 bit integer.\n\"l8\"              // Endianess of a single byte is irrelevant.\n\"l16, b8\"         // Little endian 16 bit integer followed by a byte.\n```\n\n### Skipping Bytes\n\nYou can skip over bytes your pattern with `x`.\n\n**Mnemonic**: The letter `x` means to cross-out, which is kind of like skipping.\n\n```javascript\n\"b8, x16, l16\"    // A byte, two skipped bytes, and a little-endian 16 bit\n                  // integer.\n```\n\n### Signed Versus Unsigned Integers\n\nAll numbers are assumed to be unsigned, unless prefixed by a negative symbol.\n\n**Mnemonic**: The `-` symbol indicates the possibility of negative numbers.\n\n```javascript\n\"-b32\"            // Big-endian 32 bit signed integer.\n\"-l32\"            // Little-endian 32 bit signed integer.\n\"b32\"             // Big-endian 32 bit unsigned integer.\n```\n\n### IEEE 754 Floating Point Numbers\n\nThe number type for JavaScript is the  64 bit IEEE 754 floating point. Packet\ncan read write 64 bit and 32 bit IEEE 754 floating point numbers.\n\nTo indicated that the type is a floating point number, use the `f` type suffix.\nThis is indicated with a `f` suffix.\n\n**Mnemonic**: The letter `f` stands for\n*floating-point*.\n\n```javascript\n\"b64f\"            // Big-endian 64 bit IEEE 754 double floating point number.\n\"l32f\"            // Little-endian 32 bit IEEE 754 single floating point number.\n```\n\nThe floating-point numbers can be stored in little-endian or big-endian byte order.\n\n### Arrays of Raw Bytes\n\nA value will be converted to a big-endian array of bytes if followed by an `a`\nsuffix.\n\n**Mnemonic**: The letter `a` stands for *array*.\n\n```javascript\n\"l128a\"           // Unsigned little-endian 128 bit integer as big-endian array\n                  // of bytes.\n```\n\nNote that big-endian means that the most significant byte is at index `0` of the\narray.\n\nThis can be surprising if you're expecting the significance of the bytes will\nincrease with the index of the array, but then that's what little-endian is all\nabout. (Big-endian orders like Arabic numerals, while little-endian orders like\noffsets into memory.)\n\nIf you'd prefer a little-endian array, simply call `reverse` on the array passed\nto you.\n\n### Arrays of Common Types\n\nIt is often the case that a binary format contains an array of values. The most\ncommon case are arrays of bytes representing ASCII or UTF-8 strings.\n\nArrays are specified with an subscript and a count.\n\n**Mnemonic**: The square brackets are used as array subscripts in JavaScript,\nand used to declare array length in other C dialect languages.\n\n```javascript\n\"b32[4]\"          // An array of four big-endian 32 bit numbers.\n\"b8[16]\"          // An array of 16 bytes.\n```\n\nThe array notation produces an array of the type before the subscript.\n\n### Zero Terminated Arrays\n\nZero terminated series are specified with a `z` qualifier.\n\nYou can specify both termination and width together. Why would you need this?\nThis occurs in underlying C structures when there is a fixed width character\narray in a structure, but the structure still contains a zero terminated string.\n\n**Upcoming**: Chose your own terminator.\n\n**Mnemonic**: The letter `z` stands for zero.\n\n```javascript\n\"l16z\"            // Little-endian 16 bit numbers terminated by a zero value.\n\"b8z\"             // Byte string terminated by zero.\n\"b8[12]z\"         // Byte string terminated by zero in a field 12 bytes long.\n```\n\n### Array Padding\n\nYou can specify a padding value immediately after the array brackets using curly\nbraces. This should be the numeric value, or character code for padding. If you\nwant to zero pad, use `0`. If you want to pad with ASCII spaces use `32`.\n\n**Mnemonic**: Curly braces are used to define array literals in C.\n\n```javascript\n\"b16[12]{0}\"      // Array of 12 big-endian 16 bit integers, zero padded.\n\"b8[12]{32}z\"     // Byte string terminated by zero in a field 12 bytes long\n                  // ascii space padded.\n```\n### Length Encoded Arrays\n\nLength encoded arrays are specified by joining a count type and a value type\nwith a forward slash character `/`.\n\n**Mnemonic**: Inspired by Perl's `pack`, which uses the slash to separate count\nand type.\n\n```javascript\n\"b8/b8\"           // Length encoded byte array with a byte length.\n\"l16/b8\"          // Length encoded byte array with 16 bit little-endian length.\n```\n\n### Bit Packed Integers\n\nIntegers are often divided into smaller integers through a process called bit\npacking. Bit packing is specified by following an integer specification with\na curly brace enclosed series series of integers patterns whose total size in\nbits equals the size of the packed integer.\n\nPacked integers are always big-endian and can be either singed or unsigned.\n\n**Mnemonic** Curly braces are used to define structures in C and bit packing is\nkind of like a structure.\n\n```javascript\n\"b16{b3,x6,-b7}\"  // A 16 bit big-endian integer divided into a 3-bit integer,\n                  // 6 skipped bits, and a signed 7-bit integer.\n```\n\nYou can also name the packed fields.\n\n```javascript\n\"b16{b3 => type, x6, -b7 => count}\"\n```\n\n### Alternate Patterns\n\nA common pattern in binary formats is using the value of a byte, or the high\norder bits of a byte to specify the type of data to follow. [Length Encoded\nArrays](#length-encoded-arrays) are one example of this practice, where a\nan integer count indicates the length of a following string or array.\n\nWith an alternate pattern, **Packet** will extract an integer from the byte\nstream, then choose a pattern based on the value of that integer. The pattern is\napplied at the index where the integer used to choose the pattern was extracted.\nThat is, the bytes used to choose the pattern are included when the pattern is\napplied. It is a peek and switch.\n\nAlternate patterns are grouped by parenthesis `(` and `)` and delimited by pipes\n`|`. Each alternative maps a match to a pattern separated by a colon `:`.\n\n**Mnemonic** &mdash; Parenthesis and pipes are used to indicate alternation in\nregular expressions, while colons are used to delineate switch options in C.\n\n```javascript\n// MySQL length coded binary; if the byte is less than 252, use the byte value,\n// otherwise the byte value indicates the length of the following word.\n\"b8(0-251: b8 | 252: x8, b16 | 253: x8, b24 | 254: x8, b64)\"\n```\n\nConditions are either a value to match exactly or a range of values. **Packet**\ntests each condition is tested in order. **Packet** uses the alternation of the\nfirst condition to match the extracted integer is used. An alternate without a\ncondition will always match. This is used to specify a default pattern.\n\n```javascript\n// Simpiler, but will also match 255 which is invalid, which is fine if you test\n// the value in your callback.\n\"b8(252: x8, b16 | 253: x8, b24 | 254: x8, b64 | b8)\"\n```\n\nThe values can be expressed in binary, decimal or hexadecimal.\n\n### Bitwise Alternate Patterns\n\nYou can also indicate a branch based on set bits by prefixing the value with an\nampersand. **Packet** will use the value as a bit mask. If the result of a\nlogical *and* with the bit mask equals the bit mask, then **Packet** use use\nthat alternative.\n\n**Mnemonic** The `&` performs a logical and in C and is used to check to see if\nbits in a bit mask are set.\n\n```javascript\n\"b8(&0x80: b16{x1,b15} | b8)\"   // A 15-bit word if the first bit is set,\n                                // otherwise a byte.\n```\n\nBitwise conditions cannot be used in to choose a pattern for serialization. Upon\nserialization, the field value is a JavaScript number, not an stream of bytes.\nThe bit flag simply does not exist.\n\nInstead, we need to perform a range check to determine which pattern. To delimit\nalternate tests for reading and writing, we use a slash in the condition.\n\n```javascript\n// A 15-bit word if the first bit is set, otherwise a byte.\n\"b8(&0x80/0x80-0xffff: b16{x1{1},b15} | b8)\"\n```\n\n### Multi-Field Alternate Patterns\n\nAlternate patterns can define either a single field or multiple field.\nAlternate patterns can contain bit-packed patterns, but they cannot contain\nstill more alternate patterns.\n\n```javascript\n// Two alternate patterns with a different number of fields.\n\"b8(&0x80/1: b16{b1, b15}, b16|b32{b1, b31})\"\n```\n\nIn the above example, the serialization test would be applied to the field value\nin the position of the `b1` field for either alternate.\n\n### Named Alternate Patterns\n\nNames can be applied either to the entire alternation if the alternation\nproduces a single field, or else to individual members of the alternate\npatterns.\n\n```\n// A single field mapped to a name.\n\"b8(&0x80/0x80-0xffff: b16{x1{1},b15} | b8) => number\"\n```\n\nWhen serializing named multi-field patterns, for each alternate, **Packet** will\nuse the first value of the property in the alternate for the serialization\ncondition. **Packet** reads the property from the object we're serializing. If\nthe value is not null, it is tested against the serialization condition. If it\nis null, the test is skipped. We use the first alternate whose object property\nis not null and whose serialization condition matches the object property.\n\n```javascript\n// Multi-field alternates mapped to names.\n\"b8(&0x80/1: b16{b1 => control, b15 => type}, x16|b32{b1 => control, b31 => sequence})\"\n```\n\n### Transforms\n\nOften there are transformations that you need to perform on an field to get\nit to its final state. You may need to convert a byte array to string of a\nparticular character encoding, for example. This is done with a transformation\nfunctions which are specified with a transformation pipeline.\n\nIf the transformation is a fixed transformation, you can perform the\ntransformation by defining a pipeline. A pipeline defines one or more\ntransformations that are invoked on the value after parsing and before\nserialization. The transformations can accept scalar JavaScript parameters.\n\n```javascript\nfunction str(encoding, name, field, parsing, value) {\n    if (parsing) {\n        var buffer = new Buffer(array.length)\n        for (var i = 0; i &lt; value.length; i++) {\n            buffer[i] = value[i];\n        }\n        var length = value.length\n        if (field.terminator) {\n            length += field.terminator.length;\n        }\n        return buffer.toString(encoding, 0, length);\n    } else {\n        if (field.terminator) {\n            value += field.terminator;\n        }\n        return new Buffer(value, encoding);\n    }\n}\n```\n\nNow you can use the transform in your pattern.\n\n```javascript\n\"b8z|str('ascii')\"      // An ascii string terminated by zero.\n\"b8z|str('ascii'), b16\" // An ascii string terminated by zero followed by a\n                        // big-endian 16 bit integer.\n```\n\nThe `str` transform is defined by default. The transform names are purposely\nterse to fit with the brevity of the pattern language.\n\n## Error Messages\n\nError messages for pattern parsing.\n\n * **invalid pattern at N** &mdash; The characters starting at the specified\n   index is unexpected the pattern is invalid. The invalid character may not be\n   at the specified index, but shortly there after, such as unmatched braces.\n * **bit field overflow at N** &mdash; The sum of the bit size of bit field\n   elements is greater than the size of the containing element. The sum of the\n   bit size of bit field elements must equal the size of the containing element.\n * **bit field underflow at N** &mdash; The sum of the bit size of bit field\n   elements is less than the size of the containing element. The sum of the bit\n   size of bit field elements must equal the size of the containing element.\n * **bit size must be non-zero at N** &mdash; Encountered element with a bit size of\n   zero. Element size must be a non-zero value.\n * **bits must be divisible by 8 at N** &mdash; Encountered element with a bit\n   size that is not divisible by 8. If an element is not a bit field element, it\n   must align to an 8-bit boundary.\n * **floats can only be 32 or 64 bits at N** &mdash; Encountered a float element\n   with an unsupported bit size. Only 32 and 64 bit floats are supported.\n * **\"array length must be non-zero at N** &mdash; Encountered an array length\n   of zero. Arrays must have a non-zero length.\n\n## Change Log\n\nChanges for each release.\n\n### Version 0.0.6\n\nWed Jul  3 21:52:20 UTC 2013\n\n * Implement `Serializer.offsetsOf`. #87. #85. #86. #63.\n * Objects primary, positional arguments secondary. #84.\n * Reset namedness of `Parser`. #83.\n * Serialize and parsed a named length encoded array. #82.\n * Increase test coverage.  #77. #69. #68. #67. #66.\n * Test text to float conversion. #66.\n * Remove `n` syntax from README. @jryans. #64.\n * Remove detection of `n` synonym for `b`.\n * Remove asterisk to indicate wildcard condition. #33.\n * `Parser.parse` returns bytes read. #60.\n * Report coverage to Coveralls. #61.\n * Rename `pattern` to `field`. #57.\n * Massive tidy after change in enclosed objects.\n\n### Version 0.0.5\n\nFri Mar  1 03:05:15 UTC 2013\n\n * Chunked serialization bug fixes. #59. #58. #55.\n * Move supporting libraries to root directory. #44.\n * Spell check `README.md` and remove dead features. #32. #55.\n * Implement `sizeOf` property for serializer. #37.\n * Fix minimum number value. #54.\n\n### Version 0.0.4\n\nMon Nov  6 04:50:16 UTC 2012.\n\n * Create parsers and serializers from prototypes. #53.\n * Parse patterns with Win32 CRLF. #51. (Greg Ose <greg@nullmethod.com>)\n * Copy cached pattern for alternation rewriting. #50.\n * Flatten alternation prior to serialization. #34.\n * Add `.js` suffix to tests. #49.\n * Convert to closure style. #40, #47, #39, #38, #27.\n * Remove pausing from `Parser`. #46.\n * Implement `reset` for serializer. #43.\n * Single letter field names. #45.\n * Remove streams from API. #41.\n\n### Version 0.0.3\n\nFri Aug 17 00:40:37 UTC 2012.\n\n * Fix Packet in NPM. #12.\n * Serialize alternate structures. #31.\n * Test serialization of words. #20.\n * Serializer not exported by `index.js`.\n * Named patterns reset buffer offset. #29.\n * Allow spaces before alternation condition. #28.\n * Create a markdown `README.md`. #18.\n * Build on Node 0.8 at Travis CI. #23.\n * Fix too greedy match of bit packing pattern. #19.\n * Skip leading whitespace in pattern. #15.\n\n## Contributors\n\n  * [Ben Hockey](https://github.com/neonstalwart)\n  * [Aaron Qian](https://github.com/aq1018)\n","readmeFilename":"README.md","gitHead":"aaac44883ee9a33376c905b84b8edb1a7c117db0","_id":"packet@1.0.0-alpha.2","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-Fl2N0B3Zz8zn9bUd7mzqQUX+Z9PgAPLeA5MEMFvfC2bQZjitzuYIctracsyfUB6TwpUPsJBRL6KnG/hrWuCSSA==","shasum":"56552095ee7cefb7891c9e7b8e7af15e13f269f5","tarball":"https://registry.npmjs.org/packet/-/packet-1.0.0-alpha.2.tgz","fileCount":32,"unpackedSize":273556,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgWLlkCRA9TVsSAnZWagAApjAQAKFMYq9hnKkrjGFX9gpP\nDX9ldNH7SG7EaSG2PfGXW+Ho57+OH0jYxPW5daiOKPpW4VPElkFxDyFcyRHc\nVp8iPBT+6QNCMCYKNR5Yuef61RCb2BrQTYIPtUmjxUQfY9pSZrE0sZJiL3LB\noz9ym+FRJn749kdtNBIrNZDNkBpETK4yzvnw+880vdSL/6S7zh6omOy4CgT8\nulguMctdKThxuuMFxCAXZydEZNp0YhD/8hh00qnSXiqGxK7zpQGsfmdN1pqX\nmM1lNaIimEvEIqRg7JyPYDBMZqlHaGFyVndQSdcHMOeJvWmaAhwAMv3lHkFd\nTqS/PIE5YQCwIEQObwY8Xiigy6pOpYWzRNF5J4bUs+AyMDcqKEAv2xuoB47e\nf2Ts1fnoq5ahF0Zbk/8hOAq8ddzljvVnPQuL4KAidPbfz0HdD9SLlxDmJ/qx\nbiQB7kyAG73BeLhtz8cKmIdnERrHqUNWbCTMKoqFSQDR5IRBRzZU5GiKsEwc\n2W471hCQ4AZc0x6FJvK7zjyFcaCsTpRkoXkd6/6V448mDgqd+nW9X7LqpnDN\nYO3ezFB7vXCI3QyLJpA3ntH8KBgudCb3kX3F/r3mTHwx5z5S21PkkPD7OOsL\nZmjYPOvyqhRQ7YHWI9MNkNhkCMBYFIwiNPuMC/EX9fQXM4J5JiH1Azfc5ld7\nAGR/\r\n=tUzi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDFW6B1l37gwaAJuBIgq+Mi9RRTixgPF1dkKiXZCfB6AwIhAMfHJ/OW6tcMp/gVhogaQqYi6OzAIE7cq/XiQrYY/DCH"}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/packet_1.0.0-alpha.2_1616427363994_0.9912096514594528"},"_hasShrinkwrap":false},"1.0.0-alpha.3":{"name":"packet","version":"1.0.0-alpha.3","description":"Pure JavaScript evented binary parsers and serializers for Node.js.","keywords":["packet","pack","binary","network","structure","async","asynchronous","javascript"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"contributors":[{"name":"J. Ryan Stinnett","email":"jryans@gmail.com"},{"name":"Ben Hockey","email":"neonstalwart@gmail.com"},{"name":"Greg Ose","email":"neonstalwart@gmail.com","url":"http://nullmethod.com/"},{"name":"Aaron Qian","email":"aq1018@gmail.com"},{"name":"Demarius Chrite","email":"chrite.demarius@gmail.com","url":"https://github.com/demarius"}],"homepage":"https://github.com/bigeasy/packet","bugs":{"url":"https://github.com/bigeasy/packet/issues"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/bigeasy/packet.git"},"dependencies":{"fast-deep-equal":"3.1.3","programmatic":"2.0.0-alpha.9"},"devDependencies":{"extant":"^2.0.0-alpha.0","proof":"^9.0.3"},"main":"packet.js","scripts":{"test":"proof -n --allow-natives-syntax test/*/*.t.js"},"nyc":{"exclude":["test/**","!test/generated","inlines.js"]},"readme":"[![Actions Status](https://github.com/bigeasy/packet/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/packet/actions)\n[![codecov](https://codecov.io/gh/bigeasy/packet/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/packet)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA comparator function builder.\n\n| What          | Where                                         |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/packet/issues/1    |\n| Documentation | https://bigeasy.github.io/packet              |\n| Source        | https://github.com/bigeasy/packet             |\n| Issues        | https://github.com/bigeasy/packet/issues      |\n| CI            | https://travis-ci.org/bigeasy/packet          |\n| Coverage:     | https://codecov.io/gh/bigeasy/packet          |\n| License:      | MIT                                           |\n\n\n```\nnpm install packet\n```\n\nIncremental binary parsers and serializers for Node.js.\n\n### Diary\n\nIn the middle of the final rewrite after many years of learning about Node.js.\n\nCurrently working in the `compose` folder to create compiled parsers based on\nthe work in `composer`.\n\n### Continue\n\nPacket creates **pre-compiled**, **pure-JavaScript**, **binary parsers** and\n**serializers** that are **incremental** through a binary pattern language that\nis **declarative** and very **expressive**.\n\nRewrite pending.\n\nPacket simplifies the construction an maintenance of libraries that convert\nbinary to JavaScript and back. The name Packet may make you think that it is\ndesigned solely for binary network protocols, but it is also great for reading\nand writing binary file formats.\n\n**Incremental** &mdash; Node packet creates incremental parsers and serializers\nthat are almost as fast as the parser you'd write by hand, but a lot easier to\ndefine and maintain.\n\n**Declarative** &mdash; Packet defines a binary structure using a pattern\nlanguage inspired by Perl's `pack`. The binary patterns are used to define both\nparsers and serializers. If you have a protocol specification, or even just a C\nheader file with structures that define your binary data, you can probably\ntranslate that directly into Packet patterns.\n\nFor parsers, you associate the patterns to callbacks invoked with captured\nvalues when the pattern is extracted from the stream. For serializers you simply\ngive the values to write along with the pattern to follow when writing them.\n\n**Expressive** &mdash; The pattern language can express\n\n  * signed and unsigned integers,\n  * endianess of singed and unsigned integers,\n  * floats and doubles,\n  * fixed length arrays of characters or numbers,\n  * length encoded strings of characters or numbers,\n  * zero terminated strings of characters or numbers,\n  * said strings terminated any fixed length terminator you specify,\n  * padding of said strings with any padding value you specify,\n  * signed and unsigned integers extracted from bit packed integers,\n  * conditions based on bit patterns\n  * character encodings,\n  * custom transformations,\n  * and pipelines of character encodings and custom transformations.\n\n### Limitations\n\n**Parsing not searching** &mdash; Packet is not a pattern matching library. It\ndoes not search binary streams for patterns. Packet is used for parsing\nwell-defined streams of binary data.\n\n**8-bit boundaries** &mdash; I'm unable to think of an example in contemporary\ncomputing that doesn't align to an 8-bit boundary, but the world is big and I am\nsmall, so I plan on being surprised. I can also imagine that someone might want\nto unleash Packet on legacy data someday, from way back when a byte was whatever\na computer manufacturer said it was.\n\nTherefore, It's worth noting that Packet parses 8-bit bytes and expects bytes to\nalign to an 8-bit boundary. Packet can parse 7-bit ASCII formats like `tar`\narchives, because they are 8-bit aligned with the top bit ignored. Packet can\nalso parse and serialize bit packed integers, so it does support awkward integer\nsizes, but within an 8-bit aligned integer.\n\n## Installing\n\nInstall Packet using NPM.\n\n```\nnpm install packet\n```\n\nThe source is available on [GitHub](https://github.com/bigeasy/packet).\n\n## Parsers and Serializers\n\nPacket defines a binary format using a binary pattern language inspired by\nPerl's `pack` function. The pattern language is used in a `Parser` to define the\nparameters passed to callback when enough bytes are read from the input stream\nto satisfy the pattern. The pattern language is used in a `Serializer` to define\nhow JavaScript primitives passed to the `serialize` method are written to\nstream.\n\n### Patterns\n\nPatterns are a series of element declarations joined by commas.\n\n```javascript\nparser.extract(\"length: b16, address: b32, name: b8z\", function (object) {\n  console.log(object.length, object.address, object.name);\n});\nparser.parse([ 0x01, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00 ]);\n```\n\nYou can also name the elements in a pattern. If named, parsers will be create an\nobject to pass to callbacks, serializers will serialize an object's properties.\n\n```javascript\nparser.extract(\"b16 => length, b32 => address, b8z => name\", function (record) {\n  console.log(record);\n});\nparser.parse([ 0x01, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00 ]);\n```\n\nUnnamed elements are good for short, simple patterns. For longer patterns it is\neasier to have a parser build an object for you.\n\nThe following example shows a complicated pattern, the invariable portion of an\nIP header, the first 20 bytes before options, if any.\n\n```javascript\n// Define an IP header pattern using a joined array to explode the pattern.\nparser.packet('ip', 'b8{version: b4, headerLength: b4},         \\\n                     typeOfService: b8,                         \\\n                     length: b16,                               \\\n                     identification: b16,                       \\\n                     b16{flags: b3, fragmentOffset: b13},       \\\n                     timeToLive: b8,                            \\\n                     protocol: b8,                              \\\n                     checksum: b16,                             \\\n                     sourceAddress: b32,                        \\\n                     destinationAddress: b32                    \\\n                    ');\n\n// The pattern is then used to defined parser and serializer actions.\nparser.extract(\"ip\", function (header) {\n  console.log(header);\n});\nparser.parse(buffer);\n```\n\nBoth parsers and serializers can define patterns using the `packet` method. The\n`packet` method allows you to pre-compile patterns.\n\n```javascript\n// Create a parser and define a header.\nvar parser = require('packet').createParser();\nparser.packet(\"header\", \"b8 => type, b16 => length, b32 => extra\");\nparser.packet(\"data\", \"b16 => sequence, b16 => crc\");\n\n// Now you can define your serializer using your parser as a prototype. The\n// serializer will inherit the parser's packet definitions.\nvar serializer = parser.createSerializer();\n```\n\nParsers and serializers maintain internal state so that they can be used\nincrementally. If you're going to parse streams incrementally, you're going to\nneed a parser for each stream your parsing. Same goes for serializers and\nserializing.\n\nWhen parsing/serializing incrementally create new parsers and serializers using\nthe prototype pattern above.\n\n```javascript\n// Create a serializer and define a header.\nvar serializer = require(\"packet\").createSerializer();\nserializer.packet(\"header\", \"b8 => type, b16 => length, b32 => extra\");\nserializer.packet(\"data\", \"b16 => sequence, b16 => crc\");\n\n// Now you can define parsers for a using the serializer as a prototype.\nnet.createServer(function (socket) {\n  var parser = serializer.createParser();\n  socket.on(\"data\", function (buffer) {\n    parser.parse(buffer);\n  });\n  parser.extract(\"header\", function (header) {\n    console.log(header);\n  });\n});\n```\n\n### Parsers\n\nParsers parse a buffer extracting a specified pattern. The pattern is specified\nusing the `extract` method. The `extract` method accept either a pattern or the\nname a pre-compiled pattern.\n\nAfter the pattern has been specified, the parser will extract the data from one\nor more buffers according to the specified pattern.\n\nWhen the pattern specified by `extract` has been read from the series of\nbuffers, it will invoke a callback with the extracted values. The `extract`\ncallback has the option of calling the `extract` method specifying a subsequent\npattern for the parser to extract. When the callback returns, the parser will\nimmediately continue to parse the newly specified pattern from the series of\nbuffers.\n\nThe parser callback receives the values either as positioned function arguments\nor as an object. How the callback is invoked is based on the pattern and the\n[arity](http://en.wikipedia.org/wiki/Arity) of the callback function.\n\nTo receive an object in the callback, we defined named elements. When the\npattern has at least one named element, and the callback has only a single\nargument, an object is passed to the callback containing the values using the\nelement names as keys.\n\nUnnamed elements are excluded, but there's no good reason not name them. Use a\nskip pattern to skip over unwanted bytes instead.\n\nYou can still get positioned arguments using a named pattern. Just provide a\ncallback with more than one argument and it will be invoked with the extract\nvalues as parameters.\n\nA callback for a pattern without any named elements is always invoked with\nvalues as parameters regardless of arity.\n\n### Serializers\n\nFirst you call `serialize` with a pattern and arguments to serialize, then you\ncall `write` with a series of buffers.\n\n## Binary Pattern Fields\n\nThe binary pattern language is used to specify the fields binary structures in\ndata streams, using a comma separated field pattern.\n\n### Big-Endian Byte Ordering\n\nTo define a big-endian byte ordering for a field, prefix the bit size with `b`.\n\n```yaml\nmnemonic: The letter `b` stands for big-endian.\nexamples:\n  -\n    pattern: world: b16\n    object:\n      word: 256\n    description: Big-endian 32 bit number.\n  -\n    pattern: byte: b8\n    object:\n      byte: 1\n    description: Endianess of a single byte is irrelevant.\n  -\n    pattern: word: l16, byte: b8\n    object:\n      word: 1\n      byte: 1\n    parsed: 0x01, 0x00, 0x01\n```\n\n**Mnemonic**: The letter `b` stands for big-endian.\n\n```javascript\n\"b16\"             // Big-endian 32 bit number.\n\"b8\"              // Endianess of a single byte is irrelevant.\n\"l16, b8\"         // Big-endian 16 bit integer followed by a byte.\n```\n\n### Little-Endian Byte Ordering\n\nTo define a little-endian byte ordering for a field, prefix the bit size with `l`.\n\n**Mnemonic**: The letter `l` stands for little-endian.\n\n```javascript\n\"l32\"             // Little-endian 32 bit integer.\n\"l8\"              // Endianess of a single byte is irrelevant.\n\"l16, b8\"         // Little endian 16 bit integer followed by a byte.\n```\n\n### Skipping Bytes\n\nYou can skip over bytes your pattern with `x`.\n\n**Mnemonic**: The letter `x` means to cross-out, which is kind of like skipping.\n\n```javascript\n\"b8, x16, l16\"    // A byte, two skipped bytes, and a little-endian 16 bit\n                  // integer.\n```\n\n### Signed Versus Unsigned Integers\n\nAll numbers are assumed to be unsigned, unless prefixed by a negative symbol.\n\n**Mnemonic**: The `-` symbol indicates the possibility of negative numbers.\n\n```javascript\n\"-b32\"            // Big-endian 32 bit signed integer.\n\"-l32\"            // Little-endian 32 bit signed integer.\n\"b32\"             // Big-endian 32 bit unsigned integer.\n```\n\n### IEEE 754 Floating Point Numbers\n\nThe number type for JavaScript is the  64 bit IEEE 754 floating point. Packet\ncan read write 64 bit and 32 bit IEEE 754 floating point numbers.\n\nTo indicated that the type is a floating point number, use the `f` type suffix.\nThis is indicated with a `f` suffix.\n\n**Mnemonic**: The letter `f` stands for\n*floating-point*.\n\n```javascript\n\"b64f\"            // Big-endian 64 bit IEEE 754 double floating point number.\n\"l32f\"            // Little-endian 32 bit IEEE 754 single floating point number.\n```\n\nThe floating-point numbers can be stored in little-endian or big-endian byte order.\n\n### Arrays of Raw Bytes\n\nA value will be converted to a big-endian array of bytes if followed by an `a`\nsuffix.\n\n**Mnemonic**: The letter `a` stands for *array*.\n\n```javascript\n\"l128a\"           // Unsigned little-endian 128 bit integer as big-endian array\n                  // of bytes.\n```\n\nNote that big-endian means that the most significant byte is at index `0` of the\narray.\n\nThis can be surprising if you're expecting the significance of the bytes will\nincrease with the index of the array, but then that's what little-endian is all\nabout. (Big-endian orders like Arabic numerals, while little-endian orders like\noffsets into memory.)\n\nIf you'd prefer a little-endian array, simply call `reverse` on the array passed\nto you.\n\n### Arrays of Common Types\n\nIt is often the case that a binary format contains an array of values. The most\ncommon case are arrays of bytes representing ASCII or UTF-8 strings.\n\nArrays are specified with an subscript and a count.\n\n**Mnemonic**: The square brackets are used as array subscripts in JavaScript,\nand used to declare array length in other C dialect languages.\n\n```javascript\n\"b32[4]\"          // An array of four big-endian 32 bit numbers.\n\"b8[16]\"          // An array of 16 bytes.\n```\n\nThe array notation produces an array of the type before the subscript.\n\n### Zero Terminated Arrays\n\nZero terminated series are specified with a `z` qualifier.\n\nYou can specify both termination and width together. Why would you need this?\nThis occurs in underlying C structures when there is a fixed width character\narray in a structure, but the structure still contains a zero terminated string.\n\n**Upcoming**: Chose your own terminator.\n\n**Mnemonic**: The letter `z` stands for zero.\n\n```javascript\n\"l16z\"            // Little-endian 16 bit numbers terminated by a zero value.\n\"b8z\"             // Byte string terminated by zero.\n\"b8[12]z\"         // Byte string terminated by zero in a field 12 bytes long.\n```\n\n### Array Padding\n\nYou can specify a padding value immediately after the array brackets using curly\nbraces. This should be the numeric value, or character code for padding. If you\nwant to zero pad, use `0`. If you want to pad with ASCII spaces use `32`.\n\n**Mnemonic**: Curly braces are used to define array literals in C.\n\n```javascript\n\"b16[12]{0}\"      // Array of 12 big-endian 16 bit integers, zero padded.\n\"b8[12]{32}z\"     // Byte string terminated by zero in a field 12 bytes long\n                  // ascii space padded.\n```\n### Length Encoded Arrays\n\nLength encoded arrays are specified by joining a count type and a value type\nwith a forward slash character `/`.\n\n**Mnemonic**: Inspired by Perl's `pack`, which uses the slash to separate count\nand type.\n\n```javascript\n\"b8/b8\"           // Length encoded byte array with a byte length.\n\"l16/b8\"          // Length encoded byte array with 16 bit little-endian length.\n```\n\n### Bit Packed Integers\n\nIntegers are often divided into smaller integers through a process called bit\npacking. Bit packing is specified by following an integer specification with\na curly brace enclosed series series of integers patterns whose total size in\nbits equals the size of the packed integer.\n\nPacked integers are always big-endian and can be either singed or unsigned.\n\n**Mnemonic** Curly braces are used to define structures in C and bit packing is\nkind of like a structure.\n\n```javascript\n\"b16{b3,x6,-b7}\"  // A 16 bit big-endian integer divided into a 3-bit integer,\n                  // 6 skipped bits, and a signed 7-bit integer.\n```\n\nYou can also name the packed fields.\n\n```javascript\n\"b16{b3 => type, x6, -b7 => count}\"\n```\n\n### Alternate Patterns\n\nA common pattern in binary formats is using the value of a byte, or the high\norder bits of a byte to specify the type of data to follow. [Length Encoded\nArrays](#length-encoded-arrays) are one example of this practice, where a\nan integer count indicates the length of a following string or array.\n\nWith an alternate pattern, **Packet** will extract an integer from the byte\nstream, then choose a pattern based on the value of that integer. The pattern is\napplied at the index where the integer used to choose the pattern was extracted.\nThat is, the bytes used to choose the pattern are included when the pattern is\napplied. It is a peek and switch.\n\nAlternate patterns are grouped by parenthesis `(` and `)` and delimited by pipes\n`|`. Each alternative maps a match to a pattern separated by a colon `:`.\n\n**Mnemonic** &mdash; Parenthesis and pipes are used to indicate alternation in\nregular expressions, while colons are used to delineate switch options in C.\n\n```javascript\n// MySQL length coded binary; if the byte is less than 252, use the byte value,\n// otherwise the byte value indicates the length of the following word.\n\"b8(0-251: b8 | 252: x8, b16 | 253: x8, b24 | 254: x8, b64)\"\n```\n\nConditions are either a value to match exactly or a range of values. **Packet**\ntests each condition is tested in order. **Packet** uses the alternation of the\nfirst condition to match the extracted integer is used. An alternate without a\ncondition will always match. This is used to specify a default pattern.\n\n```javascript\n// Simpiler, but will also match 255 which is invalid, which is fine if you test\n// the value in your callback.\n\"b8(252: x8, b16 | 253: x8, b24 | 254: x8, b64 | b8)\"\n```\n\nThe values can be expressed in binary, decimal or hexadecimal.\n\n### Bitwise Alternate Patterns\n\nYou can also indicate a branch based on set bits by prefixing the value with an\nampersand. **Packet** will use the value as a bit mask. If the result of a\nlogical *and* with the bit mask equals the bit mask, then **Packet** use use\nthat alternative.\n\n**Mnemonic** The `&` performs a logical and in C and is used to check to see if\nbits in a bit mask are set.\n\n```javascript\n\"b8(&0x80: b16{x1,b15} | b8)\"   // A 15-bit word if the first bit is set,\n                                // otherwise a byte.\n```\n\nBitwise conditions cannot be used in to choose a pattern for serialization. Upon\nserialization, the field value is a JavaScript number, not an stream of bytes.\nThe bit flag simply does not exist.\n\nInstead, we need to perform a range check to determine which pattern. To delimit\nalternate tests for reading and writing, we use a slash in the condition.\n\n```javascript\n// A 15-bit word if the first bit is set, otherwise a byte.\n\"b8(&0x80/0x80-0xffff: b16{x1{1},b15} | b8)\"\n```\n\n### Multi-Field Alternate Patterns\n\nAlternate patterns can define either a single field or multiple field.\nAlternate patterns can contain bit-packed patterns, but they cannot contain\nstill more alternate patterns.\n\n```javascript\n// Two alternate patterns with a different number of fields.\n\"b8(&0x80/1: b16{b1, b15}, b16|b32{b1, b31})\"\n```\n\nIn the above example, the serialization test would be applied to the field value\nin the position of the `b1` field for either alternate.\n\n### Named Alternate Patterns\n\nNames can be applied either to the entire alternation if the alternation\nproduces a single field, or else to individual members of the alternate\npatterns.\n\n```\n// A single field mapped to a name.\n\"b8(&0x80/0x80-0xffff: b16{x1{1},b15} | b8) => number\"\n```\n\nWhen serializing named multi-field patterns, for each alternate, **Packet** will\nuse the first value of the property in the alternate for the serialization\ncondition. **Packet** reads the property from the object we're serializing. If\nthe value is not null, it is tested against the serialization condition. If it\nis null, the test is skipped. We use the first alternate whose object property\nis not null and whose serialization condition matches the object property.\n\n```javascript\n// Multi-field alternates mapped to names.\n\"b8(&0x80/1: b16{b1 => control, b15 => type}, x16|b32{b1 => control, b31 => sequence})\"\n```\n\n### Transforms\n\nOften there are transformations that you need to perform on an field to get\nit to its final state. You may need to convert a byte array to string of a\nparticular character encoding, for example. This is done with a transformation\nfunctions which are specified with a transformation pipeline.\n\nIf the transformation is a fixed transformation, you can perform the\ntransformation by defining a pipeline. A pipeline defines one or more\ntransformations that are invoked on the value after parsing and before\nserialization. The transformations can accept scalar JavaScript parameters.\n\n```javascript\nfunction str(encoding, name, field, parsing, value) {\n    if (parsing) {\n        var buffer = new Buffer(array.length)\n        for (var i = 0; i &lt; value.length; i++) {\n            buffer[i] = value[i];\n        }\n        var length = value.length\n        if (field.terminator) {\n            length += field.terminator.length;\n        }\n        return buffer.toString(encoding, 0, length);\n    } else {\n        if (field.terminator) {\n            value += field.terminator;\n        }\n        return new Buffer(value, encoding);\n    }\n}\n```\n\nNow you can use the transform in your pattern.\n\n```javascript\n\"b8z|str('ascii')\"      // An ascii string terminated by zero.\n\"b8z|str('ascii'), b16\" // An ascii string terminated by zero followed by a\n                        // big-endian 16 bit integer.\n```\n\nThe `str` transform is defined by default. The transform names are purposely\nterse to fit with the brevity of the pattern language.\n\n## Error Messages\n\nError messages for pattern parsing.\n\n * **invalid pattern at N** &mdash; The characters starting at the specified\n   index is unexpected the pattern is invalid. The invalid character may not be\n   at the specified index, but shortly there after, such as unmatched braces.\n * **bit field overflow at N** &mdash; The sum of the bit size of bit field\n   elements is greater than the size of the containing element. The sum of the\n   bit size of bit field elements must equal the size of the containing element.\n * **bit field underflow at N** &mdash; The sum of the bit size of bit field\n   elements is less than the size of the containing element. The sum of the bit\n   size of bit field elements must equal the size of the containing element.\n * **bit size must be non-zero at N** &mdash; Encountered element with a bit size of\n   zero. Element size must be a non-zero value.\n * **bits must be divisible by 8 at N** &mdash; Encountered element with a bit\n   size that is not divisible by 8. If an element is not a bit field element, it\n   must align to an 8-bit boundary.\n * **floats can only be 32 or 64 bits at N** &mdash; Encountered a float element\n   with an unsupported bit size. Only 32 and 64 bit floats are supported.\n * **\"array length must be non-zero at N** &mdash; Encountered an array length\n   of zero. Arrays must have a non-zero length.\n\n## Change Log\n\nChanges for each release.\n\n### Version 0.0.6\n\nWed Jul  3 21:52:20 UTC 2013\n\n * Implement `Serializer.offsetsOf`. #87. #85. #86. #63.\n * Objects primary, positional arguments secondary. #84.\n * Reset namedness of `Parser`. #83.\n * Serialize and parsed a named length encoded array. #82.\n * Increase test coverage.  #77. #69. #68. #67. #66.\n * Test text to float conversion. #66.\n * Remove `n` syntax from README. @jryans. #64.\n * Remove detection of `n` synonym for `b`.\n * Remove asterisk to indicate wildcard condition. #33.\n * `Parser.parse` returns bytes read. #60.\n * Report coverage to Coveralls. #61.\n * Rename `pattern` to `field`. #57.\n * Massive tidy after change in enclosed objects.\n\n### Version 0.0.5\n\nFri Mar  1 03:05:15 UTC 2013\n\n * Chunked serialization bug fixes. #59. #58. #55.\n * Move supporting libraries to root directory. #44.\n * Spell check `README.md` and remove dead features. #32. #55.\n * Implement `sizeOf` property for serializer. #37.\n * Fix minimum number value. #54.\n\n### Version 0.0.4\n\nMon Nov  6 04:50:16 UTC 2012.\n\n * Create parsers and serializers from prototypes. #53.\n * Parse patterns with Win32 CRLF. #51. (Greg Ose <greg@nullmethod.com>)\n * Copy cached pattern for alternation rewriting. #50.\n * Flatten alternation prior to serialization. #34.\n * Add `.js` suffix to tests. #49.\n * Convert to closure style. #40, #47, #39, #38, #27.\n * Remove pausing from `Parser`. #46.\n * Implement `reset` for serializer. #43.\n * Single letter field names. #45.\n * Remove streams from API. #41.\n\n### Version 0.0.3\n\nFri Aug 17 00:40:37 UTC 2012.\n\n * Fix Packet in NPM. #12.\n * Serialize alternate structures. #31.\n * Test serialization of words. #20.\n * Serializer not exported by `index.js`.\n * Named patterns reset buffer offset. #29.\n * Allow spaces before alternation condition. #28.\n * Create a markdown `README.md`. #18.\n * Build on Node 0.8 at Travis CI. #23.\n * Fix too greedy match of bit packing pattern. #19.\n * Skip leading whitespace in pattern. #15.\n\n## Contributors\n\n  * [Ben Hockey](https://github.com/neonstalwart)\n  * [Aaron Qian](https://github.com/aq1018)\n","readmeFilename":"README.md","gitHead":"d69a9ae21039b9fc77037d9f273ea7280c137a79","_id":"packet@1.0.0-alpha.3","_nodeVersion":"15.3.0","_npmVersion":"7.0.14","dist":{"integrity":"sha512-Sg+aAZLB0GvDGpJRA7mIYQFqsrKbwVTouXyI2LHn8XZRiqwufxXqc2aZYQzLPAXmBlH8ijKqF20E0HxOVLeh5Q==","shasum":"098ef8a579b3e8a96e68a2abd0e021e91f120f11","tarball":"https://registry.npmjs.org/packet/-/packet-1.0.0-alpha.3.tgz","fileCount":30,"unpackedSize":272462,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgWMeMCRA9TVsSAnZWagAAEBgP/0jCQN1uZqmUvG91ajVz\n68xIj2L4E9mMxb9RYYnmSmZ3/kkzFEdzuWyhIxaHrTIRwN+LTNM3qgU4aGCg\nKaYYRnvicV+R+aL48BnZfI6ko1q7DQCczqTYVLC0sM5ZIgSF34h7jbwOPyG+\nVc3aE/IrNhPUV6jS/VnDmcagxBbVQ5l6C5A2jQVr2LAGSs+ANks5KEHgUNEZ\n+HkENv2HpyMhvgaVOkOvCKZz2ndVVkHlhHYE1OQbuRiTKcmLF4msyI5t0D4u\nW/EaHc1kRxiUNx3GnR0VWShwI4xs4v4g+4Im4P3mFznf+7vGMJ6WJrIIvoCS\nUEpjpXn5iHb58mlLMxAFSkvUdr5ECt/N4of0grjPExb7dFHX8duVvky9ntr+\neqiyDFiGk/Gmv/Uq22/x3P3fpTgzC7bi0EB9KH2XfmYNJsOkPlnlzEfsX9nP\nWhudX5rgTZ6Mv79ZEG5iVwD1/4PIwXHLaKRXOPnplhTbEcAapjUBhYpnKFYj\n/rgbpjsoyMiaa+47xrDmV7g5XWDlGOMc75ufDDkp02jka7VeYY5vbkuO1TVD\nYEva3ROewpl2mURhDRVy21WNe4aG3il6sMqJkFE65Du8TEsNmekZ/gV7Wn2y\nAafoxcs7rhgXdFYChJNh/xDCJOJpSQ7EyiJyN1mv1cNLnjRSA7wwecfGlJ+z\nEVaT\r\n=9dBQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCQLy3thn2epjT9eBf9H8VZAYulmaOpAkC9nHJthjhI+AIgQJ70toDSiC1Jk+J8mWfQqdSx4rBvEDm29RkTN/3w0f4="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/packet_1.0.0-alpha.3_1616430988444_0.23801878457653958"},"_hasShrinkwrap":false},"1.0.0-alpha.4":{"name":"packet","version":"1.0.0-alpha.4","description":"Pure JavaScript evented binary parsers and serializers for Node.js.","keywords":["packet","pack","binary","network","structure","async","asynchronous","javascript"],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"contributors":[{"name":"J. Ryan Stinnett","email":"jryans@gmail.com"},{"name":"Ben Hockey","email":"neonstalwart@gmail.com"},{"name":"Greg Ose","email":"neonstalwart@gmail.com","url":"http://nullmethod.com/"},{"name":"Aaron Qian","email":"aq1018@gmail.com"},{"name":"Demarius Chrite","email":"chrite.demarius@gmail.com","url":"https://github.com/demarius"}],"homepage":"https://github.com/bigeasy/packet","bugs":{"url":"https://github.com/bigeasy/packet/issues"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/bigeasy/packet.git"},"dependencies":{"arguable":"13.0.0-alpha.7","fast-deep-equal":"3.1.3","programmatic":"2.0.0-alpha.12","staccato":"13.0.0-alpha.13"},"devDependencies":{"extant":"^2.0.0-alpha.5","ip":"1.1.5","mqtt-packet":"7.1.2","proof":"^9.0.3"},"main":"packet.js","scripts":{"test":"proof -n --allow-natives-syntax test/*/*.t.js"},"nyc":{"exclude":["test/**","!test/generated","inlines.js"]},"readme":"[![Actions Status](https://github.com/bigeasy/packet/workflows/Node%20CI/badge.svg)](https://github.com/bigeasy/packet/actions)\n[![codecov](https://codecov.io/gh/bigeasy/packet/branch/master/graph/badge.svg)](https://codecov.io/gh/bigeasy/packet)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nIncremental binary parsers and serializers for Node.js.\n\n| What          | Where                                         |\n| --- | --- |\n| Discussion    | https://github.com/bigeasy/packet/issues/1    |\n| Documentation | https://bigeasy.github.io/packet              |\n| Source        | https://github.com/bigeasy/packet             |\n| Issues        | https://github.com/bigeasy/packet/issues      |\n| CI            | https://travis-ci.org/bigeasy/packet          |\n| Coverage:     | https://codecov.io/gh/bigeasy/packet          |\n| License:      | MIT                                           |\n\nPacket creates **pre-compiled**, **pure-JavaScript**, **binary parsers** and\n**serializers** that are **incremental** through a packet definition pattern\nlanguage that is **declarative** and very **expressive**.\n\nPacket simplifies the construction and maintenance of libraries that convert\nbinary to JavaScript and back. The name Packet may make you think that it is\ndesigned solely for binary network protocols, but it is also great for reading\nand writing binary file formats.\n\n**Incremental** &mdash; Node packet creates incremental parsers and serializers\nthat are almost as fast as the parser you'd write by hand, but a easier to\ndefine and maintain.\n\n**Declarative** &mdash; Packet defines a binary structure using a syntax-bashed\nJavaScript definition langauge. A single definition is used to define both\nparsers and serializers. If you have a protocol specification, or even just a C\nheader file with structures that define your binary data, you can probably\ntranslate that directly into a Packet definition.\n\n**Expressive** &mdash; The pattern language can express\n\n  * signed and unsigned integers,\n  * endianess of singed and unsigned integers,\n  * floats and doubles,\n  * fixed length arrays of characters or numbers,\n  * length encoded strings of characters or numbers,\n  * zero terminated strings of characters or numbers,\n  * said strings terminated any fixed length terminator you specify,\n  * padding of said strings with any padding value you specify,\n  * signed and unsigned integers extracted from bit packed integers,\n  * string to integer value mappings,\n  * if/then/else conditionals,\n  * switch conditions,\n  * character encodings,\n  * custom transformations,\n  * assertions,\n  * and pipelines of custom transformations and assertions.\n\nPacket installs from NPM.\n\n```text\nnpm install packet\n```\n\n## Living `README.md`\n\nThis `README.md` is also a unit test using the\n[Proof](https://github.com/bigeasy/proof) unit test framework. We'll use the\nProof `okay` function to assert out statements in the readme. A Proof unit test\ngenerally looks like this.\n\n```javascript\nrequire('proof')(4, okay => {\n    okay('always okay')\n    okay(true, 'okay if true')\n    okay(1, 1, 'okay if equal')\n    okay({ value: 1 }, { value: 1 }, 'okay if deep strict equal')\n})\n```\n\nYou can run this unit test yourself to see the output from the various\ncode sections of the readme.\n\n```text\ngit clone git@github.com:bigeasy/packet.git\ncd packet\nnpm install --no-package-lock --no-save\nnode --allow-natives-syntax test/readme/readme.t.js\n```\n\nBe sure to run the unit test with the `--allow-natives-syntax` switch. The\n`--allow-natives-syntax` switch allows us to test that when we parse we are\ncreating objects that have JavaScript \"fast properties.\"\n\n## Parsers and Serializers\n\n**TODO** Here you need your incremental and whole parser interface with a simple\nexample. Would be an over view. In the next section we get into the weeds.\n\n## Packet Definition Language\n\nTo test our examples below we are going to use the following function.\n\n```javascript\nconst fs = require('fs')\nconst path = require('path')\n\nconst packetize = require('packet/packetize')\nconst SyncParser = require('packet/sync/parser')\nconst SyncSerializer = require('packet/sync/serializer')\n\n// Generate a packet parser and serializer mechnaics module.\n\n// Please ignore all the synchronous file operations. They are for testing\n// only. You will not generate packet parsers at runtime. You will use the\n// `packetizer` executable to generate your packet parser and serializer\n// mechanics modules and ship them.\n\n//\nfunction compile (name, definition, options) {\n    const source = packetize(definition, options)\n    const file = path.resolve(__dirname, '..', 'readme', name + '.js')\n    fs.writeFileSync(file, source)\n    return file\n}\n\n// Load mechanics and run a synchronous serialize and parse.\n\n// This looks more like production code, except for the part where you call\n// our for-the-sake-of-testing runtime compile.\n\n//\nfunction test (name, definition, object, expected, options = {}) {\n    const moduleName = compile(name, definition, options)\n\n    const mechanics = require(moduleName)\n\n    const serializer = new SyncSerializer(mechanics)\n    const buffer = serializer.serialize('object', object)\n\n    okay(buffer.toJSON().data, expected, `${name} correctly serialized`)\n\n    const parser = new SyncParser(mechanics)\n    const actual = parser.parse('object', buffer)\n\n    okay(actual, object, `${name} correctly parsed`)\n}\n```\n\n### Whole Integers\n\nIntegers are specified as multiples of 8 bits. For integers less than 48 bits\nyou can define the integer field as a JavaScript `typeof === 'number'`. If the\ninteger is larger than 48 bits you should define the field as JavaScript\n`BigInt`.\n\n**Mnemonic**: A count of bits to serialize or parse defined as a JavaScript\n`'number'` or `BigInt` since that's the type it will produce. We use a count of\nbits as opposed to a count of bytes so that our code looks consistent when when\nwe define bit packed integers which need to be defined in bits and not bytes.\n\nIn the following definition `value` is a 16-bit `'number'` with valid integer\nvalues from 0 to 65,535. Serializes objects with `'number'` fields must provide\na `'number'` type value and the number must be in range. No type or range\nchecking is performed.\n\n```javascript\nconst definition = {\n    object: {\n        value: 16\n    }\n}\n\nconst object = {\n    value: 0xabcd\n}\n\ntest('whole-integer', definition, object, [ 0xab, 0xcd ])\n```\n\nIntegers smaller than 48 bits _should_ be defined using a `'number'` to specify\nthe count of bits. Integers larger than 48 bits _must_ be defined as `BigInt`.\n\nIn the following definition `value` is a 64-bit `BigInt` with a valid integer\nvalues from 0 to 18,446,744,073,709,551,616. Serializes objects with `BigInt`\nfields must provide a `BigInt` type value and the number must be in range. No\ntype or range checking is performed.\n\n**Mnemonic**: The `n` suffix is the same suffix used to indicate a `BigInt`\nliteral in JavaScript.\n\n```javascript\nconst definition = {\n    object: {\n        value: 64n\n    }\n}\n\nconst object = {\n    value: 0xfedcba9876543210n\n}\n\ntest('whole-integer-64', definition, object, [\n    0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10\n])\n```\n\n### Negative Integers\n\nIntegers with negative values are generally represented as two's compliment\nintegers on most machines. To parse and serialize as two's compliment you\nprecede the bit length of an integer field with a `-` negative symbol.\n\nIn the following definition `value` is a two's compliment 16-bit integer with\nvalid values from -32768 to 32767. Two's compliment is a binary representation\nof negative numbers.\n\n**Mnemonic**: Negative symbol to indicate a potentially negative value.\n\n```javascript\nconst definition = {\n    object: {\n        value: -16\n    }\n}\n\nconst object = {\n    value: -1\n}\n\ntest('negative-integer', definition, object, [ 0xff, 0xff ])\n```\n\nAs with whole integers, you _must_ define an integer larger than 32-bits as a\n`BitInt`.\n\nIn the following definition `value` is a two's compliment 16-bit integer with\nvalid values from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807.\n\n```javascript\nconst definition = {\n    object: {\n        value: -64n\n    }\n}\n\nconst object = {\n    value: -1n\n}\n\ntest('negative-integer-64', definition, object, [\n    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff\n])\n```\n\n### Endianness\n\nBy default, all numbers are written out big-endian, where the bytes are written\nfrom the most significant to the least significant. The same order in which\nyou'd specify the value as a hexadecimal literal in JavaScript.\n\nLittle-endian means that the bytes are serialized from the least significant\nbyte to the most significant byte. Note that this is the order of _bytes_ and\nnot _bits_. This would be the case if you wrote an integer out directly to a\nfile from a C program on an Intel machine.\n\nTo parse and serialize an integer as little-endian you precede the bit length of\nan integer field with a `~` tilde.\n\nIn the following definition `value` is a 16-bit `number` field with valid\ninteger values from 0 to 65,535. A value of `0xabcd` would be serialized in\nlittle-endian order as `[ 0xcd, 0xab ]`.\n\n**Mnemonic**: The tilde is curvy and we're mixing things up, turning them\naround, vice-versa like.\n\n```javascript\nconst definition = {\n    object: {\n        value: ~16\n    }\n}\n\nconst object = {\n    value: 0xabcd\n}\n\ntest('little-endian', definition, object, [ 0xcd, 0xab ])\n```\n\nIf you want a little-endian negative number combine both `-` and `~`. You can\ncombine the `-` and `~` as `-~` and `~-`.\n\nIn the following definition both `first` and `second` are 16-bit `number` fields\nwith valid integer values from -32768 to 32767. A value of `-0x2` would be\nconverted to the twos compliment representation 0xfffe and serialized in\nlittle-endian as `[ 0xfe, 0xff ]`.\n\n```javascript\nconst definition = {\n    object: {\n        first: ~-16,\n        second: -~16\n    }\n}\n\nconst object = {\n    first: -2,\n    second: -2\n}\n\ntest('little-endian-twos-compliment', definition, object, [\n    0xfe, 0xff, 0xfe, 0xff\n])\n```\n\nJust as with the default big-endian integer fields, little-endian integer fields\ngreater than 32-bits must be specified as `BigInt` fields using a `'bigint'`\nliteral.\n\n```javascript\nconst definition = {\n    object: {\n        value: ~64n,\n    }\n}\n\nconst object = {\n    value: 0xfedcba9876543210n\n}\n\ntest('little-endian-64', definition, object, [\n    0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe\n])\n```\n\nSimilarly, for little-endian signed number fields greater than 32-bits you\ncombine the `-` and `~` with a `BigInt` literal. You can combine the `-` and `~`\nas `-~` and `~-`.\n\n```javascript\nconst definition = {\n    object: {\n        first: ~-64n,\n        second: -~64n\n    }\n}\n\nconst object = {\n    first: -2n,\n    second: -2n\n}\n\ntest('little-endian-twos-compliment-64', definition, object, [\n    0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // first\n    0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff  // second\n])\n```\n\n### Nested Structures\n\nYou can nest structures arbitrarily. The nesting of structures does not effect\nthe serialization or parsing, it will still be a series bytes in the stream, but\nit may help the structure your programs group values in a meaningful way.\n\n```javascript\nconst definition = {\n    object: {\n        header: {\n            type: 8,\n            length: 16\n        },\n        options: {\n            encrypted: 8,\n            checksum: 32\n        }\n    }\n}\n\nconst object = {\n    header: {\n        type: 1,\n        length: 64\n    },\n    options: {\n        encrypted: 0,\n        checksum: 0xaaaaaaaa\n    }\n}\n\ntest('nested-structures', definition, object, [\n    0x01,                   // header.type\n    0x00, 0x40,             // header.length\n    0x00,                   // options.encrypted\n    0xaa, 0xaa, 0xaa, 0xaa  // options.checksum\n])\n```\n\nYou can define a nested structure and then elide it by defining the structure\nwith a name that begins with a `_`. This is silly so don't do it. It is\navailable merely to be consistent with packet integers, accumulators and limits.\n\n**TODO** Short example.\n\n### Packed Integers\n\nPacked integers are expressed as nested structures grouped in an `Array`\nfollowed by an integer definition of the packed integer size. The byte lengths\nin the packed integer must sum to the size of the packed integer.\n\nPacked integer fields are always big-endian and cannot be made little endian.\nPacked integer fields can be made two's compliment by preceding the field bit\nlength with a `-` negative symbol just like whole integers.\n\nA packed 32-bit integer with a single two's compliment (potentially negative)\nvalue named `volume`.\n\nThe bit length values of the packed values sum to 32. Note that we consider\n`volume` to be 10 bits and not -10 bits in this summation of packed field\nvalues. The `-` is used to indicate a two's compliment integer field.\n\n```javascript\nconst definition = {\n    object: {\n        header: [{\n            type: 7,\n            encrypted: 1,\n            volume: -10,\n            length: 14\n        }, 32 ]\n    }\n}\n\nconst object = {\n    header: {\n        type: 3,\n        encrypted: 1,\n        volume: -1,\n        length: 1024\n    }\n}\n\ntest('packed-integer', definition, object, [\n    0x7,    // type and encrypted packed into ne byte\n    0xff,   // eight bytes of volume\n    0xc4,   // two types of volume and top of length\n    0x0     // rest of length\n])\n```\n\nThe packed integer will be serialized as big-endian by default. You can specify\nthat the packed integer is serialized as little-endian by proceeding the bit\nlength with a `~` tilde.\n\n```javascript\nconst definition = {\n    object: {\n        header: [{\n            type: 7,\n            encrypted: 1,\n            volume: -10,\n            length: 14\n        }, ~32 ]\n    }\n}\n\nconst object = {\n    header: {\n        type: 3,\n        encrypted: 1,\n        volume: -1,\n        length: 1024\n    }\n}\n\ntest('packed-integer-little-endian', definition, object, [\n    0x0,    // rest of length\n    0xc4,   // two types of volume and top of length\n    0xff,   // eight bytes of volume\n    0x7     // type and encrypted packed into ne byte\n])\n```\n\nYou many not want the nested structure of the packed header to appear in your\nparsed object. You can elide the nested structure by giving it a name that\nbegins with an `_`.\n\n**TODO** Example.\n\nElide only works for packet integers, accumulators, limits and structures. If\nyou name a field of any other type it will be defined with the underscore.\n\n**TODO** Example.\n\n### Literals\n\nLiterals are bytes written on serialization that are constant and not based on a\nvalue in the serialized structure.\n\nYou define a constant with an array that contains a `String` that describes the\nconstant value in hexadecimal digits. There should be two hexadecimal digits for\nevery byte. The length of the field is determined by the number of bytes\nnecessary to hold the value.\n\n**Mnemonic**: A string literal reminds us this is literal and stands out because\nit is not numeric. Hexadecimal helps distinguish these constant values from\nfield sizes and other aspects of the definition language expressed with numbers.\n\n```javascript\nconst definition = {\n    object: {\n        constant: [ 'fc' ],\n        value: 16\n    }\n}\n\nconst object = {\n    value: 0xabcd\n}\n\ntest('constant', definition, object, [\n    0xfc, 0xab, 0xcd\n])\n```\n\nGenerated parsers skip the constant bytes and do not validate the parsed value.\nIf you want to perform validation you can define the field as an integer field\nand inspect the parsed field value. This means you will also have to\nconsistently set the serialized field value on your own.\n\nA literal is ignored on serialization if it exists. It is not set in the\ngenerated structure on parsing. In our example the `contsant` property of the\nobject is not generated on parse.\n\n**TODO** How about an explicit example that doesn't require as much exposition\nas our `test` definition.\n\nNot much point in naming a literal, is there? The literal it will not be read\nfrom the serialized object nor will the named literal property be set in a\nparsed parsed object. What if you have multiple literals? Now you have to have\n`constant1` and `constant2`. It starts to look ugly as follows.\n\n```javascript\nconst definition = {\n    object: {\n        constant1: [ 'fc' ],\n        key: 16,\n        constant2: [ 'ab' ],\n        value: 16\n    }\n}\n\nconst object = {\n    key: 1,\n    value: 0xabcd\n}\n\ntest('constants', definition, object, [\n    0xfc, 0x0, 01,\n    0xab, 0xab, 0xcd\n])\n```\n\nYou can forgo naming a literal by defining it as padding before or after a\nfield.\n\nTo prepend a literal to a field definition in an array where the literal\ndefinition is the first element and field definition is the second. The literal\nwill be written before writing the field value and skipped when parsing the\nfield value.\n\n```javascript\nconst definition = {\n    object: {\n        key: [[ 'fc' ], 16 ],\n        value: [[ 'ab' ], 16 ]\n    }\n}\n\nconst object = {\n    key: 1,\n    value: 0xabcd\n}\n\ntest('unnamed-literals', definition, object, [\n    0xfc, 0x0, 01,\n    0xab, 0xab, 0xcd\n])\n```\n\nYou can specify an unnamed literal that follows a field. Enclose the field\ndefinition in an array with the field definition as the first element and the\nliteral definition as the second element.\n\n```javascript\nconst definition = {\n    object: {\n        value: [ 16, [ 'ea' ] ],\n    }\n}\n\nconst object = {\n    value: 0xabcd\n}\n\ntest('unnamed-literal-after', definition, object, [\n    0xab, 0xcd, 0xea\n])\n```\n\nYou can specify an unnamed literal both before and after a field. Enclose the\nfield definition in an array and define preceding literal as the first element\nand following literal as the last element.\n\nThe example above can be defined using literals around the `key` property alone.\n\n```javascript\nconst definition = {\n    object: {\n        key: [[ 'fc' ], 16, [ 'ab' ] ],\n        value: 16\n    }\n}\n\nconst object = {\n    key: 1,\n    value: 0xabcd\n}\n\ntest('unnamed-literals-before-and-after', definition, object, [\n    0xfc, 0x0, 01,\n    0xab, 0xab, 0xcd\n])\n```\n\nYou can define a literal that repeats its value. The constant value is defined\nusing an array that contains a `String` with the literal value as the first\nelement and the number of times to repeat the value as the second element.\n\n**Mnemonic**: The repeat count follows the hexadecimal definition, its relation\nto the definition is expressed by its containment in an array.\n\n```javascript\nconst definition = {\n    object: {\n        constant: [ 'beaf', 3 ],\n        value: 16\n    }\n}\n\nconst object = { value: 0xabcd }\n\ntest('literal-repeat', definition, object, [\n    0xbe, 0xaf, 0xbe, 0xaf, 0xbe, 0xaf,\n    0xab, 0xcd\n])\n```\n\nYou can express repeated literals as unnamed literals by prepending or appending\nthem to a field definition.\n\n```javascript\nconst definition = {\n    object: {\n        value: [[ 'beaf', 3 ], 16 ]\n    }\n}\n\nconst object = { value: 0xabcd }\n\ntest('unamed-literal-repeat', definition, object, [\n    0xbe, 0xaf, 0xbe, 0xaf, 0xbe, 0xaf,\n    0xab, 0xcd\n])\n```\n\nNote that a literal definition without a repeat count is the same as a literal\ndefinition with a repeat count of `1`.\n\n```javascript\nconst definition = {\n    object: {\n        explicit: [[ 'beaf', 1 ], 16 ],\n        implicit: [[ 'beaf' ], 16 ]\n    }\n}\n\nconst object = { explicit: 0xabcd, implicit: 0xabcd }\n\ntest('unamed-literal-repeat-once', definition, object, [\n    0xbe, 0xaf, 0xab, 0xcd,\n    0xbe, 0xaf, 0xab, 0xcd\n])\n```\n\nLittle endian serialization of literals seems like an unlikely use case. One\nwould imagine at a specification would specify the bytes in network byte order.\nOften times filler bytes are a repeat of a single byte so endianness doesn't\nmatter.\n\nIf you want little-endian serialization of a literal value you could simply\nreverse the bits yourself.\n\nHere we write `0xbeaf` little-endian by explicitly flipping `0xbe` and `0xaf`.\n\n```javascript\nconst definition = {\n    object: {\n        value: [[ 'afbe' ], 16 ]\n    }\n}\n\nconst object = { value: 0xabcd }\n\ntest('unamed-literal-little-endian-explicit', definition, object, [\n    0xaf, 0xbe,\n    0xab, 0xcd\n])\n```\n\nSimple enough, however...\n\nIf specify a repeat count prepended by a `~` the pattern will be written\nlittle-endian.\n\n**Mnemonic**: Use use a tilde `~` because it's squiggly and we're swirling the\nbytes around vice-versa. Same mnemonic for little-endian integer fields.\n\n```javascript\nconst definition = {\n    object: {\n        value: [[ 'beaf', ~1 ], 16 ]\n    }\n}\n\nconst object = { value: 0xabcd }\n\ntest('unamed-literal-little-endian', definition, object, [\n    0xaf, 0xbe,\n    0xab, 0xcd\n])\n```\n\nYou can repeat the little-endian serialization more than once.\n\n```javascript\nconst definition = {\n    object: {\n        value: [[ 'beaf', ~3 ], 16 ]\n    }\n}\n\nconst object = { value: 0xabcd }\n\ntest('unamed-literal-little-endian-repeat', definition, object, [\n    0xaf, 0xbe, 0xaf, 0xbe, 0xaf, 0xbe,\n    0xab, 0xcd\n])\n```\n\nUnnamed little-endian literals can be appended or prepended. Any unnamed literal\ndefinition can be appended, prepended or both.\n\n### Length-Encoded Arrays\n\nA common pattern in serialization formats is a series of repeated values\npreceded by a count of those values.\n\n**Mnemonic**: We enclose the definition in an array. The first element is an\ninteger field definition for the length. It's scalar appearance indicates that\nit does not repeat. The repeated value is enclosed in an array indicating that\nit will be the value that repeats. The ordering of the scalar followed by the\narray mirrors the binary representation of a length/count followed by repeated\nvalues.\n\n```javascript\nconst definition = {\n    object: {\n        array: [ 16, [ 8 ] ]\n    }\n}\n\nconst object = {\n    array: [ 0xaa, 0xbb, 0xcc, 0xdd ]\n}\n\ntest('length-encoded', definition, object, [\n    0x0, 0x4, 0xaa, 0xbb, 0xcc, 0xdd\n])\n```\n\nThe repeated value can be of any type including structures.\n\n```javascript\nconst definition = {\n    object: {\n        array: [ 16, [{ key: 16, value: 16 }] ]\n    }\n}\n\nconst object = {\n    array: [{ key: 0xaa, value: 0xbb }, { key: 0xcc, value: 0xdd }]\n}\n\ntest('length-encoded-structures', definition, object, [\n    0x0, 0x2,               // length encoding\n    0x0, 0xaa, 0x0, 0xbb,   // first structure\n    0x0, 0xcc, 0x0, 0xdd    // second structure\n])\n```\n\nYou can even nest length-encoded arrays inside length-encoded arrays.\n\n```javascript\nconst definition = {\n    object: {\n        array: [ 16, [[ 16, [ 8 ]]] ]\n    }\n}\n\nconst object = {\n    array: [[ 0xaa, 0xbb ], [ 0xcc, 0xdd ]]\n}\n\ntest('length-encoded-nested', definition, object, [\n    0x0, 0x2,               // length encoding\n    0x0, 0x2, 0xaa, 0xbb,   // first array length encoding and values\n    0x0, 0x2, 0xcc, 0xdd    // second array length encoding and values\n])\n```\n\nBecause pure binary data is a special case, instead of an array of `8` bit\nbites, you can specify a length encoded binary data as a `Buffer`.\n\n```javascript\nconst definition = {\n    object: {\n        array: [ 16, [ Buffer ] ]\n    }\n}\n\nconst object = {\n    array: Buffer.from([ 0xaa, 0xbb, 0xcc, 0xdd ])\n}\n\ntest('length-encoded-buffer', definition, object, [\n    0x0, 0x4, 0xaa, 0xbb, 0xcc, 0xdd\n])\n```\n\n### Inline Transforms and Assertions\n\nInline transforms are specified by wrapping a field definition in an array with\na pre-serialization function before or a post-parsing function after it or both.\nThe pre-serialization function and post-parsing function must be enclosed in an\narray.\n\nA pre-serialization transformation function takes the value from the JavaScript\nobject and returns the transformed that is then written to the stream. The\npost-parsing transformation function takes a value extracted from the stream and\nreturns the transformed value that is assigned to the JavaScript object.\n\nThe following transform will convert a hexadecimal string to an integer on\nserialization and back to a hexadecimal string on parse.\n\n**Mnemonic**: A function is obviously a function, it does something to in the\nmidst of parsing. We used functions elsewhere in the language, so we enclose\nthem in arrays, The array brackets act as parenthesis, these are parenthetical\nuser actions on the stream.\n\n```javascript\nconst definition = {\n    object: {\n        value: [[ $_ => parseInt($_, 16) ], 32, [ $_ => $_.toString(16) ]]\n    }\n}\n\nconst object = {\n    value: '89abcdef'\n}\n\ntest('transform-basic', definition, object, [\n    0x89, 0xab, 0xcd, 0xef\n])\n```\n\nWhoa, what's with the parameter names pal? `$_` violates everything I was ever\ntaught about naming variables. How would you even pronounce that?\n\nWell, once upon a time I wrote me a lot of Perl. In Perl this variable is called\n\"dollar under.\" It is the default variable for an array value when you loop\nthrough an array with `foreach`. I miss those days, so I thought I revive them.\nYou can name positional arguments anything you like, but I'll be using these\nnames to get you used to them, because they're available as named arguments as\nwell.\n\nYou can also use named arguments via object deconstruction. When you do, you\nmust specify names that are in the current namespace. The namespace will contain\nthe object properties in the current path.\n\n```javascript\nconst definition = {\n    object: {\n        value: [[ ({ value }) => parseInt(value, 16) ], 32, [ ({ value }) => value.toString(16) ]]\n    }\n}\n\nconst object = {\n    value: '89abcdef'\n}\n\ntest('transform-by-name', definition, object, [\n    0x89, 0xab, 0xcd, 0xef\n])\n```\n\nYou can also refer to the current variable using the Perl-esque \"dollar under\"\nvariable. Perl-esque variables can make your code more concise. If used\nconsistently it will still be human readable.\n\n```javascript\nconst definition = {\n    object: {\n        value: [[ ({ $_ }) => parseInt($_, 16) ], 32, [ ({ $_ }) => $_.toString(16) ]]\n    }\n}\n\nconst object = {\n    value: '89abcdef'\n}\n\ntest('transform-dollar-under', definition, object, [\n    0x89, 0xab, 0xcd, 0xef\n])\n```\n\nThere are two Perl-esque variable names `$_` for the immediate property value,\nand `$` for the root object. Any other system provided names such as `$i`,\n`$buffer`, `$start` and `$end` will begin with a `$` do distinguish them from\nuser specified names and to avoid namespace collisions.\n\n**Mnemonic**: Borrowed from Perl `foreach` loop, `$_` is the immediate property\nvalue, useful for its brevity. `$` is the root variable, the shortest special\nvariable because if you're starting from the root, you have a path ahead of you.\n\nA transform or assertion is always defined with an array with three elements. If\nyou only want to define a pre-serialization action, the last element will be an\nempty array. If you only want to define a post-parsing action, the first element\nwill be an empty array.\n\nIn the following example we do not want to perform a post-parsing action, so we\nleave the post-parsing array empty, but we do not neglect to add it.\n\n```javascript\nconst definition = {\n    object: {\n        value: [[ $_ => typeof $_ == 'string' ? parseInt($_, 16) : $_ ], 32, []]\n    }\n}\n\nconst moduleName = compile('transform-pre-only', definition)\nconst mechanics = require(moduleName)\n\n{\n    const buffer = new SyncSerializer(mechanics).serialize('object', { value: '89abcdef' })\n    const object = new SyncParser(mechanics).parse('object', buffer)\n    okay(object, { value: 0x89abcdef }, 'transform-pre-only-convert')\n}\n\n{\n    const buffer = new SyncSerializer(mechanics).serialize('object', { value: 0x89abcdef })\n    const object = new SyncParser(mechanics).parse('object', buffer)\n    okay(object, { value: 0x89abcdef }, 'transform-pre-only-no-convert')\n}\n```\n\nNamed arguments have limitations. We're using a simple regex based parser to\nextract the arguments from the function source, not a complete JavaScript\nparser. We are able to parse object destructuring, array destructuring, and\ndefault argument values of numbers, single quoted strings and double quoted\nstrings.\n\nDo not use regular expressions, interpolated strings or function calls, in your\ndefault argument assignments. You can use any valid JavaScript in your function\nbodies.\n\nIn the following definition we've added an unused named variable that is default\nassigned a value extracted from a literal string by a regular expression. The\nright curly brace in the literal string won't confuse our simple argument\nparser, but the right curly brace in the regular expression will.\n\n```javascript\nconst definition = {\n    object: {\n        value: [[\n            ({ $_, packet: { extra = /^([}])/.exec(\"}\")[1] } }) => parseInt($_, 16)\n        ], 32, [\n            ({ $_ }) => $_.toString(16)\n        ]]\n    }\n}\n\nconst _definition = {\n    object: {\n        value: [[ $_ => typeof $_ == 'string' ? parseInt($_, 16) : $_ ], 32, []]\n    }\n}\n\ntry {\n    packetize(definition)\n} catch (error) {\n    okay(error instanceof SyntaxError, 'unable to parse regex')\n}\n```\n\nAs you can see it's an unlikely use case. Basically, if you find yourself\nwriting logic in your named arguments, stop and place it in a function in a\nmodule and invoke that module function from the inline function.\n\nWe'll continue to use `$_` and `$` in positional argument examples so we can all\nget used to them.\n\nThe first argument to a transformation function with positional arguments is the\ntransformed value, the second argument is the root object being transformed.\n\nThe following WebSockets inspired example xors a value with a `mask` property in\nthe packet.\n\n```javascript\nconst definition = {\n    object: {\n        mask: 16,\n        value: [[ ($_, $) => $_ ^ $.mask ], 16, [ ($_, $) => $_ ^ $.mask ]]\n    }\n}\n\nconst object = {\n    mask: 0xaaaa,\n    value: 0xabcd\n}\n\ntest('transform-mask-positional', definition, object, [\n    0xaa, 0xaa, 0x1, 0x67\n])\n```\n\nThis can be expressed using named arguments. Note how we can order the arguments\nany way we like.\n\n```javascript\nconst definition = {\n    object: {\n        mask: 16,\n        value: [[ ({ $, $_ }) => $_ ^ $.mask ], 16, [ ({ $_, $ }) => $_ ^ $.mask ]]\n    }\n}\n\nconst object = {\n    mask: 0xaaaa,\n    value: 0xabcd\n}\n\ntest('transform-mask-named', definition, object, [\n    0xaa, 0xaa, 0x1, 0x67\n])\n```\n\nYou can also name the names of the object properties in the current path. Again,\nnote that the order of names does not matter with named arguments.\n\n```javascript\nconst definition = {\n    object: {\n        mask: 16,\n        value: [[\n            ({ object, value }) => value ^ object.mask\n        ], 16, [\n            ({ value, object }) => value ^ object.mask\n        ]]\n    }\n}\n\nconst object = {\n    mask: 0xaaaa,\n    value: 0xabcd\n}\n\ntest('transform-mask-long-named', definition, object, [\n    0xaa, 0xaa, 0x1, 0x67\n])\n```\n\n(Not to self: Seems like it might also be useful to be able to reference the\ncurrent object in a loop, which could be `$0` for the current object, `$1` for a\nparent. This would be simpler than passing in the indices, but that would be\nsimple enough, just give them the already existing `$i`. Heh, no make them\nsuffer.)\n\nThe third argument passed to a transformation function is an array of indices\nindicating the index of each array in the path to the object. **TODO** Move\nfixed arrays above.\n\n```javascript\nconst definition = {\n    object: {\n        array: [ 16, [{\n            mask: 16,\n            value: [[\n                ($_, $, $i) => $_ ^ $.array[$i[0]].mask\n            ], 16, [\n                ($_, $, $i) => $_ ^ $.array[$i[0]].mask\n            ]]\n        }]]\n    }\n}\n\nconst object = {\n    array: [{\n        mask: 0xaaaa, value: 0xabcd\n    }, {\n        mask: 0xffff, value: 0x1234\n    }]\n}\n\ntest('transform-mask-array-positional', definition, object, [\n    0x0, 0x2,                   // length encoded count of elements\n    0xaa, 0xaa, 0x1, 0x67,      // first element\n    0xff, 0xff, 0xed, 0xcb      // second element\n])\n```\n\nWe can use named arguments as well.\n\n```javascript\nconst definition = {\n    object: {\n        array: [ 16, [{\n            mask: 16,\n            value: [[\n                ({ $_, $, $i }) => $_ ^ $.array[$i[0]].mask\n            ], 16, [\n                ({ $_, $, $i }) => $_ ^ $.array[$i[0]].mask\n            ]]\n        }]]\n    }\n}\n\nconst object = {\n    array: [{\n        mask: 0xaaaa, value: 0xabcd\n    }, {\n        mask: 0xffff, value: 0x1234\n    }]\n}\n\ntest('transform-mask-array-named', definition, object, [\n    0x0, 0x2,                   // length encoded count of elements\n    0xaa, 0xaa, 0x1, 0x67,      // first element\n    0xff, 0xff, 0xed, 0xcb      // second element\n])\n```\n\nWe can also use the names of the object properties in the current path. The `$i`\narray variable of is a special system property and it therefore retains its\ndollar sign prepended name.\n\n```javascript\nconst definition = {\n    object: {\n        array: [ 16, [{\n            mask: 16,\n            value: [[\n                ({ value, object, $i }) => value ^ object.array[$i[0]].mask\n            ], 16, [\n                ({ value, object, $i }) => value ^ object.array[$i[0]].mask\n            ]]\n        }]]\n    }\n}\n\nconst object = {\n    array: [{\n        mask: 0xaaaa, value: 0xabcd\n    }, {\n        mask: 0xffff, value: 0x1234\n    }]\n}\n\ntest('transform-mask-array-full-named', definition, object, [\n    0x0, 0x2,                   // length encoded count of elements\n    0xaa, 0xaa, 0x1, 0x67,      // first element\n    0xff, 0xff, 0xed, 0xcb      // second element\n])\n```\n\nIf your pre-serialization function and post-parsing function are the same you\ncan specify it once and use it for both serialization and parsing by surrounding\nit with an additional array.\n\n```javascript\nconst definition = {\n    object: {\n        mask: 16,\n        value: [[[ ($_, $) => $_ ^ $.mask ]], 16 ]\n    }\n}\n\nconst object = {\n    mask: 0xaaaa, value: 0xabcd\n}\n\ntest('transform-mask-same', definition, object, [\n    0xaa, 0xaa, 0x1, 0x67\n])\n```\n\nNote that the above functions can also be defined using `function` syntax. Arrow\nfunctions are generally more concise, however.\n\n```javascript\nconst definition = {\n    object: {\n        mask: 16,\n        value: [[[ function ({ value, object }) {\n            return value ^ object.mask\n        } ]], 16 ]\n    }\n}\n\nconst object = {\n    mask: 0xaaaa, value: 0xabcd\n}\n\ntest('transform-mask-function-syntax', definition, object, [\n    0xaa, 0xaa, 0x1, 0x67\n])\n```\n\n### Fixed Length Arrays\n\nFixed length arrays are arrays of a fixed length. They are specified by an array\ncontaining the numeric length of the array.\n\n**Mnemonic**: Like a length encoded definition the element definition is placed\ninside an array because it is the array element. Like a length encoded\ndefinition the length of the array precedes the element definition. It is the\nlength of the array enclosed in an array like C array declaration.\n\n```javascript\nconst definition = {\n    object: {\n        fixed: [[ 2 ], [ 16 ]]\n    }\n}\n\nconst object = {\n    fixed: [ 0xabcd, 0xdcba ]\n}\n\ntest('fixed', definition, object, [\n    0xab, 0xcd, 0xdc, 0xba\n])\n```\n\nCalculated length arrays are fixed length arrays where the fixed length is\nspecified by function. The length is, therefore, not fixed at all. It is\ncalculated.\n\nIn the following example we have a length encoding that is in a header and there\nis a field between the length encoding and the array so we can't use a\nlength-encoded array definition. We use a calculated length that references the\nheader's length field.\n\n**Mnemonic** Same as fixed length arrays replacing the fixed length with a\nfunction indicating that the function will calculate the length.\n\n```javascript\nconst definition = {\n    object: {\n        header: {\n            length: 16,\n            type: 8\n        },\n        array: [[ $ => $.header.length ], [ 16 ]]\n    }\n}\n\nconst object = {\n    header: {\n        length: 2,\n        type: 1\n    },\n    array: [ 0xabcd, 0xdcba ]\n}\n\ntest('fixed-calculated', definition, object, [\n    0x0, 0x2,               // header.length\n    0x1,                    // header.type\n    0xab, 0xcd, 0xdc, 0xba\n])\n```\n\n### Requiring Modules\n\nThe functions in our packet parser may depend on external libraries. We can\n\n```javascript\nconst definition = {\n    object: {\n        value: [[ value => ip.toLong(value) ], 32, [ value => ip.fromLong(value) ]]\n    }\n}\n\nconst source = packetize(definition, { require: { ip: 'ip' } })\n\nconst moduleName = path.resolve(__dirname, 'require.js')\nfs.writeFileSync(moduleName, source)\n\nconst mechanics = require(moduleName)\n\nconst object = { value: '127.0.0.1' }\n\nconst buffer = new SyncSerializer(mechanics).serialize('object', object)\n\nokay(buffer.toJSON().data, [\n    127, 0, 0, 1\n], 'require serialized')\n\nconst parsed = new SyncParser(mechanics).parse('object', buffer)\nokay(parsed, object, 'require parsed')\n```\n\nWhen can also use modules local to the current project using relative paths, but\nwe face a problem; we're not going to ship language definition with our\ncompleted project, we're going to ship the generated software. Therefore,\nrelative must be relative to the generated file. Your relative paths much be\nrelative to the output directory... (eh, whatever. Maybe I can fix that up for\nyou.)\n\n```javascript\n{\n    ; ({\n        packet: {\n            value: [[ $value => ip.toLong($value) ], 32, [ $value => ip.fromLong($value) ]]\n        }\n    }, {\n        require: { ip: '../ip' }\n    })\n}\n```\n\n### Assertions\n\n**TODO** Needs examples of failed assertions.\n\nWe can also perform inline assertions. You specify an assertion the same way you\nspecify a transformation. You wrap your definition in an array.\nA pre-serialization assertion is a function within an array in the element\nbefore the definition. A post-parsing assertions is a function within an array\nin the element after the definition.\n\nWhen performing inline assertions, we are not transforming a value, we're simply\nchecking it's validity and raising an exception if a value is invalid. You could\nuse a transformation to do this, but you would end up returning the value as is.\n\nWith an assertion function the return value is ignored. It is not used as the\nserialization or assignment value.\n\nTo declare an assertion function you assign a default value of `0` or `null` to\nthe immediate property argument.\n\nIn the following definition we use a `0` default value for the immediate\nproperty argument which indicates that the value and should not be used for\nserialization for the pre-serialization function nor assignment for the\npost-parsing function.\n\n```javascript\nconst definition = {\n    object: {\n        value: [[\n            ($_ = 0) => assert($_ < 1000, 'excedes max value')\n        ], 16, [\n            ($_ = 0) => assert($_ < 1000, 'excedes max value')\n        ]]\n    }\n}\nconst object = {\n    value: 1\n}\ntest('assertion', definition, object, [\n    0x0, 0x1\n], { require: { assert: 'assert' } })\n```\n\n(I assume I'll implement this in this way:) The exception will propagate to the\nAPI caller so that you can catch it in your code and cancel the serialization or\nparse. (However, if I do wrap the assertion in a try/catch and rethrow it\nsomehow, then the following example is moot.\n\nIf you where to use a transform, you would have to return the value and your\ndefinition would be more verbose.\n\n```javascript\nconst definition = {\n    object: {\n        value: [[\n            $_ => {\n                assert($_ < 1000, 'excedes max value')\n                return $_\n            }\n        ], 16, [\n            $_ => {\n                assert($_ < 1000, 'execdes max value')\n                return $_\n            }\n        ]]\n    }\n}\nconst object = {\n    value: 1\n}\ntest('assertion-not-assertion', definition, object, [\n    0x0, 0x1\n], { require: { assert: 'assert' } })\n```\n\nYou can use the name function for both pre-serialization and post-parsing by\nsurrounding the function in an additional array.\n\n```javascript\nconst definition = {\n    object: {\n        value: [[[ ($_ = 0) => assert($_ < 1000, 'excedes max value') ]], 16 ]\n    }\n}\nconst object = {\n    value: 1\n}\ntest('assertion-mirrored', definition, object, [\n    0x0, 0x1\n], { require: { assert: 'assert' } })\n```\n\nYou can use named arguments to declare an assertion function.\n\n```javascript\nconst definition = {\n    object: {\n        value: [[[ ({ $_ = 0 }) => assert($_ < 1000, 'excedes max value') ]], 16 ]\n    }\n}\nconst object = {\n    value: 1\n}\ntest('assertion-named', definition, object, [\n    0x0, 0x1\n], { require: { assert: 'assert' } })\n```\n\n### Assertion and Transformation Arguments\n\nYou can pass arguments to assertions and transforms. Any value in the array that\nfollows the function that is not itself a `function` is considered an argument\nto the function. The arguments are passed in the order in which they are\nspecified preceding the immediate property value.\n\nIn the following definition the function is followed by a `number` argument\nwhich is passed as the first parameter to the function in serialize or parser.\n\n```javascript\nconst definition = {\n    object: {\n        value: [[[ (max, $_ = 0) => assert($_ < max, `value excedes ${max}`), 1024 ]], 16 ]\n    }\n}\nconst object = {\n    value: 1\n}\ntest('assertion-parameter', definition, object, [\n    0x0, 0x1\n], { require: { assert: 'assert' } })\n```\n\nThis is useful when defining a function that you use more than once in your\ndefinition.\n\n```javascript\nconst max = (max, $_ = 0) => assert($_ < max, `value excedes ${max}`)\n\nconst definition = {\n    object: {\n        length: [[[ max, 1024 ]], 16 ],\n        type: [[[ max, 12 ]], 8 ]\n    }\n}\nconst object = {\n    length: 256,\n    type: 3\n}\ntest('assertion-parameter-reuse', definition, object, [\n    0x1, 0x0, 0x3\n], { require: { assert: 'assert' } })\n```\n\nWhen using named arguments, the argument values are assigned to the named\nparameters preceding the first variable that is defined in the current scope.\nThat is, the first occurrence of a variable name that is either the name of a\nproperty in the current path or a system name beginning with `$` dollar sign.\n\nIn the following definition the first argument to the `max` function will be\nassigned to the `max` named argument. The positional argument mapping stops at\nthe `$path` parameter since it is a system parameter beginning with `$` dollar\nsign. The `'oops'` parameter of the `max` function call for the `type` property\nwill be ignored.\n\n```javascript\nconst max = ({ max, $path, $_ = 0 }) => assert($_ < max, `${$path.pop()} excedes ${max}`)\n\nconst definition = {\n    object: {\n        length: [[[ max, 1024 ]], 16 ],\n        type: [[[ max, 12, 'oops' ]], 8 ]\n    }\n}\nconst object = {\n    length: 256,\n    type: 3\n}\ntest('assertion-parameter-named-reuse', definition, object, [\n    0x1, 0x0, 0x3\n], { require: { assert: 'assert' } })\n```\n\n### Terminated Arrays\n\nIn the following example, we terminate the array when we encounter a `0` value.\nThe `0` is not included in the array result.\n\n```javascript\n{\n    const definition = {\n        object: {\n            array: [[ 8 ], 0x0 ]\n        }\n    }\n    const object = {\n        array: [ 0xab, 0xcd ]\n    }\n    test('terminated', definition, object, [\n        0xab, 0xcd, 0x0\n    ])\n}\n```\n\n#### Multi-byte Terminators\n\nYou can specify multi-byte terminators by specifying the multi-byte terminator\nbyte by byte in the end of the definition array.\n\nIn the following example, we terminate the array when we encounter a `0xa` value\nfollowed by a `0xd` value, carriage return followed by line feed.\n\nThe `0` is not included in the array result.\n\n```javascript\nconst definition = {\n    object: {\n        array: [[ 8 ], 0xd, 0xa ]\n    }\n}\nconst object = {\n    array: [ 0xab, 0xcd ]\n}\ntest('terminated-multibyte', definition, object, [\n    0xab, 0xcd, 0xd, 0xa\n])\n```\n\n### String Value Maps\n\n**TODO**: Need first draft.\n\n```javascript\n{\n    const definition = {\n        object: {\n            header: [{ type: [ 8, [ 'off', 'on' ] ] }, 8 ]\n        }\n    }\n    const object = {\n        header: {\n            type: 'on'\n        }\n    }\n    test('string-value-map', definition, object, [\n        0x1\n    ])\n}\n```\n\n```javascript\n{\n    const description = {\n        packet: {\n            type: [ 8, { 0: 'off', 1: 'on', null: 'unknown' } ]\n        }\n    }\n}\n```\n\n### Floating Point Values\n\nPacket supports serializing and parsing IEEE754 floating point numbers. This is\nthe representation common to C.\n\nA floating point number is is specified by specifying the value as a floating\nthe point number as `number` with the bit size repeated in the decimal digits of\nthe number.\n\n**TODO** Values of `1.1` and `-1.5` are not serializing and restoring correctly.\nI can't remember if this is expected.\n\n```javascript\nconst definition = {\n    object: {\n        doubled: 64.64,\n        float: 32.32\n    }\n}\nconst object = {\n    doubled: 1.2,\n    float: -1.5\n}\ntest('float', definition, object, [\n    0x3f, 0xf3, 0x33, 0x33,\n    0x33, 0x33, 0x33, 0x33,\n    0xbf, 0xc0, 0x0, 0x0\n])\n```\n\nThere are only two sizes of floating point number available, 64-bit and 32-bit.\nThese are based on the IEEE 754 standard. As of 2008, the standard defines a\n[128-bit quad precision floating\npoint](https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format)\nbut the JavaScript `number` is itself a 64-bit IEEE 754 double-precision float,\nso we'd have to introduce one of the big decimal libraries from NPM to support\nit, so it's probably best you sort out a solution for your application using\ninline functions, maybe serializing to a byte array or `BigInt`. If you\nencounter at 128-bit number in the wild, I'd be curious. Please let me know.\n\n### Conditionals\n\n**TODO**: Need first draft.\n\nBasic conditionals are expressed as an array of boolean functions paired with\nfield definitions. The functions and definitions repeat creating an if/else if\nconditional. The array can end with a field definition that acts as the `else`\ncondition.\n\nIf the function has positional arguments, the function is called with the root\nobject, followed by an array of indices into any arrays the current path,\nfollowed by an array of names of the properties in the current path.\n\nIn the following definition the bit size of value is 8 bits of the `type`\nproperty is `1`, 16 bits if the type property is `2`, 24 bits if the `type`\nproperty `3` and `32` bits for any other value of `type`.\n\n```javascript\n{\n    const definition = {\n        object: {\n            type: 8,\n            value: [\n                $ => $.type == 1, 8,\n                $ => $.type == 2, 16,\n                $ => $.type == 3, 24,\n                true, 32\n            ]\n        }\n    }\n    const object = {\n        type: 2,\n        value: 1\n    }\n    test('conditional', definition, object, [\n        0x2,\n        0x0, 0x1\n    ])\n}\n```\n\nYou can use conditionals in bit-packed integers as well.\n\n```javascript\n{\n    const definition = {\n        object: {\n            header: [{\n                type: 4,\n                value: [\n                    $ => $.header.type == 1, 28,\n                    $ => $.header.type == 2, [{ first: 4, second: 24 }, 28 ],\n                    $ => $.header.type == 3, [{ first: 14, second: 14 }, 28 ],\n                    true, [[ 24, 'ffffff' ], 4 ]\n                ]\n            }, 32 ]\n        }\n    }\n    const object = {\n        header: {\n            type: 2,\n            value: { first: 0xf, second: 0x1 }\n        }\n    }\n    test('conditional-packed', definition, object, [\n        0x2f, 0x0, 0x0, 0x1\n    ])\n}\n```\n\n### Switch Conditionals\n\n**TODO**: Need first draft. Also, example is wrong.\n\n```javascript\nconst definition = {\n    object: {\n        type: 8,\n        value: [\n            ($) => $.type, [\n                { $_: 1 },          8,\n                { $_: [ 2, 3 ] },   16,\n                { $_: [] },         32\n            ]\n        ]\n    }\n}\nconst object = {\n    type: 2,\n    value: 1\n}\ntest('switch', definition, object, [\n    0x2, 0x0, 0x1\n])\n```\n\n### References to Parietals\n\n**TODO**: First draft done.\n\nIf you have a complicated type that requires a complicated definition that is\ntedious to repeat, you can reference that definition by name.\n\nReferences can be used as types and can also be used as length encoding lengths\nif they resolve to an integer type. If you create a type that is only used by\nreference that you do not want available as a packet, prepend and underscore and\nit will not be returned as a packet type.\n\n**Mnemonic**: A string name to name the referenced type.\n\nIn the following a definition an encoded integer is defined as a partial that\nwill not be presented as a packet due to the `_` prefix to the name. It is\nreferenced by the `series` property as a type and used for the length encoding\nof the `data` property.\n\n```javascript\nconst definition = {\n    $encodedInteger: [\n        [\n            value => value <= 0x7f, 8,\n            value => value <= 0x3fff, [ 16, [ 0x80, 7 ], [ 0x0, 7 ] ],\n            value => value <= 0x1fffff, [ 24, [ 0x80, 7 ], [ 0x80, 7 ], [ 0x0, 7 ] ],\n            true, [ 32, [ 0x80, 7 ], [ 0x80, 7 ], [ 0x80, 7 ], [ 0x0, 7 ] ]\n        ],\n        [ 8,\n            sip => (sip & 0x80) == 0, 8,\n            true, [ 8,\n                sip => (sip & 0x80) == 0, [ 16, [ 0x80, 7 ], [ 0x0, 7 ] ],\n                true, [ 8,\n                    sip => (sip & 0x80) == 0, [ 24, [ 0x80, 7 ], [ 0x80, 7 ], [ 0x0, 7 ] ],\n                    true, [ 32, [ 0x80, 7 ], [ 0x80, 7 ], [ 0x80, 7 ], [ 0x0, 7 ] ]\n                ]\n            ]\n        ]\n    ],\n    object: {\n        value: '$encodedInteger',\n        // array: [ '$encodedInteger', [ 8 ] ] ~ I haven't done this, requires using conditionals in length encoded arrays or calculated arrays.\n    }\n}\nconst object = {\n    value: 1,\n      array: [ 1 ]\n}\ntest('partial', definition, object, [\n    0x1 // , 0x1, 0x1\n])\n```\n\n### Checksums and Running Calculations\n\nSome protocols perform checksums on the body of message. Others require tracking\nthe remaining bytes in a message based on a length property in a header and\nmaking decisions about the contents of the message based on the bytes remaining.\n\nTo perform running calculations like buffers and remaining bytes we can use\naccumulators, lexically scoped object variables that can be used to store the\nstate of a running calculation.\n\nThe following definition creates an MD5 checksum of the body of a packet and\nstores the result in a checksum property that follows the body of the message.\n\n```javascript\n{\n    const definition = {\n        object: [{ hash: () => crypto.createHash('md5') }, {\n            body: [[[\n                ({ $buffer, $start, $end, hash }) => hash.update($buffer.slice($start, $end))\n            ]], {\n                number: 32,\n                data: [[ 8 ], 0x0 ]\n            }],\n            checksum: [[\n                ({ $_, hash }) => $_ = hash.digest()\n            ], [[ 16 ], [ Buffer ]], [\n                ({ checksum = 0, hash }) => {\n                    assert.deepEqual(hash.digest().toJSON(), checksum.toJSON())\n                }\n            ]]\n        }]\n    }\n    const object = {\n        body: {\n            number: 1,\n            data: [ 0x41, 0x42, 0x43 ]\n        },\n        checksum: Buffer.from([ 0xc9, 0xd0, 0x87, 0xbd, 0x2f, 0x8f, 0x4a, 0x33, 0xd4, 0xeb, 0x2d, 0xe4, 0x47, 0xc0, 0x40, 0x28 ])\n    }\n    test('checksum', definition, object, [\n        0x0, 0x0, 0x0, 0x1,\n        0x41, 0x42, 0x43, 0x0,\n        0xc9, 0xd0, 0x87, 0xbd,\n        0x2f, 0x8f, 0x4a, 0x33,\n        0xd4, 0xeb, 0x2d, 0xe4,\n        0x47, 0xc0, 0x40, 0x28\n    ], { require: { assert: 'assert', crypto: 'crypto' } })\n}\n```\n\nHere we also introduce the concept of buffer inlines. These are inlines that\noperate not on the serialized or parsed value, but instead on the underlying\nbuffer. In the above example the `hash.update()` inline is not called once for\neach property in the `body`, it is called for each buffer chunk that contains\nthe binary data for the `body`.\n\nUnlike ordinary inline functions, a buffer inline is not called prior to\nserialization. Buffer inlines are called as late as possible to process as much\nof the buffer continuously as possible. In the previous example, the\n`hash.update()` inline is applied to the binary data that defines the entire\n`body` which it encapsulates.\n\nWe use nested structures to group.\n\n**TODO**: Simpler calculation example to start. Calculation is important because\nit will allow us to talk about the difference between `sizeof`,\n`offsetof`.\n\n**TODO**: Come back and implement this by finding a way to extract sizeof and\noffset of. Punting because I don't really know what inspired this example or\nwhat it is supposed to illustrate.\n\n```javascript\nconst definition = {\n    packet: [{ counter: () => [] }, {\n        header: {\n            type: 8,\n            length: [[\n                ({ $, counter }) => {\n                    return counter[0] = $sizeof.packet($) - $offsetof.packet($, 'body')\n                }\n            ], 16, [\n                ({ $_, counter }) => {\n                    return counter[0] = $_\n                }\n            ]]\n        },\n        body: [[[\n            ({ $_ = 0, $start, $end, counter }) => counter[0] -= $end - $start\n        ]], {\n            value: 32,\n            string: [[ 8 ], 0x0 ],\n            variable: [\n                ({ counter }) => counter[0] == 4, 32,\n                ({ counter }) => counter[0] == 2, 16,\n                8\n            ]\n        }],\n    }]\n}\n```\n\n### Parameters\n\n**TODO**: Need first draft, or reread this and see if it is a real first draft.\n\nAccumulators described in the preceding section also define parameters. Any\naccumulator declared on the top most field will create parameters to the\ngenerated serializes and parsers.\n\n```javascript\nconst definition = {\n    object: [{ counter: [ 0 ] }, [[[\n        ({ $start, $end, counter }) => counter[0] += $end - $start\n    ]], {\n        number: 8,\n        string: [ [ 8 ], 0x0 ]\n    }]]\n}\n// **TODO**: API call to get counter.\n```\n\nThe parameters are available as both arguments that can be passed to inline\nfunctions as well as generally available in the program scope. Be careful not to\ncareful not to hide any module declarations you've declared.\n\n```javascript\nconst definition = {\n    object: [{ encoding: 'utf8' }, {\n        string: [[\n            value => Buffer.from(value, encoding)\n        ], [ [ Buffer ], 0x0 ], [\n            value => value.toString(encoding)\n        ]]\n    }]\n}\nconst moduleName = compile('parameters', definition, {})\n// *TODO*: API call to encode string ascii or something.\n```\n\n## What's Missing\n\nA section of things that need to be written.\n\n * **TODO** Did we support packed `BigInt` integers?\n * **TODO** Absent values.\n * **TODO** Switch statements.\n * **TODO** Composition.\n * **TODO** Parse or serialize conditionals, i.e. unconditionals.\n\n## Outline\n\n * Living `README.md`.\n * Parsers and Serializers\n * Packet Definition Language\n    * Integers\n        * Negative Integers\n        * Endianness\n    * Nested Structures\n    * Packed Integers\n    * Literals\n    * Length-Encoded Arrays\n    * Inline Transforms and Assertions\n    * Fixed Length Arrays\n    * Requiring Modules\n    * Assertions\n    * Assertion and Transformation Arguments\n    * Terminated Arrays\n        * Multi-byte Terminators\n    * String Value Maps\n    * Floating Point Values\n    * Conditionals\n    * Switch Conditionals\n    * References to Partials\n    * Accumulators\n    * Parameters\n * What's Missing\n * Outline\n","readmeFilename":"README.md","gitHead":"03abea05da86ae5d9a0846345014a59ccfdf18cf","_id":"packet@1.0.0-alpha.4","_nodeVersion":"16.13.2","_npmVersion":"8.1.2","dist":{"integrity":"sha512-ZCX2kAS1IpLu8Kp1U9Q2cH5ccAc0zxrONcU0QVjbttrt+x+mQXBbMavYkOcB/byiO1S4Ybd+CzXu/uknlkkWRA==","shasum":"a3f6bba9460b1701ba1767c95a79bf7f40724ff6","tarball":"https://registry.npmjs.org/packet/-/packet-1.0.0-alpha.4.tgz","fileCount":41,"unpackedSize":562506,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiGcYTACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmrEpg/+Pudja6WeUyMCQy+DeJDPuj2k+qLx3cmxPr+fMz1XMKHgK9Cv\r\nPJ8ydaHhTLrAs5uL5R6uig54glan4NgtRuEknfgUQviN06IPvIz60E/77yWR\r\nXL9eUwNjhrE126tV5CX+OlBwiN5GdydqiaM5Xg6xV/oi0Wdjmq+TMtbz7NPp\r\nFhJ3zHqVscVpJP9t8Teudr6oHvdT9SITmWb4enP0ljdatOl8CRFT9LcluQ76\r\nHQZmleUcUBELbKzlcZgJpVXlbBsJcAvpa0+8Dm7HJM7uYoVkD2MGHppjhLhN\r\nNDPAIPXDDiqEOUJu+Z6FEA3HCb6CHHHKeUxcficMD5z6ZP932a8LzV2afCBk\r\nuQTv+LTvxtRB7zyhWVrWIxoywGdqJnzjhqIwYMS603WeS/i76rMgoFKGIX0R\r\n+wp2j2zWzYZG3yF9mtCYoPvDOqg7kbpy8KaSxg60M6iUrbzz/OCiuIfXzkRz\r\n5qxvGTKHfYsR82a7MrT0Tngs8+wrsC4Br9flD2IEFOp4ykAKkO/7HxZFi/3J\r\na2+IVkjNjptMFcgdaFLnIK3SLTQPlyxUrVQabVMjduDD2zjSfu1rPv3LuVP+\r\nPPIwC/HbinkrpqzreEMs2r4dhMBkv0SxQhu2FuXRqgz6SkE6VmKPvRg8oFxq\r\nK6+YMq+lYMV3xVNxibZ/8owA0IuikVNLgfM=\r\n=Xg2h\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDZSINxOhhwVW278lsqX8hRUlo9rATcNEA3CZllgyH59AIga9rwMXea8Z2FYpsH+tDY3btGeFgaWGpc4yfKNP4M1yw="}]},"_npmUser":{"name":"bigeasy","email":"alan@prettyrobots.com"},"directories":{},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/packet_1.0.0-alpha.4_1645856275106_0.5297186394563469"},"_hasShrinkwrap":false}},"maintainers":[{"name":"bigeasy","email":"alan@prettyrobots.com"}],"author":{"name":"Alan Gutierrez","email":"alan@prettyrobots.com"},"time":{"modified":"2022-06-23T07:04:15.347Z","created":"2011-04-10T09:53:47.906Z","0.0.1":"2011-04-10T09:53:47.906Z","0.0.2":"2011-04-10T09:53:47.906Z","0.0.3":"2012-08-17T00:53:51.868Z","0.0.4":"2012-11-06T04:51:29.315Z","0.0.6":"2013-07-03T21:54:20.781Z","0.0.7":"2015-11-28T06:53:31.407Z","1.0.0-alpha.0":"2021-03-22T15:32:48.903Z","1.0.0-alpha.1":"2021-03-22T15:33:33.090Z","1.0.0-alpha.2":"2021-03-22T15:36:04.168Z","1.0.0-alpha.3":"2021-03-22T16:36:28.613Z","1.0.0-alpha.4":"2022-02-26T06:17:55.347Z"},"description":"Pure JavaScript evented binary parsers and serializers for Node.js.","repository":{"type":"git","url":"http://github.com/bigeasy/packet.git"},"readme":"","readmeFilename":"","users":{"tunnckocore":true},"homepage":"https://github.com/bigeasy/packet","keywords":["packet","pack","binary","network","structure","async","asynchronous","javascript"],"contributors":[{"name":"J. Ryan Stinnett","email":"jryans@gmail.com"},{"name":"Ben Hockey","email":"neonstalwart@gmail.com"},{"name":"Greg Ose","email":"neonstalwart@gmail.com","url":"http://nullmethod.com/"},{"name":"Aaron Qian","email":"aq1018@gmail.com"},{"name":"Demarius Chrite","email":"chrite.demarius@gmail.com","url":"https://github.com/demarius"}],"bugs":{"url":"https://github.com/bigeasy/packet/issues"},"license":"MIT"}