简体   繁体   English

Rust:从 HashMap 可变值的 downcast_ref 返回 &mut 引用

[英]Rust: return &mut reference from downcast_ref of HashMap mutable value

As the title says, we have an application which runs wasm plugins.正如标题所说,我们有一个运行 wasm 插件的应用程序。 Each plugin can register their own State in the StateRegistry .每个插件都可以在State中注册自己的StateRegistry Then whenever the plugins are executed, they will modify their respective State .然后每当执行插件时,它们都会修改各自的State

The code below illustrates this:下面的代码说明了这一点:

use std::{collections::HashMap, any::Any};

type ContractId = String;
type GenericContractState = Box<dyn Any>;

// This will be WASM code
mod foo_contract {
    use super::StateRegistry;

    pub struct State {
    }

    pub fn update(states: &mut StateRegistry) {
        let state = states.states.get_mut(&"foo_contract".to_string()).unwrap();
        let state = state.downcast_mut::<State>().unwrap();
        // I'd prefer something like:
        // let state = state.lookup::<State>().unwrap()
    }
}

pub struct StateRegistry {
    pub states: HashMap<ContractId, GenericContractState>,
}

impl StateRegistry {
    fn new() -> Self {
        Self { states: HashMap::new() }
    }

    fn register(&mut self, contract_id: ContractId, state: GenericContractState) {
        self.states.insert(contract_id, state);
    }

    /*
    fn lookup<'a, S>(&'a mut self, contract_id: &ContractId) -> Option<StateRefWrapper<'a, S>> {
        match self.states.get_mut(contract_id) {
            Some(state) => {
                let ptr = state.downcast_mut::<S>();
                match ptr {
                    Some(ptr) => Some(StateRefWrapper { _mut: state, ptr }),
                    None => None,
                }
            }
            None => None,
        }
    }
    */
}

/*
struct StateRefWrapper<'a, S> {
    _mut: &'a mut Box<dyn Any>,
    ptr: &'a mut S,
}
*/

fn main() {
    let mut states = StateRegistry::new();
    let foo_state = Box::new(foo_contract::State {});
    states.register("foo_contract".to_string(), foo_state);

    foo_contract::update(&mut states);
}

The part I want to improve is that currently the plugin developer has to use this code to lookup their State in the registry:我要改进的部分是,目前插件开发人员必须使用此代码在注册表中查找他们的State

        let state = states.states.get_mut(&"foo_contract".to_string()).unwrap();
        let state = state.downcast_mut::<State>().unwrap();

I want to create a respective method in StateRegistry that is usable like this:我想在StateRegistry中创建一个可以像这样使用的相应方法:

        let state = state.lookup::<State>().unwrap()

My attempt (commented above) was something like this:我的尝试(上面评论)是这样的:

impl StateRegistry {
    // ...

    fn lookup<'a, S>(&'a mut self, contract_id: &ContractId) -> Option<StateRefWrapper<'a, S>> {
        match self.states.get_mut(contract_id) {
            Some(state) => {
                let ptr = state.downcast_mut::<S>();
                match ptr {
                    Some(ptr) => Some(StateRefWrapper { _mut: state, ptr }),
                    None => None,
                }
            }
            None => None,
        }
    }
}

struct StateRefWrapper<'a, S> {
    _mut: &'a mut Box<dyn Any>,
    ptr: &'a mut S,
}

How can I get this lookup() function working?我怎样才能让这个lookup() function 工作?

Thanks谢谢

You can't construct your StateRefWrapper in the way you want to, because it would contain two mutable borrows of the same value.您不能以您想要的方式构造您的StateRefWrapper ,因为它将包含两个具有相同值的可变借用。 You can, however, return just a &mut S which seems sufficient:但是,您可以只返回一个看起来足够的&mut S

fn lookup<'a, S: 'static>(&'a mut self, contract_id: &ContractId) -> Option<&'a mut S> {
    self.states
        .get_mut(contract_id)
        .and_then(|state| state.downcast_mut())
}

And use it like this:并像这样使用它:

pub fn update(states: &mut StateRegistry) {
    let state = states.lookup::<State>(&"foo_contract".to_string()).unwrap();
    // state.modify();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM