> ## Documentation Index
> Fetch the complete documentation index at: https://developers.stellar.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Types

> Define your own data structures in a smart contract.

The [custom types example] demonstrates how to define your own data structures that can be stored on the ledger, or used as inputs and outputs to contract invocations. This example is an extension of the [storing data example].

[![Open in Codespaces](https://github.com/codespaces/badge.svg)][open-in-github-codespaces]

[![Open in Codeanywhere](https://codeanywhere.com/img/open-in-codeanywhere-btn.svg)][open-in-code-anywhere]

[open-in-github-codespaces]: https://github.com/codespaces/new?repo=stellar/soroban-examples&editor=web

[open-in-code-anywhere]: https://app.codeanywhere.com/#https://github.com/stellar/soroban-examples

[custom types example]: https://github.com/stellar/soroban-examples/tree/v23.0.0/custom_types

[storing data example]: https://developers.stellar.org/docs/build/smart-contracts/getting-started/storing-data.md

## Run the Example

First go through the [Setup] process to get your development environment configured, then clone the `v23.0.0` tag of `soroban-examples` repository:

[setup]: https://developers.stellar.org/docs/build/smart-contracts/getting-started/setup.md

```sh theme={"theme":{"light":"github-light","dark":"github-dark"}}
git clone -b v23.0.0 https://github.com/stellar/soroban-examples
```

Or, skip the development environment setup and open this example in [GitHub Codespaces][open-in-github-codespaces] or [Code Anywhere][open-in-code-anywhere].

To run the tests for the example, navigate to the `custom_types` directory, and use `cargo test`.

```sh theme={"theme":{"light":"github-light","dark":"github-dark"}}
cd custom_types
cargo test
```

You should see the output:

```
running 1 test
test test::test ... ok
```

## Code

```rust title="custom_types/src/lib.rs" theme={"theme":{"light":"github-light","dark":"github-dark"}}
#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct State {
    pub count: u32,
    pub last_incr: u32,
}

const STATE: Symbol = symbol_short!("STATE");

#[contract]
pub struct IncrementContract;

#[contractimpl]
impl IncrementContract {
    /// Increment increments an internal counter, and returns the value.
    pub fn increment(env: Env, incr: u32) -> u32 {
        // Get the current count.
        let mut state = Self::get_state(env.clone());

        // Increment the count.
        state.count += incr;
        state.last_incr = incr;

        // Save the count.
        env.storage().instance().set(&STATE, &state);

        // Return the count to the caller.
        state.count
    }
    /// Return the current state.
    pub fn get_state(env: Env) -> State {
        env.storage().instance().get(&STATE).unwrap_or(State {
            count: 0,
            last_incr: 0,
        }) // If no value set, assume 0.
    }
}
```

Ref: [https://github.com/stellar/soroban-examples/tree/v23.0.0/custom\_types](https://github.com/stellar/soroban-examples/tree/v23.0.0/custom_types)

## How it Works

Custom types are defined using the `#[contracttype]` attribute on either a `struct` or an `enum`.

Open the `custom_types/src/lib.rs` file to follow along.

### Custom Type: Struct

Structs are stored on ledger as a map of key-value pairs, where the key is up to a 32 character string representing the field name, and the value is the value encoded.

Field names must be no more than 32 characters.

```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct State {
    pub count: u32,
    pub last_incr: u32,
}
```

### Custom Type: Enum

The example does not contain enums, but enums may also be contract types.

Enums containing unit and tuple variants are stored on ledger as a two element vector, where the first element is the name of the enum variant as a string up to 32 characters in length, and the value is the value if the variant has one.

Only unit variants and single value variants, like `A` and `B` below, are supported.

```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
#[contracttype]
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Enum {
    A,
    B(...),
}
```

Enums containing integer values are stored on ledger as the `u32` value.

```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
#[contracttype]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(u32)]
pub enum Enum {
    A = 1,
    B = 2,
}
```

### Using Types in Functions

Types that have been annotated with `#[contracttype]` can be stored as contract data and retrieved later.

Types can also be used as inputs and outputs on contract functions.

```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
/// Increment increments an internal counter, and returns the value.
pub fn increment(env: Env, incr: u32) -> u32 {
    // Get the current count.
    let mut state = Self::get_state(env.clone());

    // Increment the count.
    state.count += incr;
    state.last_incr = incr;

    // Save the count.
    env.storage().instance().set(&STATE, &state);

    // Return the count to the caller.
    state.count
}

/// Return the current state.
pub fn get_state(env: Env) -> State {
    env.storage().instance().get(&STATE).unwrap_or(State {
        count: 0,
        last_incr: 0,
    }) // If no value set, assume 0.
}
```

## Tests

Open the `custom_types/src/test.rs` file to follow along.

```rust title="custom_types/src/test.rs" theme={"theme":{"light":"github-light","dark":"github-dark"}}
#[test]
fn test() {
    let env = Env::default();
    let contract_id = env.register(IncrementContract, ());
    let client = IncrementContractClient::new(&env, &contract_id);

    assert_eq!(client.increment(&1), 1);
    assert_eq!(client.increment(&10), 11);
    assert_eq!(
        client.get_state(),
        State {
            count: 11,
            last_incr: 10
        }
    );
}
```

In any test the first thing that is always required is an `Env`, which is the Soroban environment that the contract will run in.

```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
let env = Env::default();
```

The contract is registered with the environment using the contract type.

```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
let contract_id = env.register(IncrementContract, ());
```

All public functions within an `impl` block that is annotated with the `#[contractimpl]` attribute have a corresponding function generated in a generated client type. The client type will be named the same as the contract type with `Client` appended. For example, in our contract the contract type is `IncrementContract`, and the client is named `IncrementContractClient`.

```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
let client = IncrementContractClient::new(&env, &contract_id);
```

The test invokes the `increment` function on the registered contract that causes the `State` type to be stored and updated a couple times.

```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
assert_eq!(client.increment(&1), 1);
assert_eq!(client.increment(&10), 11);
```

The test then invokes the `get_state` function to get the `State` value that was stored, and can assert on its values.

```rust theme={"theme":{"light":"github-light","dark":"github-dark"}}
assert_eq!(
    client.get_state(),
    State {
        count: 11,
        last_incr: 10
    }
);
```

## Build the Contract

To build the contract, use the `stellar contract build` command.

```sh theme={"theme":{"light":"github-light","dark":"github-dark"}}
stellar contract build
```

A `.wasm` file should be outputted in the `target` directory:

```
target/wasm32v1-none/release/soroban_custom_types_contract.wasm
```

## Run the Contract

If you have [`stellar-cli`] installed, you can [deploy] and invoke contract function.

> [tab] macOS/Linux
>
> ```sh theme={"theme":{"light":"github-light","dark":"github-dark"}}
> stellar contract invoke \
>     --id CACDYF3CYMJEJTIVFESQYZTN67GO2R5D5IUABTCUG3HXQSRXCSOROBAN \
>     --source-account alice \
>     --network testnet \
>     -- \
>     increment \
>     --incr 5
> ```

> [tab] Windows (PowerShell)
>
> ```powershell theme={"theme":{"light":"github-light","dark":"github-dark"}}
> stellar contract invoke `
>     --id CACDYF3CYMJEJTIVFESQYZTN67GO2R5D5IUABTCUG3HXQSRXCSOROBAN `
>     --source-account alice `
>     --network testnet `
>     -- `
>     increment `
>     --incr 5
> ```

The following output should occur using the code above.

```
5
```

Run it a few more times with different increment amounts to watch the count change.

Use the `stellar-cli` to inspect what the counter is after a few runs.

```sh theme={"theme":{"light":"github-light","dark":"github-dark"}}
stellar contract read --id 1 --key STATE
```

```
STATE,"{""count"":25,""last_incr"":15}"
```

[`stellar-cli`]: ../getting-started/setup#install-the-stellar-cli

[deploy]: https://developers.stellar.org/docs/build/smart-contracts/getting-started/deploy-to-testnet.md
