# `AshGrant.Permissionable`
[🔗](https://github.com/jhlee111/ash_grant/blob/v0.14.1/lib/ash_grant/permissionable.ex#L1)

Protocol for converting values to `AshGrant.PermissionInput` structs.

This protocol enables AshGrant to accept permissions from various sources
without requiring manual conversion in your `PermissionResolver`.

## Why Use This Protocol?

- **Zero boilerplate**: Return your existing structs directly from the resolver
- **Separation of concerns**: Conversion logic lives near your struct definition
- **Extensible**: Implement for any struct, including third-party ones
- **Backward compatible**: Plain strings continue to work without changes

## Default Implementations

AshGrant provides implementations for:

- `BitString` (plain strings) - Converts to `PermissionInput` with just the string
- `AshGrant.PermissionInput` - Pass-through, returns as-is
- `AshGrant.Permission` - Converts parsed permission back to input format

## Implementing for Custom Structs

If you have your own permission struct, implement the protocol:

    defmodule MyApp.RolePermission do
      defstruct [:permission_string, :label, :role_name]
    end

    defimpl AshGrant.Permissionable, for: MyApp.RolePermission do
      def to_permission_input(%MyApp.RolePermission{} = rp) do
        %AshGrant.PermissionInput{
          string: rp.permission_string,
          description: rp.label,
          source: "role:#{rp.role_name}"
        }
      end
    end

Then your resolver can simply return these structs:

    defmodule MyApp.PermissionResolver do
      @behaviour AshGrant.PermissionResolver

      @impl true
      def resolve(actor, _context) do
        # Just return your structs - AshGrant handles conversion
        MyApp.Accounts.get_role_permissions(actor)
      end
    end

## Usage Examples

### Plain strings (backward compatible)

    def resolve(actor, _context) do
      ["post:*:read:always", "post:*:update:own"]
    end

### Mixed strings and PermissionInput

    def resolve(actor, _context) do
      [
        "post:*:read:always",
        %AshGrant.PermissionInput{
          string: "post:*:update:own",
          description: "Edit own posts",
          source: "editor_role"
        }
      ]
    end

### Custom structs via Protocol

    def resolve(actor, _context) do
      # Returns [%MyApp.RolePermission{}, ...]
      # Protocol handles conversion automatically
      MyApp.Accounts.get_role_permissions(actor)
    end

# `t`

```elixir
@type t() :: term()
```

All the types that implement this protocol.

# `to_permission_input`

```elixir
@spec to_permission_input(t()) :: AshGrant.PermissionInput.t()
```

Converts a value to `AshGrant.PermissionInput` struct.

## Examples

    iex> AshGrant.Permissionable.to_permission_input("post:*:read:always")
    %AshGrant.PermissionInput{string: "post:*:read:always"}

    iex> input = %AshGrant.PermissionInput{string: "post:*:read:always", description: "Read posts"}
    iex> AshGrant.Permissionable.to_permission_input(input)
    %AshGrant.PermissionInput{string: "post:*:read:always", description: "Read posts"}

---

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