Search code examples
pointersrustraw

How to make raw pointer to parent struct in rust


sorry for my poor english I'm a new rust programer from c++ and trying to
make the job done.

Player has many sub module, and then usualy reffence each other. In c++ , we like to save a pointer to Player, so I can access other module or method easilly. I can't imagine how to orginze code under rust's safty check mechenism. Then I try to use raw pointer , but still failed. Here is my codes:


struct Task {
    id: u32,
    status: u32,
}

struct TaskMgr {
    tasks: Vec<Task>,
    pl: *mut Player
}

impl TaskMgr {
    fn get_owner(&mut self) -> &mut Player {
        unsafe {
            &mut *self.pl
        }
    }
    fn submit_task(&mut self, id: u32) {
        unsafe {
            (*self.pl).add_item(1000, 1);
        }
    }
    fn on_add_item(&mut self, id: u32, cnt: u32) {
        println!("task on add item {} {} items len:{}", id, cnt, self.tasks.len());
        self.tasks[0].status =2;
    }
}

struct Item {
    id: u32,
    cnt: u32,
}

struct ItemMgr {
    items: Vec<crate::Item>,
    pl: *mut Player
}

struct Player
{
    task_mgr: TaskMgr,
    item_mgr: ItemMgr,
}

impl Default for Player {
    fn default() -> Self {
        let mut r = Self {
            task_mgr: TaskMgr { tasks: vec![Task { id: 1, status: 0 }], pl: std::ptr::null_mut() },
            item_mgr: ItemMgr { items: vec![Item { id: 1000 , cnt: 1}],pl: std::ptr::null_mut() },
        };
        unsafe {
            r.task_mgr.pl = std::ptr::addr_of_mut!(r);
            r.item_mgr.pl = &mut r;
        }
        r
    }
}

impl Player {
    fn submit_task(&mut self, id: u32) {
        self.task_mgr.submit_task(id);
    }

    fn on_add_item(&mut self, id: u32, cnt: u32) {
        self.task_mgr.on_add_item(id, cnt);
    }

    fn add_item(&mut self, id: u32, cnt: u32) {
        let i = self.item_mgr.items.iter_mut().find(|x| x.id == id);
        if i.is_some() {
            i.unwrap().cnt += 1;
        }
        self.on_add_item(id, cnt);
    }
}

fn main() {
    let mut pl = Player::default();
    pl.submit_task(1);

}

output will be

task on add item 1000 2 items len:486381840784

items len is obviously wrong, why ? how to fix it std::ptr::addr_of_mut!(r) or *mut r both dont work if I move pointer assignment out of default() function, it sounds work.

    let mut pl = Player::default();
    unsafe {
        pl.task_mgr.pl = &mut pl as *mut Player;
        pl.item_mgr.pl = &mut pl as *mut Player;
    }

but this will make code hard to use how to assgin raw pointer when Player create


Solution

  • How to make raw pointer to parent struct in Rust?

    I think you can obtain a reference to the parent struct and then convert it to a raw pointer using the as keyword. Something like this:

    struct ParentStruct {
        value: i32,
    }
    
    struct ChildStruct {
        parent: *const ParentStruct,
    }
    
    fn main() {
        let parent = ParentStruct { value: 10 };
        let child = ChildStruct { parent: &parent as *const ParentStruct };
    
        // Accessing parent value through raw pointer in child.
        unsafe {
            let parent_ref = &*child.parent;
            println!("Parent value: {}", parent_ref.value);
        }
    }
    

    Docs: https://doc.rust-lang.org/std/keyword.as.html