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
Related
I've come across a problem that requires doing DFS on a tree defined like such:
pub struct TreeNode {
pub val: i32,
pub left: Option<Rc<RefCell<TreeNode>>>,
pub right: Option<Rc<RefCell<TreeNode>>>,
}
I want to use the non-recursive version of the algorithm with an explicit stack. The tree is read-only and the values in the tree are not guaranteed to be unique (they can't be used to identify a node).
Problem is, that the iterative version requires a visited data structure. Normally, in C++, I'd just use an std::set with node pointers for implementing visited. How would I do the same (or analogous) in Rust? There doesn't seem to be an easy way to get a pointer to an object that I can use in a set.
First off, we don't need to keep track of visited if we know there are no circular dependencies. Normally binary trees don't have circular dependencies so we may be able to assume it simply is not an issue. In this case, we can use a VecDeque as our 'stack' queue.
type TreeNodeRef = Rc<RefCell<TreeNode>>;
pub struct TreeNode {
pub val: i32,
pub left: Option<TreeNodeRef>,
pub right: Option<TreeNodeRef>,
}
pub fn dfs(root: TreeNodeRef, target: i32) -> Option<TreeNodeRef> {
let mut queue = VecDeque::new();
queue.push_back(root);
while let Some(node) = queue.pop_front() {
// Check if this is the node we are looking for
if node.borrow().val == target {
return Some(node)
}
// Add left and write to the back of the queue for DFS
let items = node.borrow();
if let Some(left) = &items.left {
queue.push_front(left.clone());
}
if let Some(right) = &items.right {
queue.push_front(right.clone());
}
}
// Search completed and node was not found
None
}
However, if we need to keep a list of visited nodes, we can cheat a little. An Rc<T> is just a boxed value with a reference count so we can extract a pointer from it. Even though we can not compare TreeNodes, we can store where they are kept in memory. When we do that, the solution looks like this:
pub fn dfs(root: TreeNodeRef, target: i32) -> Option<TreeNodeRef> {
let mut visited = HashSet::new();
let mut queue = VecDeque::new();
queue.push_back(root);
while let Some(node) = queue.pop_front() {
// Check node has not been visited yet
if visited.contains(&Rc::as_ptr(&node)) {
continue
}
// Insert node to visited list
visited.insert(Rc::as_ptr(&node));
if node.borrow().val == target {
return Some(node)
}
let items = node.borrow();
if let Some(left) = &items.left {
queue.push_front(left.clone());
}
if let Some(right) = &items.right {
queue.push_front(right.clone());
}
}
None
}
Rust Playground
You may also find it interesting to look at the bottom 2 code examples in this answer to see how a generic search method could be made.
Edit: Alternatively, here is a Rust Playground of how this could be done with a regular Vec and Rc::clone(x) as recommended by #isaactfa.
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 know why Rust doesn't like my code. However, I don't know what would be the idiomatic Rust approach to the problem.
I'm a C# programmer, and while I feel I understand Rust's system, I think my "old" approach to some problems don't work in Rust at all.
This code reproduces the problem I'm having, and it probably doesn't look like idiomatic Rust (or maybe it doesn't even look good in C# as well):
//a "global" container for the elements and some extra data
struct Container {
elements: Vec<Element>,
global_contextual_data: i32,
//... more contextual data fields
}
impl Container {
//this just calculates whatever I need based on the contextual data
fn calculate_contextual_data(&self) -> i32 {
//This function will end up using the elements vector and the other fields as well,
//and will do some wacky maths with it.
//That's why I currently have the elements stored in the container
}
}
struct Element {
element_data: i32,
//other fields
}
impl Element {
//I need to take a mutable reference to update element_data,
//and a reference to the container to calculate something that needs
//this global contextual data... including the other elements, as previously stated
fn update_element_data(&mut self, some_data: i32, container: &Container) {
self.element_data *= some_data + container.calculate_contextual_data() //do whatever maths I need
}
}
fn main(){
//let it be mutable so I can assign the elements later
let mut container = Container {
elements: vec![],
global_contextual_data: 1
};
//build a vector of elements
let elements = vec![
Element {
element_data: 5
},
Element {
element_data: 7
}
];
//this works
container.elements = elements;
//and this works, but container is now borrowed as mutable
for elem in container.elements.iter_mut() {
elem.element_data += 1; //and while this works
let some_data = 2;
//i can't borrow it as immutable here and pass to the other function
elem.update_element_data(some_data, &container);
}
}
I understand why elem.update_element_data(some_data, &container); won't work: I'm already borrowing it as mutable when I call iter_mut. Maybe each element should have a reference to the container? But then wouldn't I have more opportunities to break at borrow-checking?
I don't think it's possible to bring my old approach to this new system. Maybe I need to rewrite the whole thing. Can someone point me to the right direction? I've just started programming in Rust, and while the ownership system is making some sort of sense to me, the code I should write "around" it is still not that clear.
I came across this question:
What's the Rust way to modify a structure within nested loops? which gave me insight into my problem.
I revisited the problem and boiled the problem down to the sharing of the vector by borrowing for writes and reads at the same time. This is just forbidden by Rust. I don't want to circumvent the borrow checker using unsafe. I was wondering, though, how much data should I copy?
My Element, which in reality is the entity of a game (I'm simulating a clicker game) has both mutable and immutable properties, which I broke apart.
struct Entity {
type: EntityType,
starting_price: f64,
...
...
status: Cell<EntityStatus>
}
Every time I need to change the status of an entity, I need to call get and set methods on the status field. EntityStatus derives Clone, Copy.
I could even put the fields directly on the struct and have them all be Cells but then it would be cumbersome to work with them (lots of calls to get and set), so I went for the more aesthetically pleasant approach.
By allowing myself to copy the status, edit and set it back, I could borrow the array immutably twice (.iter() instead of .iter_mut()).
I was afraid that the performance would be bad due to the copying, but in reality it was pretty good once I compiled with opt-level=3. If it gets problematic, I might change the fields to be Cells or come up with another approach.
Just do the computation outside:
#[derive(Debug)]
struct Container {
elements: Vec<Element>
}
impl Container {
fn compute(&self) -> i32 {
return 42;
}
fn len(&self) -> usize {
return self.elements.len();
}
fn at_mut(&mut self, index: usize) -> &mut Element {
return &mut self.elements[index];
}
}
#[derive(Debug)]
struct Element {
data: i32
}
impl Element {
fn update(&mut self, data: i32, computed_data: i32) {
self.data *= data + computed_data;
}
}
fn main() {
let mut container = Container {
elements: vec![Element {data: 1}, Element {data: 3}]
};
println!("{:?}", container);
for i in 0..container.len() {
let computed_data = container.compute();
container.at_mut(i).update(2, computed_data);
}
println!("{:?}", container);
}
Another option is to add an update_element to your container:
#[derive(Debug)]
struct Container {
elements: Vec<Element>
}
impl Container {
fn compute(&self) -> i32 {
let sum = self.elements.iter().map(|e| {e.data}).reduce(|a, b| {a + b});
return sum.unwrap_or(0);
}
fn len(&self) -> usize {
return self.elements.len();
}
fn at_mut(&mut self, index: usize) -> &mut Element {
return &mut self.elements[index];
}
fn update_element(&mut self, index: usize, data: i32) {
let computed_data = self.compute();
self.at_mut(index).update(data, computed_data);
}
}
#[derive(Debug)]
struct Element {
data: i32
}
impl Element {
fn update(&mut self, data: i32, computed_data: i32) {
self.data *= data + computed_data;
}
}
fn main() {
let mut container = Container {
elements: vec![Element {data: 1}, Element {data: 3}]
};
println!("{:?}", container);
for i in 0..container.len() {
let computed_data = container.compute();
container.at_mut(i).update(2, computed_data);
}
println!("{:?}", container);
for i in 0..container.len() {
container.update_element(i, 2);
}
println!("{:?}", container);
}
Try it!
I'm coming from mostly OOP languages, so getting this concept to work in Rust kinda seems hard. I want to implement a basic counter that keeps count of how many "instances" I've made of that type, and keep them in a vector for later use.
I've tried many different things, first was making a static vector variable, but that cant be done due to it not allowing static stuff that have destructors.
This was my first try:
struct Entity {
name: String,
}
struct EntityCounter {
count: i64,
}
impl Entity {
pub fn init() {
let counter = EntityCounter { count: 0 };
}
pub fn new(name: String) {
println!("Entity named {} was made.", name);
counter += 1; // counter variable unaccessable (is there a way to make it global to the struct (?..idek))
}
}
fn main() {
Entity::init();
Entity::new("Hello".to_string());
}
Second:
struct Entity {
name: String,
counter: i32,
}
impl Entity {
pub fn new(self) {
println!("Entity named {} was made.", self.name);
self.counter = self.counter + 1;
}
}
fn main() {
Entity::new(Entity { name: "Test".to_string() });
}
None of those work, I was just trying out some concepts on how I could be able to implement such a feature.
Your problems appear to be somewhat more fundamental than what you describe. You're kind of throwing code at the wall to see what sticks, and that's simply not going to get you anywhere. I'd recommend reading the Rust Book completely before continuing. If you don't understand something in it, ask about it. As it stands, you're demonstrating you don't understand variable scoping, return types, how instance construction works, how statics work, and how parameters are passed. That's a really shaky base to try and build any understanding on.
In this particular case, you're asking for something that's deliberately not straightforward. You say you want a counter and a vector of instances. The counter is simple enough, but a vector of instances? Rust doesn't allow easy sharing like other languages, so how you go about doing that depends heavily on what it is you're actually intending to use this for.
What follows is a very rough guess at something that's maybe vaguely similar to what you want.
/*!
Because we need the `lazy_static` crate, you need to add the following to your
`Cargo.toml` file:
```cargo
[dependencies]
lazy_static = "0.2.1"
```
*/
#[macro_use] extern crate lazy_static;
mod entity {
use std::sync::{Arc, Weak, Mutex};
use std::sync::atomic;
pub struct Entity {
pub name: String,
}
impl Entity {
pub fn new(name: String) -> Arc<Self> {
println!("Entity named {} was made.", name);
let ent = Arc::new(Entity {
name: name,
});
bump_counter();
remember_instance(ent.clone());
ent
}
}
/*
The counter is simple enough, though I'm not clear on *why* you even want
it in the first place. You don't appear to be using it for anything...
*/
static COUNTER: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;
fn bump_counter() {
// Add one using the most conservative ordering.
COUNTER.fetch_add(1, atomic::Ordering::SeqCst);
}
pub fn get_counter() -> usize {
COUNTER.load(atomic::Ordering::SeqCst)
}
/*
There are *multiple* ways of doing this part, and you simply haven't given
enough information on what it is you're trying to do. This is, at best,
a *very* rough guess.
`Mutex` lets us safely mutate the vector from any thread, and `Weak`
prevents `INSTANCES` from keeping every instance alive *forever*. I mean,
maybe you *want* that, but you didn't specify.
Note that I haven't written a "cleanup" function here to remove dead weak
references.
*/
lazy_static! {
static ref INSTANCES: Mutex<Vec<Weak<Entity>>> = Mutex::new(vec![]);
}
fn remember_instance(entity: Arc<Entity>) {
// Downgrade to a weak reference. Type constraint is just for clarity.
let entity: Weak<Entity> = Arc::downgrade(&entity);
INSTANCES
// Lock mutex
.lock().expect("INSTANCES mutex was poisoned")
// Push entity
.push(entity);
}
pub fn get_instances() -> Vec<Arc<Entity>> {
/*
This is about as inefficient as I could write this, but again, without
knowing your access patterns, I can't really do any better.
*/
INSTANCES
// Lock mutex
.lock().expect("INSTANCES mutex was poisoned")
// Get a borrowing iterator from the Vec.
.iter()
/*
Convert each `&Weak<Entity>` into a fresh `Arc<Entity>`. If we
couldn't (because the weak ref is dead), just drop that element.
*/
.filter_map(|weak_entity| weak_entity.upgrade())
// Collect into a new `Vec`.
.collect()
}
}
fn main() {
use entity::Entity;
let e0 = Entity::new("Entity 0".to_string());
println!("e0: {}", e0.name);
{
let e1 = Entity::new("Entity 1".to_string());
println!("e1: {}", e1.name);
/*
`e1` is dropped here, which should cause the underlying `Entity` to
stop existing, since there are no other "strong" references to it.
*/
}
let e2 = Entity::new("Entity 2".to_string());
println!("e2: {}", e2.name);
println!("Counter: {}", entity::get_counter());
println!("Instances:");
for ent in entity::get_instances() {
println!("- {}", ent.name);
}
}
I'm writing a system where I have a collection of Objects, and each Object has a unique integral ID. Here's how I would do it in C++:
class Object {
public:
Object(): id_(nextId_++) { }
private:
int id_;
static int nextId_;
}
int Object::nextId_ = 1;
This is obviously not thread_safe, but if I wanted it to be, I could make nextId_ an std::atomic_int, or wrap a mutex around the nextId_++ expression.
How would I do this in (preferably safe) Rust? There's no static struct members, nor are global mutable variables safe. I could always pass nextId into the new function, but these objects are going to be allocated in a number of places, and I would prefer not to pipe the nextId number hither and yon. Thoughts?
Atomic variables can live in statics, so you can use it relatively straightforwardly (the downside is that you have global state).
Example code: (playground link)
use std::{
sync::atomic::{AtomicUsize, Ordering},
thread,
};
static OBJECT_COUNTER: AtomicUsize = AtomicUsize::new(0);
#[derive(Debug)]
struct Object(usize);
impl Object {
fn new() -> Self {
Object(OBJECT_COUNTER.fetch_add(1, Ordering::SeqCst))
}
}
fn main() {
let threads = (0..10)
.map(|_| thread::spawn(|| Object::new()))
.collect::<Vec<_>>();
for t in threads {
println!("{:?}", t.join().unwrap());
}
}
nor are global mutable variables safe
Your C++ example seems like it would have thread-safety issues, but I don't know enough C++ to be sure.
However, only unsynchronized global mutable variables are trouble. If you don't care about cross-thread issues, you can use a thread-local:
use std::cell::Cell;
#[derive(Debug)]
struct Monster {
id: usize,
health: u8,
}
thread_local!(static MONSTER_ID: Cell<usize> = Cell::new(0));
impl Monster {
fn new(health: u8) -> Monster {
MONSTER_ID.with(|thread_id| {
let id = thread_id.get();
thread_id.set(id + 1);
Monster { id, health }
})
}
}
fn main() {
let gnome = Monster::new(41);
let troll = Monster::new(42);
println!("gnome {:?}", gnome);
println!("troll {:?}", troll);
}
If you do want something that works better with multiple threads, check out bluss' answer, which shows how to use an atomic variable.