Structs and enums

The structs and enums you define in your Sway code have equivalents automatically generated by the SDK's abigen! macro.

For instance, if in your Sway code you have a struct called CounterConfig that looks like this:

struct CounterConfig {
  dummy: bool,
  initial_value: u64,
}

After using the abigen! macro, CounterConfig will be accessible in your Rust file! Here's an example:

    abigen!(Contract(name="MyContract",
                     abi="e2e/sway/types/contracts/complex_types_contract/out/release/complex_types_contract-abi.json"));

    // Here we can use `CounterConfig`, a struct originally
    // defined in the contract.
    let counter_config = CounterConfig {
        dummy: true,
        initial_value: 42,
    };

You can freely use your custom types (structs or enums) within this scope. That also means passing custom types to functions and receiving custom types from function calls.

Generics

The Fuel Rust SDK supports both generic enums and generic structs. If you're already familiar with Rust, it's your typical struct MyStruct<T> type of generics support.

For instance, your Sway contract could look like this:

contract;

use std::hash::sha256;

struct SimpleGeneric<T> {
    single_generic_param: T,
}

abi MyContract {
  fn struct_w_generic(arg1: SimpleGeneric<u64>) -> SimpleGeneric<u64>;
}

impl MyContract for Contract {
    fn struct_w_generic(arg1: SimpleGeneric<u64>) -> SimpleGeneric<u64> {
        let expected = SimpleGeneric {
            single_generic_param: 123u64,
        };

        assert(arg1.single_generic_param == expected.single_generic_param);

        expected
    }
}

Your Rust code would look like this:

        // simple struct with a single generic param
        let arg1 = SimpleGeneric {
            single_generic_param: 123u64,
        };

        let result = contract_methods
            .struct_w_generic(arg1.clone())
            .call()
            .await?
            .value;

        assert_eq!(result, arg1);

Unused generic type parameters

Sway supports unused generic type parameters when declaring structs/enums:

struct SomeStruct<T, K> {
  field: u64
}

enum SomeEnum<T, K> {
  One: u64
}

If you tried the same in Rust you'd get complaints that T and K must be used or removed. When generating Rust bindings for such types we make use of the PhantomData type. The generated bindings for the above example would look something like this:

struct SomeStruct<T, K> {
   pub field: u64,
   pub _unused_generic_0: PhantomData<T>
   pub _unused_generic_1: PhantomData<K>
}

enum SomeEnum<T, K> {
  One(u64),
  IgnoreMe(PhantomData<T>, PhantomData<K>)
}

To lessen the impact to developer experience you may use the new method to initialize a structure without bothering with the PhantomDatas.:

        assert_eq!(
            <StructUnusedGeneric<u16, u32>>::new(15),
            StructUnusedGeneric {
                field: 15,
                _unused_generic_0: std::marker::PhantomData,
                _unused_generic_1: std::marker::PhantomData
            }
        );

If your struct doesn't have any fields we'll also derive Default. As for enums all PhantomDatas are placed inside a new variant called IgnoreMe which you'll need to ignore in your matches:

        match my_enum {
            EnumUnusedGeneric::One(_value) => {}
            EnumUnusedGeneric::IgnoreMe(..) => panic!("Will never receive this variant"),
        }