modules communicate with eatch other using messages
Message reqs:
relative generic - understandable for the infrastructure
contain module specific information
ability to add new kinds of messages
e.g. HttpRequest does not meet the requirements, but it may be the specific part of the message
Example of simplest message that satisfies these reqs - Windows MSG “translated” to Zig:
pub const Msg = struct {
// The message identifier.
// Applications can only use the low word;
// the high word is reserved by the system.
msg: u32,
// Additional information about the message.
// The exact meaning depends on the value of the 'msg' member
wParam: usize,
// Additional information about the message.
// The exact meaning depends on the value of the 'msg' member
lParam: ?*anyopaque,
};
I think the best way to create messages like this would be to use a tagged union. Tagged unions work similar under the hood, but will give you more type safety compared to the C-style approach.
If you don’t know ahead of time what kind of messages there are, then yeah you cannot use tagged unions.
But I don’t really know why you wouldn’t know them upfront. If you have two modules that want send messages to each other, then surely they must be equipped with the knowledge of how to interpret these messages. So why not bake this knowledge tagged union? You could also make one tagged union for each channel or something like that, if you can’t maintain a global tagged union with all message types.
But of course you can always go back to the C way of doing things with anyopaque pointer and an integer (at least use an enum maybe?) tag, if you think that that’s the better solution.
Also a quick reminder: if you use different shared libraries, then you should always use extern structs/unions to ensure that both sides have the same memory layout.
But only do this if you can’t solve the problem without it. It’s not hard to add something extensible like this to a tagged union, but that doesn’t mean it’s a good idea to just throw one of those at the end of the union “just in case” or to make it “extensible”. It should represent a use you can’t satisfy in another way, like a plugin system where a consumer you didn’t write needs to use the message architecture.