I'm looking for some advice on how to organize my structs and traits here:
I'm working on implementing a UVM-style (https://www.usenix.org/legacy/event/usenix99/full_papers/cranor/cranor.pdf) virtual memory management system in my own hobby OS kernel. It, however, uses class-style inheritance (written in this case in C, though this should also work with C++) to achieve one important function: The interface to a memory object.
Let me explain. A memory object is something that can be mapped into virtual memory (often a file window). This interface has functions to get, mark dirty, and put (drop reference to) pages within the object. I want to use a page cache to implement this part of the interface.
Here's the problem: The PageCache needs to call something underlying to actually interact with the backing store. However, I want my Arc<VNode> (virtual inode; file) to implement MemoryObject. It would be most fitting (were this C or C++) to also use class-style inheritance to fix this. But this is Rust.
I have three potential alternate solutions, each of which suboptimal for different reasons:
- Give the
PageCachea*const dyn Pagerpointing to theVNode(requires moreunsafe) - Make every call to the
PageCacheaccept a&dyn Pager(not clean in terms of ownership) - Use several additional traits to use a
PageCacheto implementMemoryObjecton object that also implementPager(need a trait just to get the structPageCacheto use)
What are your thoughts?