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.
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
I have a simple example game entity called a Nation, which is a struct that contains all the data relevant to the player's assets and activities. The player is allowed to change their nation name, which is used to log in and take their turns. Thus, the player has to have a unique identifier that doesn't change.
There are also other things in the game system which similarly need unique identifiers, so to my dinosaur C brain, the obvious solution was to try making a global HashMap to contain the struct name as a key, and the instance count... and then auto-increment that counter whenever a new struct is created, using the current value as the ID.
Rust really hates me for trying that, which is fine. But, I'd like to learn a more proper way to accomplish this. Since I have to implement Default for these anyways, putting the increment and then assignment in the default() function seems like the right place to use it, but the counters themselves need to live somewhere accessible to those functions.
Right now, I have this, which is ugly but seems to work, so far:
static mut nation_id : i64 = 0;
#[derive(Debug)]
struct Nation {
id : i64, // unique naiton ID, established at allocation
name : String, // the nation name, entered at runtime
// more stuff here...
}
impl Default for Nation {
fn default() -> Nation {
unsafe {
nation_id += 1;
Nation {
id: nation_id, // We want this to actually come from a counter
name: String::from(""),
// more stuff here...
}
}
}
}
// World just holds a Vec<Nation> that is initialized to new() and thus empty.
fn main() {
println!("This is just a test.");
let mut w : World = Default::default();
println!("{:?}", w);
println!("{} nations exist.", w.nations.len());
let mut n : Nation = Default::default();
println!("{:?}", n);
w.nations.push(n);
println!("{} nations exist.", w.nations.len());
let mut n2 : Nation = Default::default();
println!("{:?}", n2);
w.nations.push(n2);
println!("{} nations exist.", w.nations.len());
println!("Test completed.");
}
If you want a counter, one way to do that is to use atomics. This function will return a counter and can work on multiple threads concurrently.
use std::sync::atomic::AtomicU64;
use std::sync::atomic::Ordering::SeqCst;
pub fn unique_id() -> u64 {
static COUNTER: AtomicU64 = AtomicU64::new(0);
COUNTER.fetch_add(1, SeqCst)
}
We can also improve it by enforcing that ids must be unique.
pub fn unique_id() -> u64 {
static COUNTER: AtomicU64 = AtomicU64::new(0);
let id = COUNTER.fetch_add(1, SeqCst);
assert_ne!(id, u64::MAX, "ID counter has overflowed and is no longer unique");
id
}
Rust Playground
There is a blog post about Rust, where it is explained why Rust can't have self-referencing members.
There is an example with a slice storing offset and length instead of the pointer. I want to apply this to an object, where different parts need references to other parts.
Let's say the object looks like this:
struct Whole {
struct Part0 { //members}
struct Part1 {
needs reference to part 0
}
struct Part2 {
needs reference to part 1 and part 0
}
}
So, Whole can move around in memory (e.g., it can be stored in a vector). But in my scenario, Part1 and Part2 are always inside the Whole (and it is known at compile time). Also, Part1 always needs reference to the Whole it is currently part of. Thus Part 1 should be able to reference Part 0 by calculating its offset from Part 1's self.
I want to make a "reference" that stores offset of Part0 relative from Part1, so that Part1 can get a reference to Part0 by taking this offset from its 'self'.
You could just use Rc:
use std::rc::Rc;
struct Part0 {}
struct Part1 {
at_0: Rc<Part0>,
}
struct Part2 {
at_0: Rc<Part0>,
at_1: Rc<Part1>,
}
struct Whole {
at_0: Rc<Part0>,
at_1: Rc<Part1>,
at_2: Rc<Part2>,
}
fn main() {
let at_0 = Rc::new(Part0 {});
let at_1 = Rc::new(Part1 { at_0: at_0.clone() });
let at_2 = Rc::new(Part2 {
at_0: at_0.clone(),
at_1: at_1.clone(),
});
let _ = Whole { at_0, at_1, at_2 };
}
Playground
But in my scenario, Part1 and Part2 are always inside the Whole (and it is known at compile time).
In that case, there's no reason for Part1 and Part2 to be structs of their own: their fields could instead be defined directly on Whole. Defining them as structs of their own might have made sense if that encapsulated some sub-behaviour, but the fact these parts need access to their siblings belies the suitability of such an approach.
If, for some reason, Part1 and Part2 must nevertheless remain as structs in their own right, then you could:
Pass a reference to the relevant sibling into any method that requires it:
impl Part1 {
fn do_something(&self, part0: &Part0) {
// do whatever with self and part0
}
}
and/or
Implement relevant behaviours on Whole rather than the sub-part:
impl Whole {
fn do_something(&self) {
// do whatever with self.part1 and self.part0
}
}
Of course, using unsafe code, it is nevertheless possible to discover the layout of a struct and access its members in the manner that you describe: I just don't see it being useful for the scenario described in this question. Nevertheless...
Ideally you'd want to embed knowledge of the layout of Whole's members directly into your compiled code. Unfortunately, because rustc does not directly provide means by which the layout of a struct's members can be discovered during compilation, the only way this could be done is by manually calculating the position of each member. However, as documented in The Default Representation in The Rust Reference (emphasis added):
Nominal types without a repr attribute have the default representation. Informally, this representation is also called the rust representation.
There are no guarantees of data layout made by this representation.
Consequently, if Whole is using Rust's default representation, it is impossible to determine the layout of its members during compilation (however, if Whole uses The C Representation, which guarantees a particular layout of a struct's members, one can manually calculate their positions at compile-time, which the repr_offset crate greatly simplifies); instead, the layout of Whole's members can be determined at runtime:
use std::ptr;
impl Whole {
fn new() -> Self {
let mut me = Self { ... };
unsafe {
let addr_of_part0 = ptr::addr_of!(me.part0).cast::<u8>();
let addr_of_part1 = ptr::addr_of!(me.part1).cast::<u8>();
let addr_of_part2 = ptr::addr_of!(me.part2).cast::<u8>();
me.part1.offset_to_part0 = addr_of_part0.offset_from(addr_of_part1);
me.part2.offset_to_part0 = addr_of_part0.offset_from(addr_of_part2);
me.part2.offset_to_part1 = addr_of_part1.offset_from(addr_of_part2);
}
me
}
}
And then one can do:
impl Part1 {
unsafe fn part0(&self) -> &Part0 {
let addr_of_self = ptr::addr_of!(*self).cast::<u8>();
let addr_of_part0 = addr_of_self.offset(self.offset_of_part0);
&*addr_of_part0.cast()
}
}
impl Part2 {
unsafe fn part0(&self) -> &Part0 {
let addr_of_self = ptr::addr_of!(*self).cast::<u8>();
let addr_of_part0 = addr_of_self.offset(self.offset_of_part0);
&*addr_of_part0.cast()
}
unsafe fn part1(&self) -> &Part1 {
let addr_of_self = ptr::addr_of!(*self).cast::<u8>();
let addr_of_part1 = addr_of_self.offset(self.offset_of_part1);
&*addr_of_part1.cast()
}
}
Note that these functions are unsafe because they rely on you, the programmer, only invoking them when you know that the respective offset_of_... fields are valid offsets to the relevant type that can be dereferenced into a shared pointer with the same lifetime as self. You likely will only ever be able to guarantee this when you are accessing self through an owning Whole, otherwise you could easily end up violating memory safety and triggering undefined behaviour—#Netwave's suggestion of using refcounted ownership is one thoroughly sensible way to avoid this risk.
you can use some black magic of unsafe, and encapsulate the logic private to your struct promise SAFETY internally
#[derive(Debug)]
struct Part0 {
data: Vec<u8>,
}
struct Part1 {
pdata0: NonNull<Part0>
}
struct Part2 {
pdata0: NonNull<Part0>,
pdata1: NonNull<Part1>,
}
struct Whole {
p0: Part0,
p1: Part1,
p2: Part2,
}
impl Whole {
fn new() -> Pin<Box<Self>> {
// init Whole with NonNull
let res = Self {
p0: Part0 {
data: vec![1, 2, 3],
},
p1: Part1 {
pdata0: NonNull::dangling(),
},
p2: Part2 {
pdata0: NonNull::dangling(),
pdata1: NonNull::dangling(),
},
};
// get boxed Whole
let mut boxed = Box::pin(res);
// get rawpointer of p0
let ref0 = NonNull::from(&boxed.p0);
// set p0 to p1.pdata0
let mut_ref = (&mut boxed).as_mut();
mut_ref.get_mut().p1 = Part1 {
pdata0: ref0
};
let ref1 = NonNull::from(&boxed.p1);
let mut_ref = (&mut boxed).as_mut();
mut_ref.get_mut().p2 = Part2 {
pdata0: ref0,
pdata1: ref1,
};
boxed
}
fn use_p1(self: &Pin<Box<Self>>) {
unsafe {println!("{:?}", self.p1.pdata0.as_ref())}
}
}
fn main() {
let mut h = Whole::new();
h.use_p1();
}
I've been playing with Rust for the past few days,
and I'm still struggling with the memory management (figures).
I wrote a simple project that creates a hierarchy of structs ("keywords") from lexing/parsing a text file.
A keyword is defined like this:
pub struct Keyword<'a> {
name: String,
code: u32,
parent: Option<&'a Keyword<'a>>,
}
which is my equivalent for this C struct:
typedef struct Keyword Keyword;
struct Keyword {
char* name;
unsigned int code;
Keyword* parent;
};
A hierarchy is just a container for keywords, defined like this:
pub struct KeywordHierarchy<'a> {
keywords: Vec<Box<Keyword<'a>>>,
}
impl<'a> KeywordHierarchy<'a> {
fn add_keyword(&mut self, keyword: Box<Keyword<'a>>) {
self.keywords.push(keyword);
}
}
In the parse function (which is a stub of the complete parser), I recreated the condition that spawns the lifetime error in my code.
fn parse<'a>() -> Result<KeywordHierarchy<'a>, String> {
let mut hierarchy = KeywordHierarchy { keywords: Vec::new() };
let mut first_if = true;
let mut second_if = false;
while true {
if first_if {
// All good here.
let root_keyword = Keyword {
name: String::from("ROOT"),
code: 0,
parent: None,
};
hierarchy.add_keyword(Box::new(root_keyword));
first_if = false;
second_if = true;
}
if second_if {
// Hierarchy might have expired here?
// Find parent
match hierarchy.keywords.iter().find(|p| p.code == 0) {
None => return Err(String::from("No such parent")),
Some(parent) => {
// If parent is found, create a child
let child = Keyword {
name: String::from("CHILD"),
code: 1,
parent: Some(&parent),
};
hierarchy.add_keyword(Box::new(child));
}
}
second_if = false;
}
if !first_if && !second_if {
break;
}
}
Ok(hierarchy)
}
There's a while loop that goes through the lexer tokens.
In the first if, I add the ROOT keyword to the hierarchy, which is the only one that doesn't have a parent, and everything goes smoothly as expected.
In the second if, I parse the children keywords and I get a lifetime error when invoking KeywordHierarchy.add_keyword().
hierarchy.keywords` does not live long enough
Could you guys recommend an idiomatic way to fix this?
Cheers.
P.S. Click here for the playground
The immediate problem I can see with your design is that your loop is going to modify the hierarchy.keywords vector (in the first_if block), but it also borrows elements from the hierarchy.keywords vector (in the second_if block).
This is problematic, because modifying a vector may cause its backing buffer to be reallocated, which, if it were allowed, would invalidate all existing borrows to the vector. (And thus it is not allowed.)
Have you considered using an arena to hold your keywords instead of a Vec? Arenas are designed so that you can allocate new things within them while still having outstanding borrows to elements previously allocated within the arena.
Update: Here is a revised version of your code that illustrates using an arena (in this case a rustc_arena::TypedArena, but that's just so I can get this running on the play.rust-lang.org service) alongside a Vec<&Keyword> to handle the lookups.
https://play.rust-lang.org/?gist=fc6d81cb7efa7e4f32c481ab6482e587&version=nightly&backtrace=0
The crucial bits of code are this:
First: the KeywordHierarchy now holds a arena alongside a vec:
pub struct KeywordHierarchy<'a> {
keywords: Vec<&'a Keyword<'a>>,
kw_arena: &'a TypedArena<Keyword<'a>>,
}
Second: Adding a keyword now allocates the spot in the arena, and stashes a reference to that spot in the vec:
fn add_keyword(&mut self, keyword: Keyword<'a>) {
let kw = self.kw_arena.alloc(keyword);
self.keywords.push(kw);
}
Third: the fn parse function now takes an arena (reference) as input, because we need the arena to outlive the stack frame of fn parse:
fn parse<'a>(arena: &'a TypedArena<Keyword<'a>>) -> Result<KeywordHierarchy<'a>, String> {
...
Fourth: To avoid borrow-checker issues with borrowing hierarchy as mutable while also iterating over it, I moved the hierarchy modification outside of your Find parent match:
// Find parent
let parent = match hierarchy.keywords.iter().find(|p| p.code == 0) {
None => return Err(String::from("No such parent")),
Some(parent) => *parent, // (this deref is important)
};
// If parent is found, create a child
let child = Keyword {
name: String::from("CHILD"),
code: 1,
parent: Some(parent),
};
hierarchy.add_keyword(child);
second_if = false;
I'm trying to create a struct that takes a Path and, on demand, loads the image from the path specified. Here's what I have so far:
extern crate image;
use std::cell::{RefCell};
use std::path::{Path};
use image::{DynamicImage};
pub struct ImageCell<'a> {
image: RefCell<Option<DynamicImage>>,
image_path: &'a Path,
}
impl<'a> ImageCell<'a> {
pub fn new<P: AsRef<Path>>(image_path: &'a P) -> ImageCell<'a>{
ImageCell { image: RefCell::new(None), image_path: image_path.as_ref() }
}
//copied from https://doc.rust-lang.org/nightly/std/cell/index.html#implementation-details-of-logically-immutable-methods
pub fn get_image(&self) -> &DynamicImage {
{
let mut cache = self.image.borrow_mut();
if cache.is_some() {
return cache.as_ref().unwrap(); //Error here
}
let image = image::open(self.image_path).unwrap();
*cache = Some(image);
}
self.get_image()
}
}
This fails to compile:
src/image_generation.rs:34:24: 34:29 error: `cache` does not live long enough
src/image_generation.rs:34 return cache.as_ref().unwrap();
^~~~~
src/image_generation.rs:30:46: 42:6 note: reference must be valid for the anonymous lifetime #1 defined on the block at 30:45...
src/image_generation.rs:30 pub fn get_image(&self) -> &DynamicImage {
src/image_generation.rs:31 {
src/image_generation.rs:32 let mut cache = self.image.borrow_mut();
src/image_generation.rs:33 if cache.is_some() {
src/image_generation.rs:34 return cache.as_ref().unwrap();
src/image_generation.rs:35 }
...
src/image_generation.rs:32:53: 39:10 note: ...but borrowed value is only valid for the block suffix following statement 0 at 32:52
src/image_generation.rs:32 let mut cache = self.image.borrow_mut();
src/image_generation.rs:33 if cache.is_some() {
src/image_generation.rs:34 return cache.as_ref().unwrap();
src/image_generation.rs:35 }
src/image_generation.rs:36
src/image_generation.rs:37 let image = image::open(self.image_path).unwrap();
...
I think I understand why because the lifetime of cache is tied to borrow_mut().
Is there anyway to structure the code so that this works?
I'm not totally convinced you need interior mutability here. However, I do think the solution you've proposed is generally useful, so I'll elaborate on one way to achieve it.
The problem with your current code is that RefCell provides dynamic borrowing semantics. In other words, borrowing the contents of a RefCell is opaque to Rust's borrow checker. The problem is, when you try to return a &DynamicImage while it still lives inside the RefCell, it is impossible for the RefCell to track its borrowing status. If a RefCell allowed that to happen, then other code could overwrite the contents of the RefCell while there was a loan out of &DynamicImage. Whoops! Memory safety violation.
For this reason, borrowing a value out of a RefCell is tied to the lifetime of the guard you get back when you call borrow_mut(). In this case, the lifetime of the guard is the stack frame of get_image, which no longer exists after the function returns. Therefore, you cannot borrow the contents of a RefCell like you're doing.
An alternative approach (while maintaining the requirement of interior mutability) is to move values in and out of the RefCell. This enables you to retain cache semantics.
The basic idea is to return a guard that contains the dynamic image along with a pointer back to the cell it originated from. Once you're done with the dynamic image, the guard will be dropped and we can add the image back to the cell's cache.
To maintain ergonomics, we impl Deref on the guard so that you can mostly pretend like it is a DynamicImage. Here's the code with some comments and a few other things cleaned up:
use std::cell::RefCell;
use std::io;
use std::mem;
use std::ops::Deref;
use std::path::{Path, PathBuf};
struct ImageCell {
image: RefCell<Option<DynamicImage>>,
// Suffer the one time allocation into a `PathBuf` to avoid dealing
// with the lifetime.
image_path: PathBuf,
}
impl ImageCell {
fn new<P: Into<PathBuf>>(image_path: P) -> ImageCell {
ImageCell {
image: RefCell::new(None),
image_path: image_path.into(),
}
}
fn get_image(&self) -> io::Result<DynamicImageGuard> {
// `take` transfers ownership out from the `Option` inside the
// `RefCell`. If there was no value there, then generate an image
// and return it. Otherwise, move the value out of the `RefCell`
// and return it.
let image = match self.image.borrow_mut().take() {
None => {
println!("Opening new image: {:?}", self.image_path);
try!(DynamicImage::open(&self.image_path))
}
Some(img) => {
println!("Retrieving image from cache: {:?}", self.image_path);
img
}
};
// The guard provides the `DynamicImage` and a pointer back to
// `ImageCell`. When it's dropped, the `DynamicImage` is added
// back to the cache automatically.
Ok(DynamicImageGuard { image_cell: self, image: image })
}
}
struct DynamicImageGuard<'a> {
image_cell: &'a ImageCell,
image: DynamicImage,
}
impl<'a> Drop for DynamicImageGuard<'a> {
fn drop(&mut self) {
// When a `DynamicImageGuard` goes out of scope, this method is
// called. We move the `DynamicImage` out of its current location
// and put it back into the `RefCell` cache.
println!("Adding image to cache: {:?}", self.image_cell.image_path);
let image = mem::replace(&mut self.image, DynamicImage::empty());
*self.image_cell.image.borrow_mut() = Some(image);
}
}
impl<'a> Deref for DynamicImageGuard<'a> {
type Target = DynamicImage;
fn deref(&self) -> &DynamicImage {
// This increases the ergnomics of a `DynamicImageGuard`. Because
// of this impl, most uses of `DynamicImageGuard` can be as if
// it were just a `&DynamicImage`.
&self.image
}
}
// A dummy image type.
struct DynamicImage {
data: Vec<u8>,
}
// Dummy image methods.
impl DynamicImage {
fn open<P: AsRef<Path>>(_p: P) -> io::Result<DynamicImage> {
// Open image on file system here.
Ok(DynamicImage { data: vec![] })
}
fn empty() -> DynamicImage {
DynamicImage { data: vec![] }
}
}
fn main() {
let cell = ImageCell::new("foo");
{
let img = cell.get_image().unwrap(); // opens new image
println!("image data: {:?}", img.data);
} // adds image to cache (on drop of `img`)
let img = cell.get_image().unwrap(); // retrieves image from cache
println!("image data: {:?}", img.data);
} // adds image back to cache (on drop of `img`)
There is a really important caveat to note here: This only has one cache location, which means if you call get_image a second time before the first guard has been dropped, then a new image will be generated from scratch since the cell will be empty. This semantic is hard to change (in safe code) because you've committed to a solution that uses interior mutability. Generally speaking, the whole point of interior mutability is to mutate something without the caller being able to observe it. Indeed, that should be the case here, assuming that opening an image always returns precisely the same data.
This approach can be generalized to be thread safe (by using Mutex for interior mutability instead of RefCell) and possibly more performant by choosing a different caching strategy depending on your use case. For example, the regex crate uses a simple memory pool to cache compiled regex state. Since this caching should be opaque to callers, it is implemented with interior mutability using precisely the same mechanism outlined here.
In my code I have a mutually recursive tree structure which looks something like the following:
enum Child<'r> {
A(&'r Node<'r>),
B,
C
}
struct Node<'r> {
children : [&'r Child<'r>,..25]
}
impl <'r>Node<'r> {
fn new() -> Node {
Node {
children : [&B,..25]
}
}
}
but it doesn't compile as-is. What is the best way to modify it to make it do so?
Here is a version where the nodes can be modified from outside the tree, which I presume is what was asked for.
use std::rc::Rc;
use std::cell::RefCell;
struct Node {
a : Option<Rc<RefCell<Node>>>,
b : Option<Rc<RefCell<Node>>>,
value: int
}
impl Node {
fn new(value: int) -> Rc<RefCell<Node>> {
let node = Node {
a: None,
b: None,
value: value
};
Rc::new(RefCell::new(node))
}
}
fn main() {
let first = Node::new(0);
let second = Node::new(0);
let third = Node::new(0);
first.borrow_mut().a = Some(second.clone());
second.borrow_mut().a = Some(third.clone());
second.borrow_mut().value = 1;
third.borrow_mut().value = 2;
println!("Value of second: {}", first.borrow().a.get_ref().borrow().value);
println!("Value of third: {}", first.borrow().a.get_ref().borrow().a.get_ref().borrow().value);
}
Rc is a reference counted pointer and allows a single object to have multiple owners. It doesn't allow mutation however, so a RefCell is required which allows runtime checked mutable borrowing. That's why the code uses Rc<RefCell<Node>>. The Option type is used to represent potential children with Option<Rc<RefCell<Node>>>.
Since, the Rc type auto dereferences, it's possible to directly call RefCell methods on it. These are borrow() and borrow_mut() which return a reference and mutable reference to the underlying Node. There also exist try_borrow() and try_borrow_mut() variants which cannot fail.
get_ref() is a method of the Option type which returns a reference to the underlying Rc<RefCell<Node>>. In a real peogram we would probably want to check whether the Option contains anything beforehand.
Why does the original code not work? References &T imply non-ownership, so something else would have to own the Nodes. While it would be possible to build a tree of &Node types, it wouldn't be possible to modify the Nodes outside of the tree because once borrowed, an object cannot be modified by anything else than the borrowing object.