2

What is proper way of doing that? What options are available? I am aware about the problem of dangled references and the problem of self-referential struct. Still I have strong intuition it's a reachable problem because both owner and borrowed reference are returned and no memory deallocation happen. Also it's quite general problem! In theory, it's a solvable one.

use byte_slice_cast::*;

fn main() {
    let context = context_make();
    dbg!(&context);
}

//

fn context_make<'a>() -> Context<'a> {
    Context::<'a>::new()
}

//

#[derive(Debug)]
struct Context<'a> {
    pub dst_buffer: Box<[f32]>,
    pub dst_buffer_bytes: &'a [u8],
}

//

impl<'a> Context<'a> {
    fn new() -> Context<'a> {
        let len: usize = 13;
        let dst_buffer: Box<[f32]> = vec![0_f32; len].into_boxed_slice();
        let dst_buffer_bytes = dst_buffer.as_byte_slice();
        Context {
            dst_buffer,
            dst_buffer_bytes,
        }
    }
}

Note: this code requires byte-slice-cast = "1.2.0"

Interesting to compare solutions if there are more than one alternatives.

Playground

Kos
  • 1,547
  • 14
  • 23
  • Does this answer your question? [Why can't I store a value and a reference to that value in the same struct?](https://stackoverflow.com/questions/32300132/why-cant-i-store-a-value-and-a-reference-to-that-value-in-the-same-struct) – Netwave Nov 06 '21 at 10:13
  • That's definitely helpful, thanks. Still I believe my question add something. I have found solution with help of owning ref. I am looking for a solution with Pin and other alternatives. – Kos Nov 06 '21 at 15:30

2 Answers2

1

You can not do this in safe rust. There are good reasons for this like not being able to trivially move the struct without changing where the reference points to.

Instead, you would implement a function to get that reference:

struct Context {
    pub dst_buffer: Box<[f32]>,
}

impl Context {
    fn new() -> Context {
        let len: usize = 13;

        Context {
            dst_buffer: vec![0_f32; len].into_boxed_slice(),
        }
    }

    fn dst_buffer_bytes(&self) -> &[u8] {
        self.dst_buffer.as_byte_slice()
    }
}

And if you really want to print out the bytes too:

use std::fmt;

impl fmt::Debug for Context {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Context")
         .field("dst_buffer", &self.dst_buffer)
         .field("dst_buffer_bytes", self.dst_buffer_bytes())
         .finish()
    }
}
Hadus
  • 1,551
  • 11
  • 22
  • Sidenote: if you know that the `dst_buffer` is always 13 in length then you should instead use `[f32; 13]` that way you won't have to use the heap. – Hadus Nov 06 '21 at 15:07
  • There is better solution without reducing the structure to single representation of the data. Interesting is it possible to reach the same result with help of `Pin`. Thanks anyway. – Kos Nov 06 '21 at 15:27
  • 1
    @Kos there was a really nice article about just using pin for this on thisweekinrust: https://arunanshub.hashnode.dev/self-referential-structs-in-rust – Hadus Nov 06 '21 at 15:33
  • 1
    Thank you. It's very useful! – Kos Nov 06 '21 at 16:15
1

Solution I have found. It possible with help of create owning-ref. Interesting is it possible to reach the same result with help of standard Pin?

use byte_slice_cast::*;
use owning_ref::*;

fn main() {
    let context = Context::new();
    dbg!(&context);
    dbg!(context.dst.as_owner());
    dbg!(&*context.dst);
}

//

#[derive(Debug)]
struct Context {
    // pub dst_buffer : Box::< [ f32 ] >,
    // pub dst_buffer_bytes : &'a [ u8 ],
    pub dst: OwningRef<Box<[f32]>, [u8]>,
}

//

impl Context {
    fn new() -> Context {
        let len: usize = 2;
        let dst_buffer: Box<[f32]> = vec![0_f32; len].into_boxed_slice();
        // let dst_buffer_bytes = dst_buffer.as_byte_slice();

        let dst = OwningRef::new(dst_buffer);
        let dst = dst.map(|dst_buffer| dst_buffer.as_byte_slice());

        Context { dst }
        // Context { dst_buffer, dst_buffer_bytes }
    }
}

Playground

Kos
  • 1,547
  • 14
  • 23
  • 1
    Yes, you can do safe self-referential structs with that crate or `ouroboros` but doing this should not be generally encouraged especially to new people learning rust. This is not what experienced rust programmers would do straight away. – Hadus Nov 06 '21 at 15:32