{"id":17680705,"url":"https://github.com/elbywan/ppx-ctypes-helper","last_synced_at":"2025-03-30T19:12:47.431Z","repository":{"id":152588019,"uuid":"208648145","full_name":"elbywan/ppx-ctypes-helper","owner":"elbywan","description":"Ppx that helps serializing structures and enums to / from c. 🏭","archived":false,"fork":false,"pushed_at":"2019-09-22T20:41:00.000Z","size":100,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-05T21:36:06.547Z","etag":null,"topics":["ctypes","ocaml","ppx","reasonml","serialize"],"latest_commit_sha":null,"homepage":"","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/elbywan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"MIT-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":"2019-09-15T19:45:47.000Z","updated_at":"2020-01-12T08:49:11.000Z","dependencies_parsed_at":null,"dependency_job_id":"9a14e1e6-396a-4bcb-9c63-f9c6104c616d","html_url":"https://github.com/elbywan/ppx-ctypes-helper","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elbywan%2Fppx-ctypes-helper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elbywan%2Fppx-ctypes-helper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elbywan%2Fppx-ctypes-helper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elbywan%2Fppx-ctypes-helper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elbywan","download_url":"https://codeload.github.com/elbywan/ppx-ctypes-helper/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246365645,"owners_count":20765546,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ctypes","ocaml","ppx","reasonml","serialize"],"created_at":"2024-10-24T09:08:39.645Z","updated_at":"2025-03-30T19:12:47.406Z","avatar_url":"https://github.com/elbywan.png","language":"OCaml","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1\u003e\nppx-ctypes-helper\n\u0026nbsp;\n\u003ca href=\"https://www.npmjs.com/package/ppx-ctypes-helper\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/v/ppx-ctypes-helper?style=flat-square\"\u003e\n\u003c/a\u003e\n\u003c/h1\u003e\n\n## Purpose\n\nThe purpose of this preprocessor extension is to heavily simplify the usage of the ctypes library, especially when dealing with structures and enums.\n\n## Installation\n\n### Using esy\n\n`esy add ppx-ctypes-helper`\n\n### With dune\n\nAdd the following line to your `dune` file.\n\n```\n(preprocess ( pps ppx-ctypes-helper.lib ))\n```\n\n### With pesy\n\nAdd the following key to your `package.json` or `esy.json` file.\n\n```json\n\"preprocess\": \"pps ppx-ctypes-helper.lib\"\n```\n\n## Usage\n\n### %%struct\n\nThe `%%struct` extension sets up a full structure comprised of a ctype definition with fields, utility operators, types and a view that will automatically serialize the structure into/from an ocaml record.\n\nThe available typenames are the same as those supported by ctypes. See [here](https://github.com/ocamllabs/ocaml-ctypes/blob/master/src/ctypes/ctypes_static.mli#L118) for the list.\n\n#### Syntax\n\n`(typename)(\"*\" - 0 or more)(\"?\" - 0 or 1 occurence)([fieldName] - 0 or 1 occurence with an optional field name between the brackets)`\n\nSpaces are allowed between parts.\n\n##### Conventions\n\n- To be considered as a **structure**, a typename must start with an uppercase letter.\n- To be considered as an **enum**, a typename must contain only uppercase letters and underscores.\n\n#### Example\n\n##### Reasonml syntax\n\n```reason\n%struct\n(\n    \"StructureName\",\n    {\n        integer: \"int\",\n        text: \"string\",\n        optional_string: \"string_opt\",\n        // By default, uses the \"size\" field to determine the length  of the array.\n        string_array: \"string[]\",\n        size: \"int32_t\",\n        other_structure: \"OtherStructure\",\n        other_structure_pointer: \"OtherStructure *\",\n        other_structure_pointer_optional: \"OtherStructure *?\",\n        // Uses the \"count\" field to determine the length.\n        other_structure_array: \"OtherStructure[count]\",\n        count: \"int\",\n        other_structure_pointer_optional_array: \"OtherStructure *?[]\",\n        enumeration: \"ENUM_NAME\"\n    }\n)\n\n/* Then, simply use it like a ctype view. */\nforeign(\"function_name\", StructureName.view @-\u003e (returning @@ void))\n```\n\n##### Ocaml syntax\n\n```ocaml\n[%%struct (\"StructureName\", {\n    integer = \"int\";\n    text = \"string\";\n    optional_string = \"string_opt\";\n    string_array = \"string[]\";\n    size = \"int32_t\";\n    other_structure = \"OtherStructure\";\n    other_structure_pointer = \"OtherStructure *?\";\n    other_structure_pointer_optional = \"OtherStructure *?\";\n    other_structure_array = \"OtherStructure[count]\";\n    count = \"int\";\n    other_structure_pointer_optional_array = \"OtherStructure *?[]\";\n    enumeration = \"ENUM_NAME\";\n})]\n```\n\n##### Generated code\n\n```reason\nmodule StructureName {\n  /* Abstract type to specialize the structure. */\n  type t;\n\n  /* Ctypes structure definition. */\n  let structure: Ctypes.typ(Ctypes.structure(t));\n\n  /* Operators to access and set structure fields. */\n\n  /* To set some fields: structure \u003e. field \u003e= value \u003e. field2 \u003e= value2 */\n  /* To get a field value: structure \u003e? field */\n\n  let ( \u003e. ): ('a, 'b) =\u003e ('a, 'b);\n  let ( \u003e= ):\n    ((Ctypes.structured('a, 'b), Ctypes.field('c, Ctypes.structured('a, 'b))),\n    'c) =\u003e Ctypes.structured('a, 'b);\n  let ( \u003e? ):\n    (Ctypes.structured('a, 'b),\n    Ctypes.field('c, Ctypes.structured('a, 'b))) =\u003e 'c;\n\n  /* Field definitions. */\n\n  let integer: Ctypes.field(int, Ctypes.structure(t));\n  let text: Ctypes.field(string, Ctypes.structure(t));\n  let optional_string: Ctypes.field(option(string), Ctypes.structure(t));\n  let string_array:\n    Ctypes.field(option(Ctypes_static.ptr(string)), Ctypes.structure(t));\n  let size: Ctypes.field(int32, Ctypes.structure(t));\n  let other_structure:\n    Ctypes.field(OtherStructure.t_view, Ctypes.structure(t));\n  let other_structure_pointer:\n    Ctypes.field(Ctypes_static.ptr(OtherStructure.t_view),\n                  Ctypes.structure(t));\n  let other_structure_pointer_optional:\n    Ctypes.field(option(Ctypes_static.ptr(OtherStructure.t_view)),\n                  Ctypes.structure(t));\n  let other_structure_array:\n    Ctypes.field(option(Ctypes_static.ptr(OtherStructure.t_view)),\n                  Ctypes.structure(t));\n  let count: Ctypes.field(int, Ctypes.structure(t));\n  let other_structure_pointer_optional_array:\n    Ctypes.field(option(Ctypes_static.ptr(option(Ctypes_static.ptr(OtherStructure.t_view)))),\n                  Ctypes.structure(t));\n  let enumeration: Ctypes.field(ENUM_NAME.t, Ctypes.structure(t));\n\n  /* Type definition for the serialized record. */\n\n  type t_view = {\n    enumeration: ENUM_NAME.t,\n    other_structure_pointer_optional_array:\n      list(option(OtherStructure.t_view)),\n    count: int,\n    other_structure_array: list(OtherStructure.t_view),\n    other_structure_pointer_optional: option(OtherStructure.t_view),\n    other_structure_pointer: OtherStructure.t_view,\n    other_structure: OtherStructure.t_view,\n    size: int32,\n    string_array: list(string),\n    optional_string: option(string),\n    text: string,\n    integer: int,\n  };\n\n  /* A pair of functions + a view that are used to automatically convert from/to the record with the ctypes structure. */\n\n  let read: Ctypes.structured(t, [ `Struct ]) =\u003e t_view;\n  let write: t_view =\u003e Ctypes.structured(t, [ `Struct ]);\n  let view: Ctypes.typ(t_view);\n}\n```\n\n### %%enum\n\nIn the same fashion, the `%%enum` extension generates converters between an enum and its native value.\n\n#### Syntax\n\nDecorate a variant type with the extension.\n\nThis will generate a module of the same name as the type, but fully uppercased and containing a ctypes view.\nOptionally annotate variants with the `@as` decorator to associate a specific value.\n\nBy default, enums are associated with integers starting from 0. Use the `@as` annotation to change the inferred type.\n\nAvailable types:\n\n- string\n- int\n- float\n- char\n\n#### Example\n\n##### Ocaml syntax\n\n```ocaml\n[%%enum type int_enum = Ten [@as 10] | One | Two | Twenty [@as 20]]\n[%%enum type string_enum = Hello [@as \"Hello\"] | World]\n```\n\n##### Reasonml syntax\n\n```reason\n%enum\ntype int_enum =\n    | [@as 10] Ten\n    | One\n    | Two\n    | [@as 20] Twenty;\n\n%enum\ntype string_enum =\n    | [@as \"Hello\"] Hello\n    | World;\n```\n\n##### Generated code\n\n```ocaml\nmodule INT_ENUM =\n  struct\n    type t =\n      | Ten [@as 10]\n      | One\n      | Two\n      | Twenty [@as 20]\n    let view =\n      Ctypes.view\n        ~read:((function | 10 -\u003e Ten | 1 -\u003e One | 2 -\u003e Two | 20 -\u003e Twenty)\n        [@warning \"-8\"])\n        ~write:(function | Ten -\u003e 10 | One -\u003e 1 | Two -\u003e 2 | Twenty -\u003e 20)\n        Ctypes.int\n  end\nmodule STRING_ENUM =\n  struct\n    type t =\n      | Hello [@as \"Hello\"]\n      | World\n    let view =\n      Ctypes.view ~read:((function | \"Hello\" -\u003e Hello | \"World\" -\u003e World)\n        [@warning \"-8\"])\n        ~write:(function | Hello -\u003e \"Hello\" | World -\u003e \"World\") Ctypes.string\n  end\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felbywan%2Fppx-ctypes-helper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felbywan%2Fppx-ctypes-helper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felbywan%2Fppx-ctypes-helper/lists"}