Any best practices for maintaining deep mutable data in Rust?

I have backgrounds from ClojureScript, where I used deep nested data structure quite often. In Rust, I use RwLock to maintain deep global states, and the data I maintain might get deeper and deeper. Any tricks for that?

Any tips for memory efficiency? Basically I'm aware of preventing duplications of data and memory. Is it common trick to use Rc/Arc to share data in such cases?

Rust has persistent data ilke rpds but it's more like dynamic typed data. I preferred using static types, but would it be superior in some cases?

How to mutate literals or inserting new data deep inside the structures? Better to use Vec HashMap from std, or using other crates?

Those data structures are definitely statically typed and generic over their element type. Where did you see the contrary?

Instead of trying to use tricks to make the nested updates easier, I'd cut out the deep nesting altogether and write my app so each component's state is flat and decoupled from the other components.

Unless you are dealing with massive amounts of data and your code is littered with gratuitous amounts of clone() and collect(), your program should already have pretty low memory usage.

Go has a proverb which is quite relevant to how you are sprinkling your codebase with Arc and RwLock:

Channels orchestrate; mutexes serialize

By wrapping your state in a RwLock, you create a bottleneck where anything that wants to update state needs to take the lock first. On the other hand, when different parts of your application are decoupled from each other it means those components are free to run in parallel.

Can you show us a minimal example of what you are trying to achieve? It might be easier if we have some code to talk about.

3 Likes

maybe RwLock<HashMap<NanoId, Vec<MyData>>> and

struct MyData {
  pub id: NanoId;
  pub name: String;
  pub desc: Option<String>;
  pub tags: Vec<String>;
}

tasks like,

  • updating desc field,
  • pushing values to tags field,

and all inside that RwLock.

Also I'm not sure but I may use data like

struct MyData {
  pub id: NanoId;
  pub name: String;
  pub desc: Option<String>;
  pub tags: Vec<String>;
  pub children: HashMap<Nanoid, Box<MyData>>;
}

which is recursively nested, how do I update nested fields mutably(if it's still recommended)?

Yes they are statically typed. However in Rust I have,

#[derive(Serialize, Deserialize)]
struct MyStruct {
  pub name: String;
  pub age: u8;
}

if I use rpds, it's going to be HashTrieMap<String, String>, it's like a dynamically typed data.

I don't follow. You can put any type in those collections, including your own types that you define.

In the type

name is a String, age is a number, it's clear and statically typed.

In HashTrieMap<String, String>, or HashTrieMap<String, T>, T is generalized. To represent both name in string and age in number, maybe I can define,

enum AnotherData {
  Str(String),
  SmallNum(u8)
}

in this way it's more and more dynamic. This is how HashTrieMap is used, it's an HashMap, rather than a struct.

(I have no idea if we can libraries to provide statically typed persistent data structure. A potential example might be Haskell Records, but I'm not sure if it has structural sharing like in Clojure.)

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.