defmodule Zig.Type.Pointer do @moduledoc false alias Zig.Type alias Zig.Type.Optional use Type defstruct [:child, optional: false] @type t :: %__MODULE__{ optional: boolean(), child: Type.t() } @mutable_types ~w(array struct) # special case: pointer represents that the data are mutable. def from_json(%{"type" => "pointer", "child" => %{"type" => mutable} = child}, module) when mutable in @mutable_types do child |> Type.from_json(module) |> Map.replace!(:mutable, true) end # special case: pointer represents that the data are mutable AND optional. def from_json( %{ "type" => "optional", "child" => %{"type" => "pointer", "child" => %{"type" => mutable} = child} }, module ) when mutable in @mutable_types do child |> Type.from_json(module) |> Map.replace!(:mutable, true) |> then(&%Optional{child: &1}) end def from_json(%{"type" => "optional", "child" => pointer}, module) do pointer |> from_json(module) |> Map.replace!(:optional, true) end def from_json(%{"type" => "pointer", "child" => %{"type" => "unusable:anyopaque"}}, _module) do %__MODULE__{child: :anyopaque} end def from_json(%{"child" => child}, module) do %__MODULE__{child: Type.from_json(child, module)} end @impl true def marshal_param(_, variable, _, platform), do: Type._default_marshal_param(platform, variable) @impl true def marshal_return(_, _, _), do: raise("unreachable") # validations: @impl true def get_allowed?(_), do: false @impl true def make_allowed?(_), do: false @impl true def in_out_allowed?(%{child: child}), do: Type.get_allowed?(child) and Type.make_allowed?(child) @impl true def binary_size(_), do: nil @impl true def render_accessory_variables(type, param, prefix) do if param.in_out do ~s(var #{prefix}: #{Type.render_zig(type.child)} = undefined;) else raise "unreachable" end end @impl true # pointer might be used as a in-out return value. def payload_options(_, _), do: [error_info: "&error_info"] @impl true def render_zig(%{optional: true} = type), do: "?*#{Type.render_zig(type.child)}" def render_zig(type), do: "*#{Type.render_zig(type.child)}" @impl true def render_cleanup(_, _), do: Type._default_cleanup() @impl true def render_elixir_spec(type, context), do: Type.render_elixir_spec(type.child, context) end