Migrate to stable structures and use how to store vectors in ic stable structures

i had somthing like

static USER_FILES: RefCell<Vec<FilesStore>> = RefCell::default();

now I convert it to


#[derive(Clone, Debug, Deserialize, CandidType)]
pub struct FileNodeVector {
    pub files: Vec<FileNode>,
}

impl Storable for FileNodeVector {
    fn to_bytes(&self) -> Cow<[u8]> {
        Cow::Owned(Encode!(self).unwrap())
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Self {
        Decode!(bytes.as_ref(), Self).unwrap()
    }

    const BOUND: Bound = Bound::Unbounded;
}

static USER_FILES: RefCell<StableBTreeMap<String, FileNodeVector, Memory>> = RefCell::new(
        StableBTreeMap::init(
            MEMORY_MANAGER.with(|m| m.borrow().get(MemoryId::new(3))),
        )
    );

No the problem is I have to adjust all of my functions that uses SHARED_USER_FILES.with(|files_share_store| { which is a long painful process any alternatives ways to migrate?

Using the with syntax comes usually from using a thread_local which is irrespective of whether you use stable structures or not (it’s a Rust thing). Maybe you were using a simple static variable before (seems likely given the code snippet you shared) and now that you switch to stable structures you also introduced a thread_local (as we have in examples using stable structures)? In fact, we do recommend using a thread_local instead of a plain static variable.

in fact we are already using thread local.

can I also do it like ?

use ic_stable_structures::{
    storable::Bound, DefaultMemoryImpl, StableBTreeMap, Storable, StableVec,
};

thread_local! {
static MEMORY_MANAGER: RefCell<MemoryManager<DefaultMemoryImpl>> =
        RefCell::new(MemoryManager::init(DefaultMemoryImpl::default()));

static NOTIFICATIONS: RefCell<StableBTreeMap<String, StableVec<Notification,Memory>, Memory>> = RefCell::new(
        StableBTreeMap::init(
            MEMORY_MANAGER.with(|m| m.borrow().get(MemoryId::new(9))),
        )
    );
|

Perhaps I misunderstood the original message then. Can you show an example of what kind of change you had to do in your functions?

POSTS.with(|posts| {
            posts.borrow_mut().insert(id.clone(), self.clone());
        });

I don’t know which function u ment? but I don’t think it mattes here
what matter how to make the static that store vectors, I wish u can help me with a google meet call.

Goal

Store data like this <UserIdString, Vec<StructContractWhatever>>

I think I now got it looking at your previous comment as well.

Stable structures cannot be nested at the moment. So

static NOTIFICATIONS: RefCell<StableBTreeMap<String, StableVec<Notification,Memory>, Memory>> = RefCell::new(
        StableBTreeMap::init(
            MEMORY_MANAGER.with(|m| m.borrow().get(MemoryId::new(9))),
        )
    );

would not work as you try to store a StableVec inside a StableBTreeMap. Either you'd need to use a normal Vec` but of course it wouldn’t be as efficient (you’d need to rewrite the whole vector every time) or you’d need to design your StableBTreeMap with a composite key so that you can store multiple entries that share some part of the key (and another could be different).

You can read about using composite keys in this useful blog from Roman.

I ried use normal Vec but it shows srotable not implement for vec

Sure, but that’s not a hard error though. You need to implement Storable yourself (as you have to for any custom type you want to store in the StableBTreeMap).

do u mean impl storable for Vec

Yeah or you define your own type that wraps Vec<Data> and implement it for that. Whatever works best for you.

Failed to decode StoredContractVec

This error seams to be genrtaed from StoredContractVec but it actlyally happedn after calling FRIENDS_STORE.with(|friends_store| {...
Now, I just follow all ur steps but I am getting this error

{
  "Message": "IC0503: Error from Canister bkyz2-fmaaa-aaaaa-qaaaq-cai: Canister called `ic0.trap` with message: Failed to decode StoredContractVec: Custom(Fail to decode argument 0 from table0 to record {
    friends : vec record {
      sender : record {
        id : text;
        name : text;
        description : text;
        photo : blob;
      };
      confirmed : bool;
      receiver : record {
        id : text;
        name : text;
        description : text;
        photo : blob;
      };
    };
  }

  Caused by:
    Subtyping error: Type mismatch at /Users/ahmed/.cargo/registry/src/index.crates.io-6f17d22bba15001f/candid-0.10.10/src/de.rs:882).
Consider gracefully handling failures from this canister or altering the canister to handle exceptions. See documentation: http://internetcomputer.org/docs/current/references/execution-errors#trapped-explicitly"
}
``
my code
```lib.rs
thread_local! {
static FRIENDS_STORE: RefCell<StableBTreeMap<String, FriendVec, Memory>> = RefCell::new(
        StableBTreeMap::init(
            MEMORY_MANAGER.with(|m| m.borrow().get(MemoryId::new(6))),
        )
    );
static CONTRACTS_STORE: RefCell<StableBTreeMap<String, StoredContractVec, Memory>> = RefCell::new(
        StableBTreeMap::init(
            MEMORY_MANAGER.with(|m| m.borrow().get(MemoryId::new(6))),
        )
    );

}
pub fn get_list(user: Principal) -> Vec<Friend> {
        let mut list = vec![];
        FRIENDS_STORE.with(|friends_store| {
            let store = friends_store.borrow();
            if let Some(friends) = store.get(&user.to_string()) {
                list = friends.friends.clone();
            }
        });
        return list;
    }

impl Contract {
    pub fn get_all_contracts() -> Option<HashMap<ContractId, StoredContract>> {
        let mut contract_map = HashMap::new();

        CONTRACTS_STORE.with(|contracts_store| {
            let caller_contracts = contracts_store.borrow();
            if let Some(contracts) = caller_contracts.get(&caller().to_string()) {
                for contract in contracts.stored_contracts.iter() {
                    if let StoredContract::CustomContract(custom_contract) = contract {
                        contract_map.insert(custom_contract.id.clone(), StoredContract::CustomContract(custom_contract.check_view_permission()));
                    }
                }
            }


        });
        Some(contract_map)
    }....

This now is a candid decoding error. You need to double check whether you’ve correctly implemented the conversion from your Rust type to Candid and back. The error is likely coming from when you try to read the data from stable memory while you’re handling the request to sent to the canister.