How to constrain types where `AsRef` and `AsMut` point to the same data?

During my Rust experience, I often declare a function, which takes a generic variable which implements both AsRef<[u8]> and AsMut<[u8]>. Under this constraint, I can access the data both uniquely or sharedly.

However, I realized that the AsRef and AsMut trait does not enforce that the as-ed data is the same. For example:

struct Foo { a: [u8; 4], b: [u8; 8], }
impl AsRef<[u8]> for Foo {
    fn as_ref(&self) -> &[u8] { &self.a }
}
impl AsMut<[u8]> for Foo {
    fn as_mut(&mut self) -> &mut [u8] { &mut self.b }
}

If AsRef and AsMut point to different data, a lot of logic in my code will break.

The same situation also holds for Deref/DerefMut (DerefMut is restricted to re-use the Target associated type of Deref, which I guess the design is to imply that they should point to the same data), Borrow/BorrowMut.

P.S. Directly declare the function to take a Box<[u8]> does not work, since this function can also takes Memmap, a buffer created by mmap. Converting it to Box will lose the destructor.

isn't AsMut<[u8]> alone enough, since you can always reborrow &mut [u8] as &[u8]?

if not, can you provide some code to show your use case?

For example:

struct Context<T: /* ? */> {
    buffer: T
}

impl<T: /* ? */> Context<T> {
    fn foo(&self) {
        let buf = self.buffer.as_ref();
    }

    fn bar(&mut self) {
        let buf = &*self.buffer.as_mut();
    }
}

If I only declare AsMut, then all methods of Context will become &mut self.

do you know of a real-world case where AsRef<T> and AsMut<T> both exist and are not coherent ?
if not, this might simply be added as a correctness requirement of these traits

I never meet that situation during my 7 years Rust experience.

However, some unsafe code may depend on this correctness requirement (For example, the as_ref-read should read the same byte that was previously as_mut-written), which will then require the library interface function to be marked unsafe (e.g. "SAFETY: There will be unsoundness if AsRef and AsMut point to different data). I would like something that can constraint this in type system instead of manual annotations

if unsafe code relies on a generic safe trait impl to be implemented correctly, then that code is unsound.

at this moment, as far as i can see, there is nothing at all in the standard library that requires AsRef, Borrow, and Deref to have the same adress as their mutable counterparts.

so what you want doesn't exist. you could make your own unsafe trait to add this guarantee, and implement it for types that you know behave correctly if you want.

but if general change is to be achieved, the only thing i can imagine would be to put this as a correctness requirement on the traits at issue, similarly to how [Partial]Eq and [Partial]Ord work.

I can't see any way to express the constraint in the current type system (or honestly in any realistic extension to the type system either). Unsoundness could be avoided with a run-time assertion that ptr::eq(x.as_ref(), x.as_mut()).

In the doc of PartialEq:

The equality relation == must satisfy the following conditions (for all a , b , c of type A , B , C ):

...

Violating these requirements is a logic error. The behavior resulting from a logic error is not specified, but users of the trait must ensure that such logic errors do not result in undefined behavior. This means that unsafe code must not rely on the correctness of these methods.

So if unsafe code requires those correctness, they should either check it internally and expose as a safe function, or exposed as an unsafe function and in the "SAFETY" section, describes the safety requirements.

However, the former approach hardly works for the AsRef/AsMut one. A safe function should store the address and length to a global context in the first time a as_ref or as_mut is invoked. And in each following invocations, the result of as_ref and as_mut must be matched against the previously-stored global context.

The best approach I can come up with, is to accepts &mut [u8] in the function parameter, and stores it as a Box<[u8]> from raw pointers, and mem::forget it in the destructor.

This check only guarantees the equality in this moment. To guarantee the pointed address is not changed during the whole execution, the address should be saved into a global context.

For a simple ptr::eq(x.as_ref(), x.as_mut()) , I believe the check could be optimized out if they point to the same data. However, this may not hold for the global-context situation I mentioned above.

And in type system, I think there could be an unsafe trait AsData, with two safe methods as_ref and as_mut. Implementors should make sure the data should be the same, and this makes the consumer of this trait free from the complex check or unsafe annotations.

You can define an unsafe trait with the safety precondition you need:

// SAFFETY: implementers must guarantee that the implementation of `AsRef::as_ref`
// and `AsMut::as_mut`, if any, return references to the same place.
unsafe trait CoherentAsRefMut<T: ?Sized> {}

You can then implement this for some common types like &[u8]/&mut [u8]/Box<[u8]> and even Memmap if you need.

this is orthogonal to the coherence problem you are asking, but you can put the trait bound on individual methods instead of at type definition or the entire impl block, or you can group different methods into separate impl blocks per trait bounds.

impl<T> Context<T> {
    fn foo(&self) where T: AsRef<[u8]> {
        let buf = self.buffer.as_ref();
    }

    fn bar(&mut self) where T: AsMut<[u8]> {
        let buf = &*self.buffer.as_mut();
    }
}

as far as I know, there's no such requirement of the standard traits AsMut and AsRef. even BorrowMut, which has Borrow as super trait, or DerefMut, which has Deref as super trait, don't have the correctness requirement, but I don't know any real world examples with incoherent behavior either.

reminder AsMut can also do

struct Foo { a: [u8; 4], b: [u8; 8], flip : bool}

impl AsMut<[u8]> for Foo {
    fn as_mut(&mut self) -> &mut [u8] { 
      self.flip = !self.flip;
      if self.flip { &mut self.a } else  { &mut self.b }
    }
}

or

struct Foo { a: [u8; 4], b: [u8; 8]}

impl AsMut<[u8]> for Foo {
    fn as_mut(&mut self) -> &mut [u8] { 
      core::mem::swap(&mut self.a, &mut self.b);
      &mut self.a
    }
}

or even

struct Foo { a: [u8; 4], b: [u8; 8], flip : Wrapping<u8> }

impl AsMut<[u8]> for Foo {
    fn as_mut(&mut self) -> &mut [u8] { 
      core::mem::swap(&mut self.a, &mut self.b);
      self.flip += 1;
      if self.flip.get() % 3 == 0 { &mut self.a } else  { &mut self.b }
    }
}

without needing to get AsRef involved at all.
it is implicitly expected not to do that, the same way it is expected to return the same as AsRef, but that is not guaranteed in any way

is your concern that you might have to write unsafe code that relies on that assumption or that others would? because in my opinion you should not get crazy trying to defend an hypotetical dev from making unfounded assumptions on the internal implementation of a trait.

How exactly do you want to handle Vec<u8>? When it reallocates, does that qualify as a change? What about a theoretical MutexVec<u8> that internally locks when dereferenced, meaning another thread could've changed it between calls?

AsRef and AsMut will never change the length of the underline buffer, so I think there will never be reallocations

Is that the only way it's ever exposed? Even if so, it could again be some sort of double-buffered concurrent datastructure, which another thread acts on. Or even just an incoherent impl of As{Ref,Mut} that appends or clears or something. The point is, you can't rely on that for safety.

Which seems likely unsound. Better to store a *mut [u8], and of course the constructor would need to be unsafe since the user needs to assert that the &mut [u8] reference they provide is not invalidated while your struct is used.

Though that would still have 2 usizes of unnecessary overhead and unsafe at each call site, compared to unsafe trait impls for each buffer type asserting that AsRef and AsMut are well-behaved.