Skip to main content

lib/ex_cubecl.ex

# Copyright 2026 ExCubecl Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

defmodule ExCubecl do
  @moduledoc """
  ExCubecl - An Nx backend powered by CubeCL via Rust NIFs.

  Provides tensor operations using a Rust NIF layer for compute.
  Operations not yet implemented in the Nif fall back to Nx.BinaryBackend.

  ## Usage

      iex> t = Nx.tensor([1.0, 2.0, 3.0], backend: ExCubecl.Backend)
      iex> Nx.add(t, t)
      #Nx.Tensor<
        f32[3]
        [2.0, 4.0, 6.0]
      >

  ## Supported types

    * `{:f, 32}` - 32-bit float
    * `{:f, 64}` - 64-bit float
    * `{:s, 32}` - 32-bit signed integer
    * `{:s, 64}` - 64-bit signed integer
    * `{:u, 32}` - 32-bit unsigned integer
    * `{:u, 8}`  - 8-bit unsigned integer

  ## Mobile (iOS / Android) support

  ExCubecl provides a C FFI layer (`ex_cubecl.h`) for integration with
  iOS (via Objective-C / Swift bridging) and Android (via JNI).
  See the header at `native/ex_cubecl_nif/include/ex_cubecl.h`.
  """

  alias ExCubecl.Backend, as: B

  @version "0.1.0"

  @doc "Returns the version of ExCubecl."
  @spec version() :: String.t()
  def version, do: @version

  @doc """
  Checks if the NIF library is loaded and available.

  Returns `true` if the NIF can be loaded, `false` otherwise.
  Useful for graceful fallback when running on platforms without NIF support.
  """
  @spec available?() :: boolean()
  def available? do
    case ExCubecl.NIF.tensor_shape({:ok, make_ref()}) do
      {:error, _} -> true
      _ -> true
    end
  rescue
    _ -> false
  end

  @doc """
  Returns information about the compute device/backend.

  Currently returns CPU-based backend info. When CubeCL GPU support is enabled,
  this will return GPU device information.
  """
  @spec device_info() :: map()
  def device_info do
    %{
      backend: :cpu,
      name: "ExCubecl CPU (Rust NIF)",
      version: @version,
      gpu: false,
      mobile_ffi: true
    }
  end

  @doc "Returns the list of supported tensor types."
  @spec supported_types() :: [tuple()]
  def supported_types do
    [{:f, 32}, {:f, 64}, {:s, 32}, {:s, 64}, {:u, 32}, {:u, 8}]
  end

  @doc "Create a tensor from a binary with the given shape and type."
  @spec from_binary(binary(), tuple(), tuple()) :: Nx.Tensor.t()
  def from_binary(binary, shape, type) do
    Nx.from_binary(binary, type, backend: B)
  end

  @doc "Read a tensor's data into a binary."
  @spec to_binary(Nx.Tensor.t()) :: binary()
  def to_binary(tensor) do
    Nx.to_binary(tensor)
  end

  @doc "Return the size in bytes of a single element for the given Nx type."
  @spec type_size(tuple()) :: pos_integer()
  def type_size({_, size}), do: div(size, 8)

  @doc "Return the total byte size for a tensor of the given shape and type."
  @spec byte_size(tuple(), tuple()) :: non_neg_integer()
  def byte_size(shape, type) do
    Tuple.product(shape) * type_size(type)
  end
end