Home > Software engineering >  How can I allow multiple owners while enabeling mutation of value?
How can I allow multiple owners while enabeling mutation of value?

Time:10-07

I have an Enum, called NodeType which allows the values of Network(Network) or Mesh(Mesh). Both Network and Mesh are structs of unknown size. A Network Instance contains a 2D Vector of Node Structs, which contain a NodeType Enum, which allows for Networks to contain other Networks or Mesh structs. Meshes do some arbitrary function.

Consider the following Network which has a NodeType vector of size 1 x 3. with the contents being: [Mesh, Network0, Network1]. The first Element (Mesh), does something and is of no concern. The Second Element Network0 is created, and is assigned a NodeType(Mesh) on instantiation. As with the prior Network containing a Mesh, it is of no concern.

The Third Element Network1 is created the same way as Network0, with a NodeType(Mesh) defined on creation. However, we now want to append a new value to Network1's NodeType Vector. My issue is I am having trouble Assigning a value to a Struct that is Recursive and not the "Root" of the recursion loop. It is possible that a child Network May be referenced in more than one Parent Networks at any given time. I cannot perform a deep copy of these NodeType as it can potentially be (infinitely) large.

The Issue as I see it is a Node contains an Arc<RwLock>. But these are needed because Arc allows for many Networks to reference the same Struct instance, and RwLock allows management when threading.

Here are the Three structs used, as well as the main that instantiates the above scenario:

Node

#[derive(Debug)]
pub(crate) struct Node {
    guid: Uuid,
    node: Arc<RwLock<NodeType>>,
}

impl Node {
    pub(crate) fn new(subnet: NodeType) -> Node {
        Node {
            guid: Uuid::new_v4(),
            node: Arc::new(RwLock::new(subnet))
        }
    }

    pub(crate) fn node(self) -> Arc<RwLock<NodeType>> {
        self.node.clone()
    }
}

#[derive(Debug)]
pub(crate) enum NodeType {
    Network(Network),
    Mesh(Mesh),
}

Network

#[derive(Debug)]
pub(crate) struct Network {
    guid: Uuid,
    pub(crate) subnet: Vec<Vec<Node>>,
}

impl Network {
    pub(crate) fn new(subnet: NodeType) -> Network {
        Network {
            guid: Uuid::new_v4(),
            subnet: vec![vec![Node::new(subnet)]],
        }
    }
}

Mesh

#[derive(Debug, )]
pub(crate) struct Mesh {
    guid: Uuid,
}

impl Mesh {
    pub(crate) fn new() -> Mesh {
        Mesh {
            guid: Uuid::new_v4(),
        }
    }
}

Main

    //Creates A NodeType(Mesh)
    let a = NodeType::Mesh(Mesh::new());
    //Assigns the NodeType(Mesh) as the Second Element
    let mut agent0 = Network::new(a);

    //Creates a NodeType(Network) that Contains a Single Mesh
    let b = NodeType::Network(Network::new(NodeType::Mesh(Mesh::new())));
    //Assigns A NodeType(Network) that Contains a NodeType(Mesh) as the first element.
    agent0.subnet[0].push(Node::new(b));

    //Creates a NodeType(Network), Containing A NodeType(Mesh)
    let c = NodeType::Network(Network::new(NodeType::Mesh(Mesh::new())));
    //Assigns A NodeType(Network) that Contains a NodeType(Mesh) as the third element.
    agent0.subnet[0].push(Node::new(c));

    //An Attempt to append an additional Mesh to the Third Element's NodeType Vector. (Not Currently Working)
    let value = (*agent0.subnet[0][2].node()).get_mut();
    if let NodeType::Network(mut content) = value {
        // let d = NodeType::Mesh(Mesh::new());
        // content.subnet[0].push(Arc::new(RwLock::new(NodeType::Mesh(Mesh::new()))))
    }

The Error Received is:

let i = (*agent0.subnet[0][2].node()).get_mut();
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable

trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Arc<async_std::sync::RwLock<NodeType>>`

I hope I was clear with my question, I decided risking over-explaining versus the alternative.

CodePudding user response:

I think the problem here is that you have an Arc<RwLock<NodeType>> but you're trying to get_mut() when you only have a non-mutable reference. As the documentation for RwLock says,

use std::sync::RwLock;

let lock = RwLock::new(5);

// many reader locks can be held at once
{
    let r1 = lock.read().unwrap();
    let r2 = lock.read().unwrap();
    assert_eq!(*r1, 5);
    assert_eq!(*r2, 5);
} // read locks are dropped at this point

// only one write lock may be held, however
{
    let mut w = lock.write().unwrap();
    *w  = 1;
    assert_eq!(*w, 6);
} // write lock is dropped here

So what your code is missing is that the Arc only gives you a non-mutable reference to your RwLock which means you need to call write on it, and then unrwap() because of the possible results, as per the example above to get your mutable reference to the inner NodeType.

Edit: I think this is what you want in your final section. Not 100% sure though, as it doesn't clone your Arc but I think this is what you were trying to do:

    //An Attempt to append an additional Mesh to the Third Element's NodeType Vector.
    let mynode = &(agent0.subnet[0][2]);
    let mut locker = mynode.node.write().unwrap();
    if let NodeType::Network(content) = &mut *locker {
        let my_mesh_nodetype = NodeType::Mesh(Mesh::new());
        let my_fresh_node = Node::new(my_mesh_nodetype);
        content.subnet[0].push(my_fresh_node);
    }

Based on your comment in the code, I think this is correct.

  • Related