/* A nsync_dll_element_ represents an element of a doubly-linked list of waiters. */
typedef struct nsync_dll_element_s_ {
struct nsync_dll_element_s_ *next;
struct nsync_dll_element_s_ *prev;
void *container; /* points to the struct this nsync_dll struct is embedded in. */
} nsync_dll_element_;
CAUTION: because of the borrow semantic, linked list in rust is infamously HARD to implement correctly, intrusive linked list is especially VERY HARD. if you just want to "mechanically" translate some C code involving intrusive linked list into rust, please don't, you'd better rewrite the logic in rust, or just call the C code through ffi.
function pointers:
C:
struct wait_condition_s {
int (*f) (const void *v);
const void *v;
int (*eq) (const void *a, const void *b);
};
rust raw pointers can be casted to different types, the type is mostly for convenience. if all you need is an opaque pointer that can be stored and passed as-is to some ffi API, you can use raw pointer of any type (but must be Sized, i.e. size is known at compile time, this includes zero sized types), rust doesn't care about the type of raw pointers if you don't deref them (requires unsafe anyway).
The goal is to do a pure Rust port with no ffi. That is no functionality from C implementation. The C library builds its own synchronization primitives like semaphore, condvar, mutex etc.
Thank you for the answers. This clarifies things a bit.
Why? Mechanically translated code is worse than C!
No, really, that's by design, it's not a bug.
“Safe” rust is much safer and robust than C, but warts have to live somewhere… and they live in unsafe Rust.
That means that unsafe Rust is harder and more fragile than C.
And that means that mechanical translation from C to Rust makes things worse, not better.
In Rust you rarely need or want to do that. First of all it's much easier to bring crates into Rust project that libraries into C project. Second – all that stuff is, by necessity, built in unsafe Rust thus you don't want to do that except you don't have any choice (see above).
Then it's usually better to think about what you library does.
In Rust you wouldn't have any “pointers to void” here or “functions”. You would have closure, generics, traits and other such things.
How much Rust background do you have? Porting C library to Rust when you don't have enough Rust knowledge like some people are doing is extremely efficient way to develop intense hatred of Rust for the remaining of your life.
It's roughly similar to an attempt to port assembler library, full of machine-code-level tricks to C: not impossible… if you know C pretty well – but, essentially, unfeasible, for someone like Mel.
If it's for the sake if learning then it could be an interesting project and may even lead to something viable.
Just be prepared to redo things few times.
That's, essentially, why that's not recommended to do in “real” work: it's usually not easy to convince management to give you a chance to redo the same work 2-3-5 times… but that's, essentially, necessity to do a good port of C library in Rust if you don't have few years of Rust experience already.
But as others have mentioned. If you're able to avoid doing this by just using another type from std::collections then prefer that.
As for learning I recommend reading both the rust reference and the rustonomicon, even though some say it's outdated. It's a lot to read both, but I think it's necessary when you're writing more unsafe code.