Is there a variant of Cow that uses interior mutability? A function with a signature like fn foo(x : &mut Cow<X>)
can assign *x = ...
and the caller will lose the original state and not register the fact that it was modified. Using x: &Cell<Cow<X>>
(or any other interior mutability wrapper cell around Cow) is not any better as there is still a way that the Cell can be set such that the complete original state of the interior Cow is lost, with no record that a modification took place. I need something that is modifiable but always knows whether or not it has been modified, which seems to imply it has to be interior mutable, and probably implements DerefMut. I still need Cow's behavior where it changes from a borrowed to an owned value on modification.
These are a lot of requirements you are listing
- "modifyable"
- "knows" whether it has been modified
- maybe interior mutability(?)
- cow-behavior, changing from a borrowed to an owned value on modification
and these are both all a bit imprecise and also not trivial to imagine the interplay of.
I think it would help if you could further illustrate this by coming up with some illustrative examples / use-cases that give rise to these requirements; this would help us make more sense of the exact requirements before trying to solve them.
Here's one way... to the extent I understand your requirements, which is probably "not at all completely".
pub struct CowPen<'a, T: ?Sized + ToOwned>(Cow<'a, T>);
impl<'a, T: ?Sized + ToOwned> CowPen<'a, T> {
pub fn with<F: FnMut(&mut Cow<'a, T>)>(&mut self, mut f: F) {
let was_borrowed = matches!(self.0, Cow::Borrowed(_));
f(&mut self.0);
// ...
}
}
You can replace the borrowed variant of Cow
with another borrowed variant, though I'm not sure if you care about that case or not.
Have you considered using Rc
/Arc
and their make_mut
method? Then a foo(x: Rc<X>)
can call make_mut
on the X
in order to modify it, and if anyone else is sharing that Rc
then make_mut
will make a copy for foo
to modify, thus nobody else will see the modified value.
No, why? All you need is privacy. Playground.
&mut Cow
is fine. The caller will observe the change if you replace it or run .to_mut()
on it.
This is an exclusive loan, so there is no possibility of the caller having another pointer to a "previous" Cow
instance.
If the caller wanted to keep the previous state, they could make a copy before calling your function.
If you never want to overwrite a Cow, then take &T
and return a new Cow<T>
.
My requirements are to have a way to modify it like Cell - meaning that it can be set through a &self
method instead of a &mut self
method. But otherwise the behavior should be like Cow. I only need to know if it ever has been set - I don't need to know the difference between being set once and more than once. The use case is passing a reference to the Cow/Cell to a plugin and allowing the plugin to modify it or not, and the base app needs to know whether it did so or not, as well as defend against miswritten plugins that, if given a x: &mut Cow<X>
might assign *x = ...
.
I don't think Rc helps, because it doesn't record the distinction between "never having been modified" vs. "was modified". Also, there is no issue with multiple shared ownership. Also no cross-thread usage, so the solution can be !Sync
and/or !Send
.
I could give the plugin an opaque ref (struct with private fields, or a dyn trait) and force it to use methods. I am considering that as a fallback option. BTW - if Rust had a stable ABI that included opaque dyn trait references, that would have been my first option. But it doesn't, even though there are user crates that would help with this. I may use one of those. Right now, I am trying to work out what things could look like if I design this app so that a plugin writer has to download my crate and statically link plugin modules they write into it. I'm rewriting a C app that was written to use DLL shared object plugins, but am trying to mesh with the expectations of potential Rust users (plugin writers for my app) who probably would rather do things the Rust way - statically link Rust-to-Rust without going through a FFI. I know that doesn't mean I can't still use an opaque ref.
I also mean by this that if there is a cell or smart pointer type that has the exact behavior I need, I should use it.
You can wrap my Branded<T>
demonstrated above into a RefCell
(for a non-thread-safe solution) or RwLock
/Mutex
(for a thread-safe solution). Of course, you won't be able to get direct references to the inner value then, only temporary refs through lock/cell guards.
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.