Hello. I'm a C programmer trying to learn Rust. I've posted here once before after hitting some problems re-implementing a conventional intrusive linked list in Rust. I was quite surprised to find out that this is actually fairly challenging to do. One interesting thing someone mentioned was that Rust programmers typically don't reach for linked lists, instead favoring Vecs. This got me thinking that maybe I just need to try to reset how I think about code when learning Rust. After taking a break for a couple weeks I am trying again, this time attempting to convert a different simple C project, doing my best to think more like a Rust programmer.
That being said, I am now stuck trying to come up with the Rust versions of the structs I need and was wondering if I could get some help. I don't want any help with the method implementations just yet, but I think seeing the struct declarations would help me understand what different Rust types are useful for (particularly the smart pointers, which are a very new concept to me).
For context, this project basically allows me to represent, query, serialize, and unserialize json-like nested data structures (which I call variable structs or vstructs) in C. All entries in a vstruct can be added / removed / looked up via a name string. These are the C structs and enums used (Ignore the prefixes; I really love that rust has namespaces):
typedef enum pil_vstruct_data_type {
VSTRUCT_TYPE_U8 = 0,
VSTRUCT_TYPE_I8,
VSTRUCT_TYPE_U16,
VSTRUCT_TYPE_I16,
VSTRUCT_TYPE_U32,
VSTRUCT_TYPE_I32,
VSTRUCT_TYPE_U64,
VSTRUCT_TYPE_I64,
VSTRUCT_TYPE_STRING,
VSTRUCT_TYPE_VSTRUCT,
VSTRUCT_TYPE_U8_ARRAY,
VSTRUCT_TYPE_I8_ARRAY,
VSTRUCT_TYPE_U16_ARRAY,
VSTRUCT_TYPE_I16_ARRAY,
VSTRUCT_TYPE_U32_ARRAY,
VSTRUCT_TYPE_I32_ARRAY,
VSTRUCT_TYPE_U64_ARRAY,
VSTRUCT_TYPE_I64_ARRAY,
VSTRUCT_TYPE_STRING_ARRAY,
VSTRUCT_TYPE_VSTRUCT_ARRAY,
} pil_vstruct_data_type_t;
This enum just represents the data type of an entry in the vstruct. The primitive types are integers and the non-primitive types are strings or nested vstructs. In addition, entries can be arrays of any of these types. I believe I should be able to convert this into a Rust enum such that the underlying data types are included in the enums themselves. I'm also not sure how to declare these enums with slice types for the ARRAY
entires.
typedef struct pil_vstruct_entry {
pil_vstruct_data_type_t ve_type; /* data type of this entry's value */
u32 ve_name_size; /* size of ve_name in bytes */
u32 ve_nr_data; /* number of data values (as an array) */
char *ve_name; /* name of this entry */
void *ve_data; /* pointer to this entry's data */
pil_rb_node_t ve_link; /* link into vs_entries */
} pil_vstruct_entry_t;
This struct represents an entry in the vstruct. The key things are:
- the entry's data type (from the enum above)
- the name and name size
- the data (as a
void *
) and number of data entries (for arrays and strings)
There is also an intrusive link into a red-black tree which I have implemented elsewhere (it could just as easily have been a linked list or other data structure). I don't think I need this in the Rust implementation since the tree be able to do this non-intrusively. I also don't think I need the name and data sizes in Rust because Vecs know their lengths. I'm fairly certain I want this struct to "own" both its name and its data so that they get cleaned up when this struct is destroyed.
typedef struct pil_vstruct {
struct pil_vstruct *vs_parent; /* parent vstruct */
u32 vs_phys_size; /* packed size of this vstruct */
pil_rb_tree_t vs_entries; /* rb_tree of name / value pairs */
} pil_vstruct_t;
This is the vstruct itself (and the only structure referenced externally). This is also where I got really lost. phys_size
is meant to be the full size of a buffer required to serialize this vstruct into its binary format. This size includes the size of any internal vstructs. Whenever a user modifies a vstruct that is a child of another vstruct, I need to iterate up the chain of parents and update their sizes as well. Conceptually, I understand that I need a mutable reference to the parent, but the parent needs to "own" the child so I'm not sure how to make this work.
I would also like to replace my custom red-black tree implementation entries
for Rust's standard BTreeMap<&str, VstructEntry>
. However, whenever I add it to my struct, I get complaints about the lifetime of the &str, which I'm not sure how to resolve.
Any help would be really appreciated. I apologize for the long post, but I wanted to make sure what I have in C was clear. Again, I really would just like to see what the Rust-equivalent struct definitions would look like. Hopefully, from there I can figure out enough to write the rest of the code. Thanks a lot.