# `ExMujoco.Gen.Header`
[🔗](https://github.com/d-led/ex.mujoco/blob/main/lib/ex_mujoco/gen/header.ex#L1)

Reads MuJoCo's C headers into data.

MuJoCo generates its own Python bindings the same way — `python/mujoco/introspect`
parses the headers and checks the result in. This is the same idea in Elixir: the
headers are the source of truth, the catalogue is checked in beside us, and
`mix ex_mujoco.gen --check` proves the two agree.

Three things are read:

  * **functions** — every `MJAPI` declaration in `mujoco.h` and the headers it
    includes;
  * **structs** — the members of `mjModel` and `mjData`, with the dimensions of
    their arrays taken from `mjxmacro.h`, which exists to be read like this;
  * **enums** — every `typedef enum mjtX { … } mjtX;`.

Nothing here decides what is *bound*; it only says what exists. `ExMujoco.Gen`
holds that decision, in `c_src/manifest.exs`.

# `ctype`

```elixir
@type ctype() :: %{name: String.t(), const: boolean(), pointers: non_neg_integer()}
```

A C type as it appears in a declaration: `mjtNum*`, `const char*`.

# `enum`

```elixir
@type enum() :: %{
  name: String.t(),
  items: [%{name: String.t(), value: integer() | nil, doc: String.t()}]
}
```

# `function_decl`

```elixir
@type function_decl() :: %{
  name: String.t(),
  returns: ctype(),
  parameters: [parameter()],
  doc: String.t(),
  variadic: boolean()
}
```

# `member`

```elixir
@type member() :: %{
  name: String.t(),
  type: ctype(),
  array: String.t() | nil,
  doc: String.t()
}
```

# `parameter`

```elixir
@type parameter() :: %{
  name: String.t(),
  type: ctype(),
  array: String.t() | nil,
  kind: :integer | :float | :string | :buffer | :resource | :opaque | :callback
}
```

# `classify_member`

What a member is, as far as a binding goes.

  * `:integer` and `:float` — one value of the struct, returned as is;
  * `:array` — a binary of elements plus its two extents;
  * `:unsupported` — nothing a caller can name, with the reason why.

# `element_type`

What an array of this element type is, as `{tag, cpp_type}`.

# `enums_in`

```elixir
@spec enums_in(Path.t()) :: [enum()]
```

Every `typedef enum mjtX { … } mjtX;` in one header.

# `functions_in`

```elixir
@spec functions_in(Path.t()) :: [function_decl()]
```

The `MJAPI` declarations in one header.

# `read`

```elixir
@spec read(Path.t()) :: %{
  functions: [function_decl()],
  structs: %{required(String.t()) =&gt; [member()]},
  enums: [enum()],
  version: non_neg_integer() | nil
}
```

Everything the headers say, as one map.

`dir` is a MuJoCo include root, the one `MUJOCO_DIR` names: it must hold
`mujoco/mujoco.h`.

# `struct_members!`

```elixir
@spec struct_members!(Path.t(), String.t()) :: [member()]
```

The members of one of MuJoCo's structs, with array dimensions from `mjxmacro.h`.

Value members (`mjtSize nq`) and pointers (`mjtNum* geom_pos`) are both here,
because a caller reads both. Arrays declared inline (`mjtNum solver_fwdinv[2]`)
carry their dimension in the declaration; a pointer carries it in the X-macro
lists, which is where MuJoCo itself gets it for `mjvScene` and the bindings.

# `unexposed_reason`

```elixir
@spec unexposed_reason(String.t(), String.t()) :: String.t() | nil
```

Why a member cannot be read as an array, when it cannot.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
