{"id":20191453,"url":"https://github.com/leviroth/ppx_binary","last_synced_at":"2025-10-04T02:24:49.430Z","repository":{"id":115659305,"uuid":"110869865","full_name":"leviroth/ppx_binary","owner":"leviroth","description":"OCaml ppx rewriter for handling binary file formats","archived":false,"fork":false,"pushed_at":"2018-02-28T16:08:12.000Z","size":39,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-03T07:41:39.325Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leviroth.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-11-15T18:17:39.000Z","updated_at":"2020-05-15T04:40:43.000Z","dependencies_parsed_at":null,"dependency_job_id":"82c511a0-83f5-4332-aad0-0446d6992b17","html_url":"https://github.com/leviroth/ppx_binary","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/leviroth/ppx_binary","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leviroth%2Fppx_binary","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leviroth%2Fppx_binary/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leviroth%2Fppx_binary/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leviroth%2Fppx_binary/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leviroth","download_url":"https://codeload.github.com/leviroth/ppx_binary/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leviroth%2Fppx_binary/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278254666,"owners_count":25956644,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-04T02:00:05.491Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T03:49:10.174Z","updated_at":"2025-10-04T02:24:49.391Z","avatar_url":"https://github.com/leviroth.png","language":"OCaml","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Synopsis\n\nppx\\_binary creates binary serialization and deserialization functions for OCaml\nrecord types. It allows users to specify the exact byte size and endianness\ncorresponding to a given record field.\n\nRelative to libraries like Jane Street's\n[bin_prot](https://github.com/janestreet/bin_prot/), ppx\\_binary handles a much\nsmaller range of data types, but provides more specific control over how data is\nrepresented on disk. It is best suited for cases where the serialization format\nis determined by a pre-existing standard. For example, when working with BMP\nfiles, data must be serialized and deserialized in the exact layout expected by\nother image software. ppx\\_binary allows this format to be expressed as an OCaml\nrecord type, and automatically generates the corresponding serialization and\ndeserialization functions.\n\n\n# Usage\n\nThe examples in this section draw on the\n[BITMAPFILEHEADER](https://msdn.microsoft.com/en-us/library/windows/desktop/dd183374(v=vs.85).aspx)\nand\n[BITMAPINFOHEADER](https://msdn.microsoft.com/en-us/library/windows/desktop/dd183376(v=vs.85).aspx)\nexamples documented on MSDN.\n\n## Basic types\n\n### Stdint\n\nppx\\_binary's records are built out of the integer types provided by the\n[Stdint](http://stdint.forge.ocamlcore.org/doc/) library. Given a record with\nfields of these types, we simply add the annotation `[@@deriving binary]` with\nan argument specifying the endianness of the integers:\n\n```ocaml\nopen Stdint\n\ntype t =\n  { bfType: uint16\n  ; bfSize: uint32\n  ; bfReserved1: uint16\n  ; bfReserved2: uint16\n  ; bfOffBits: uint32 }\n  [@@deriving binary ~endianness:\"little\"]\n```\n\nFrom this declaration, ppx\\_binary will generate the following values:\n\n* `of_bytes : Bytes.t -\u003e int -\u003e t`, where `of_bytes buffer n` reads a `t` from\n  `buffer` starting at offset `n`;\n\n* `to_bytes : t -\u003e Bytes.t -\u003e int -\u003e unit`, where `to_bytes t buffer n` writes\n  `t` to `buffer` starting at `int`;\n  \n* `byte_size : int`, the size of a serialized `t` in bytes.\n\n(If this type had any name other than `t`, such as `foo`, the resulting values\nwould be named `foo_of_bytes`, `foo_to_bytes`, and `byte_size_foo`.)\n\n### Masking with `int`\n\nUnfortunately, OCaml's type system requires that there are different functions\ncorresponding to each different type in the Stdint library. If you want to\nmultiply a `uint16` by 2, you will need to perform explicit conversions such as\n`UInt16.(n * (of_int 2))`.\n\nAs an alternative, ppx\\_binary can be told to automatically convert to and from\nOCaml's built-in `int` type:\n\n```ocaml\ntype t =\n  { bfType: int [@masking uint16]\n  ; bfSize: int [@masking uint32]\n  ; bfReserved1: int [@masking uint16]\n  ; bfReserved2: int [@masking uint16]\n  ; bfOffBits: int [@masking uint32] }\n  [@@deriving binary ~endianness:\"little\"]\n```\n\nThe resulting record fields are all of type `int`, and so can be manipulated\nwithout explicit conversion. The generated code automatically handles conversion\nupon serialization and deserialization.\n\nThe downside of this approach is that ppx\\_binary does not verify that the `int`\ntype on a given platform can accomodate all values of a given Stdint type. For\nexample, converting an `int64` to an `int` can have unintended results on a\n32-bit platform. The user is responsible for ensuring that only safe conversions\nare attempted.\n\n## Compound types\n\nppx\\_binary can work with other record field types provided that there are\nappropriate `of_bytes`, `to_bytes`, and `byte_size` values defined. In the\nfollowing example, implementations of the BITMAPFILEHEADER and BITMAPINFOHEADER\nstructures are combined into one record that encapsulates the complete BMP\nheader:\n\n```ocaml\nmodule Bitmapfileheader = struct\n  type t =\n    { bfType: int [@masking uint16]\n    ; bfSize: int [@masking uint32]\n    ; bfReserved1: int [@masking uint16]\n    ; bfReserved2: int [@masking uint16]\n    ; bfOffBits: int [@masking uint32] }\n    [@@deriving binary ~endianness:\"little\"]\nend\n\nmodule Bitmapinfoheader = struct\n  type t =\n    { biSize: int [@masking uint32]\n    ; biWidth: int [@masking int32]\n    ; biHeight: int [@masking int32]\n    ; biPlanes: int [@masking uint16]\n    ; biBitCount: int [@masking uint16]\n    ; biCompression: int [@masking uint32]\n    ; biSizeImage: int [@masking uint32]\n    ; biXPelsPerMeter: int [@masking int32]\n    ; biYPelsPerMeter: int [@masking int32]\n    ; biClrUsed: int [@masking uint32]\n    ; biClrImportant: int [@masking uint32] }\n  [@@deriving binary ~endianness:\"little\"]\nend\n\nmodule Header = struct\n  type t =\n    { fileheader : Bitmapfileheader.t\n    ; infoheader : Bitmapinfoheader.t }\n  [@@deriving binary]\nend\n```\n\nIn the declaration of `Header.t`, we do not need to provide an endianness\nbecause we are not directly using any integer types. If we needed to specify\nendianness for a specific field, this could be done by adding an `[@endianness\nlittle]` or `[@endianness big]` attribute on that field.\n\nThis example can be seen in action in `examples/resize.ml` and\n`examples/resize_masking.ml`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleviroth%2Fppx_binary","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleviroth%2Fppx_binary","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleviroth%2Fppx_binary/lists"}