ReiGun
ReiGun

Reputation: 123

How do I mutate a StorageMap where the value is an enum?

here is my StorageMap:

    #[pallet::getter(fn hotel_status)]
    /// Keeps track of what accounts own what Kitty.
    pub(super) type HotelStatus<T: Config> = StorageMap<
        _,
        Twox64Concat,
        T::AccountId,
        Gender,
    >;

I want to use try_mutate to either mutate the Gender because the AccountId already exists in the map, or insert a new entry. Here's the full extrinsic:

        #[pallet::weight(0)]
        pub fn activate_hotel(
            origin: OriginFor<T>,
            hotel: T::AccountId,
        ) -> DispatchResult {
            let sender = ensure_signed(origin)?;
            log::info!("signer ID: {:?}.", sender);
            let hotel_status = <HotelStatus<T>>::get(&hotel);
            ensure!(hotel_status == Some(Gender::Active), <Error<T>>::HotelAlreadyActive);
            <HotelStatus<T>>::try_mutate(hotel, |status| {
                status = Gender::Active;
            }).map_err(|_| <HotelStatus<T>>::insert(hotel, Gender::Active));
            
            Ok(())
        }

the error I'm getting is

mismatched types
expected mutable reference, found enum `pallet::Gender`
note: expected mutable reference `&mut std::option::Option<pallet::Gender>`
                      found enum `pallet::Gender`rustc(E0308)
lib.rs(297, 14): expected mutable reference, found enum `pallet::Gender`

The substrate tutorials only give an example where the value is a vec and they try to push a new element onto it so I'm at a loss how to mutate an enum or primitive type (e.g. string, number).

Upvotes: 0

Views: 518

Answers (1)

Jerboas86
Jerboas86

Reputation: 654

  • Gender::Active is an enum
  • status is &mut Option<pallet::Gender>

You can't assign Gender::Active to status, because there are not the same type. This is what the error message is telling you:

expected mutable reference `&mut std::option::Option<pallet::Gender>`
                      found enum `pallet::Gender`rustc(E0308)

To mutate the value behind the reference you need (in this case) to dereference it with * operator. *status type is Option<pallet::Gender>. You need to wrap Gender::Active in Some variant before assigning it to *status, since Some(Gender::Active) type is also Option<pallet::Gender>.

try_mutate(hotel, |status| {
  *status = Some(Gender::Active);
  Ok(())
}

Ok(()) is required because the closure needs to return a Result

Upvotes: 1

Related Questions