0

I have a Vec<u8> named vec and a variable named x of type &dyn Trait. I want the data pointer of x to point to a position in vec.

#[derive(Debug)]
struct Point {
    x: u8,
    y: u8,
}

fn main() {
    let vec: Vec<u8> = vec![35, 1, 51, 10];

    let x: &dyn Debug;

    // create a &dyn Debug with its data pointer
    // pointing to vec[2] while the vtable points
    // to Point's implementation of Debug

    println!("{:?}", x); // expected output: "Point { x: 51, y: 10 }"
}

I'm trying to develop a virtual machine like the JVM. Every struct (Point, Line) that implements the desired trait (Display or Debug) will actually be an instruction (Add, Mov, ...) which will implement the trait Instruction, this trait contains the code of the instruction itself.

Here's another example that is closer to what I want to do:

use std::fmt::{self, Display};

struct Point {
    pub x: u8,
    pub y: u8,
}

impl Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

struct Line {
    pub start: Point,
    pub end: Point,
}

impl Display for Line {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.start, self.end)
    }
}

struct Data {
    vec: Vec<u8>,
    index: usize,
}

impl Data {
    fn new(vec: Vec<u8>) -> Self {
        Self { vec, index: 0 }
    }

    fn next(&mut self) -> Option<&dyn Display> {
        let obj;

        self.index += 1;

        match self.vec[self.index] {
            0 => {
                obj = Some(/* &Point { ... } with address equal to &(self.vec[self.index])*/);
                self.index += std::mem::size_of::<Point>();
            }

            1 => {
                obj = Some(/* &Line { ... } with address equal to &(self.vec[self.index])*/);
                self.index += std::mem::size_of::<Line>();
            }

            _ => {
                obj = None;
            }
        }

        obj
    }
}

fn main() {
    let raw_vec: Vec<u8> = vec![0, 24, 53, 1, 65, 103, 68, 10, 2];
    let data = Data::new(raw_vec);
    assert!(format!("{}", data.next().unwrap()) == "(24, 53)".to_string());
    assert!(format!("{}", data.next().unwrap()) == "((65, 103), (68, 10))".to_string());
}

Multiple structs of different length will share their data with the Vec<u8>. In this example, the memory layout of my structs may not match what I suppose they are, but this does not matter because their layout does not need to be known at compile time, but only at runtime. think of the Vec<u8> as the bytes read from a file by the program while the file itself was created by this same program.

How would I do that, even if it's unsafe or undefined behavior and without using smart pointers/heap allocation?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
R0T0M0L0T0V
  • 7
  • 1
  • 4
  • 1
    It looks like your question might be answered by the answers of [How to wrap a borrowed value in a newtype that is also a borrowed value?](https://stackoverflow.com/q/53999600/155423). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Nov 09 '20 at 15:04
  • [The duplicate applied to your situation](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=738421a39204e5c5d8cb115e2347fed2) – Shepmaster Nov 09 '20 at 15:18
  • 2
    _"How would I do that, even if it's unsafe or undefined behavior?"_ -- you mean, how can you make this sometimes work, sometimes segfault, sometimes just give random data and sometimes cause unexpected bugs in unrelated parts of your program? – Peter Hall Nov 09 '20 at 15:19
  • *can also suppose I know for certain the data layout of `Point`* — you do not, based on this code. `repr(Rust)` has no guarantees about layout. – Shepmaster Nov 09 '20 at 15:34
  • [The duplicate applied to your *modified* situation](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=37d6d5885b8f4cbb6bde870acf5293b5) – Shepmaster Nov 09 '20 at 15:37
  • Your latest update doesn't attempt to explain why the marked duplicates (along with the duplicates applied to your situation) are not correct. – Shepmaster Nov 09 '20 at 16:29
  • See also [Transmuting u8 buffer to struct in Rust](https://stackoverflow.com/q/42499049/155423); [Can I take a byte array and deserialize it into a struct?](https://stackoverflow.com/q/36061560/155423); [How to read a struct from a file in Rust?](https://stackoverflow.com/q/25410028/155423) – Shepmaster Nov 09 '20 at 16:30

0 Answers0