Implementing 2D vector syntax for accessing a 1D vector? - vector

I'm making a toy roguelike and have a Level structure for storing the game map, for which the most naive implementation is a 2D vector.
I'm following this tutorial which uses a Vector of Vectors, but states that for performance gains it's also possible to use a single Vector of size MAP_HEIGHT * MAP_WIDTH, and to access a tile at (x, y) one can simply access map[y * MAP_WIDTH + x].
I'm trying to implement this faster method but using getters and setters is clunky, and public fields aren't that great either. I'd much prefer it to feel like a 2D vector.
In order to do that I need to implement the Index trait for my class, but I'm not sure how to get the result I want. Maybe by nesting the impls? I really no idea.
Here is my code with a terrible attempt at implementing Index for my structure, which obviously won't work for my purposes because it's one dimensional:
const MAP_WIDTH: i32 = 80;
const MAP_HEIGHT: i32 = 45;
pub struct Level {
map: Vec<Tile>,
}
impl Level {
pub fn new() -> Self {
Level { map: vec![Tile::empty(); (MAP_HEIGHT * MAP_WIDTH) as usize] }
}
}
impl std::ops::Index<i32> for Level {
type Output = Tile;
fn index(&self, x: i32) -> &Self::Output {
self[MAP_WIDTH + x]; // We have x and y values; how do we make this work?
}
}

Make your struct indexible over objects of type (i32, i32).
type Pos = (i32, i32);
impl std::ops::Index<Pos> for Level {
type Output = Tile;
fn index(&self, (x, y): Pos) -> &Self::Output {
&self.map[(y * MAP_WIDTH + x) as usize]
}
}
Which you can then access with, for example:
let tile = level[(3, 4)];
Since you are using i32, you need to make sure that the values are within range, and can be coerced to usize, which is what Vecs are indexed over. Probably you should just stick with u32 or usize values from the start. Otherwise, you'll need to keep track of the minimum x and y values, and subtract them, to keep the position in range. It's definitely simpler to deal with positive coordinates and make the assumption that the corner of your map is (0, 0).

It is possible, though not obvious.
First of all, I suggest having the MAP_WIDTH and MAP_HEIGHT in usize, as they are positive integers:
const MAP_WIDTH: usize = 80;
const MAP_HEIGHT: usize = 45;
Then you need to implement Index (and possibly IndexMut) to return a slice; in this case I'm assuming that you want the first coordinate to be the row:
impl std::ops::Index<usize> for Level {
type Output = [Tile];
fn index(&self, row: usize) -> &[Tile] {
let start = MAP_WIDTH * row;
&self.map[start .. start + MAP_WIDTH]
}
}
impl std::ops::IndexMut<usize> for Level {
fn index_mut(&mut self, row: usize) -> &mut [Tile] {
let start = MAP_WIDTH * row;
&mut self.map[start .. start + MAP_WIDTH]
}
}
Then, when you index a Level, it first returns a slice with the applicable row; then you can index that slice with the column number.
Below is an example implementation with a substitute Tile:
const MAP_WIDTH: usize = 80;
const MAP_HEIGHT: usize = 45;
#[derive(Clone, Debug)]
pub struct Tile {
x: u32,
y: u32
}
pub struct Level {
map: Vec<Tile>,
}
impl Level {
pub fn new() -> Self {
Level { map: vec![Tile { x: 0, y: 0 }; (MAP_HEIGHT * MAP_WIDTH) as usize] }
}
}
impl std::ops::Index<usize> for Level {
type Output = [Tile];
fn index(&self, row: usize) -> &[Tile] {
let start = MAP_WIDTH * row;
&self.map[start .. start + MAP_WIDTH]
}
}
impl std::ops::IndexMut<usize> for Level {
fn index_mut(&mut self, row: usize) -> &mut [Tile] {
let start = MAP_WIDTH * row;
&mut self.map[start .. start + MAP_WIDTH]
}
}
fn main() {
let mut lvl = Level::new();
lvl[5][2] = Tile { x: 5, y: 2 };
println!("{:?}", lvl[5][2]); // Tile { x: 5, y: 2 }
}

You cannot do this without exposing internal details about your implementation. Index is defined as:
pub trait Index<Idx>
where
Idx: ?Sized,
{
type Output: ?Sized;
fn index(&self, index: Idx) -> &Self::Output;
}
In order to support game[x][y], the return value of game[x] would need to:
Be a reference to something. (&Self::Output)
Implement Index itself.
There's no value to return a reference to other than self, and self would already implement Index for a usize so you can't reuse it.
Instead, you can implement indexing for a tuple:
impl std::ops::Index<(usize, usize)> for Level {
type Output = Tile;
fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
&self.map[MAP_WIDTH as usize * y + x]
}
}
This can be used as level[(43, 12)].
If you implement Index to return a slice, you should be aware that you are forever requiring that your internal data structure be something that is based on slices. For example, you cannot use a "sparse" structure like a HashMap because it cannot return a &[Tile]. The ability to return a &[Tile] is now a part of the public API of the struct. It's certainly a possibility that the representation will change, especially since it's already changed once.

Related

How can I pass mutable Vec<Something> variable to function and get item that is indexed

When I try the code below for the Vec<Ev> I get a [E0308]: mismatched type error.
use std::fmt::Error;
#[derive(Debug)]
struct Ev {
semt: String,
fiyat : i32,
}
impl Ev {
fn yeni (alan: &str,fiyat: i32) -> Ev {
Self {
semt: alan.to_string(),
fiyat
}
}
}
fn dizi_yap(boyut:usize) -> Result<Vec<Ev>,Error> {
let mut evler = Vec::<Ev>::with_capacity(boyut);
evler.push(Ev::yeni("melikgazi", 210));
evler.push(Ev::yeni("kocasinan", 120));
evler.push(Ev::yeni("hacılar", 410));
evler.push(Ev::yeni("bünyan", 90));
Ok(evler)
}
fn elemani_getir(&mut dizi:Vec<Ev>, sira:usize) -> Ev {
dizi[sira]
// dizi.get(sira).expect("hata")
}
fn main() {
let mut dizi = dizi_yap(1).expect("ulasmadi");
println!("eleman: {:?}",dizi[3]);
println!("eleman: {:?}",elemani_getir(dizi, 3))
}
How can I get Vec indexed item in this example?
The syntax in you function arguments is a little off. Mutable arguments can be a little confusing, as there are two different representations. Refer to this question for a more detailed explanation.
Here is the elemali_getit function corrected:
fn elemani_getir(mut dizi: &Vec<Ev>, sira: usize) -> &Ev {
&dizi[sira]
}
And you can call it like this:
println!("eleman: {:?}", elemani_getir(&dizi, 3))
Note that elemani_getir now returns a reference to Ev (&Ev). Returning Ev instead results in an error:
cannot move out of index of `std::vec::Vec<Ev>`
To get around this error, you can either return a reference to Ev as shown above, or return an exact duplicated of Ev my deriving the Clone trait:
#[derive(Debug, Clone)]
struct Ev {
semt: String,
fiyat: i32,
}
fn elemani_getir(mut dizi: &Vec<Ev>, sira: usize) -> Ev {
dizi[sira].clone()
}

Raw Pointers not producing desired effects

#![feature(ptr_internals)]
use core::ptr::Unique;
struct PtrWrapper {
id: usize,
self_reference: Unique<Self>
}
impl PtrWrapper {
fn new() -> Self {
let dummy = unsafe {Unique::new_unchecked(std::ptr::null_mut::<PtrWrapper>())};
let mut ret = Self {id:0, self_reference: dummy };
let new_ptr = &mut ret as *mut Self;
debug_print(new_ptr);
ret.self_reference = Unique::new(new_ptr).unwrap();
debug_print(ret.self_reference.as_ptr());
ret
}
fn get_id(&self) -> usize {
self.id.clone()
}
}
fn main() {
println!("START");
let mut wrapper = PtrWrapper::new();
wrapper.id = 10;
let ptr = wrapper.self_reference.as_ptr();
unsafe {
(*ptr).id += 30;
println!("The next print isn't 40? Garbage bytes");
debug_print(ptr);
let tmp = &mut wrapper as *mut PtrWrapper;
(*tmp).id += 500;
println!("The next print isn't 540?");
debug_print(tmp);
}
println!("Below debug_print is proof of undefined behavior! Garbage bytes\n");
debug_print(wrapper.self_reference.as_ptr());
debug_print(&mut wrapper as *mut PtrWrapper);
debug_print_move(wrapper);
println!("Why is the assertion below false?");
assert_eq!(unsafe{(*ptr).id}, 540);
}
fn debug_print_move(mut wrapper: PtrWrapper) {
debug_print(&mut wrapper as *mut PtrWrapper);
}
fn debug_print(ptr: *mut PtrWrapper) {
println!("Address: {:p}", ptr);
println!("ID: {}\n", unsafe {(*ptr).get_id()});
}
The above code should compile fine in rust playground with a nightly selected version. Pay attention to the console outputs.
My question is: Why are the intermittent results not equal to the value I expect them to equal? In the case below, there is no multiple access simultaneously (single threaded), so there aren't any data races. There are, however, implicitly multiple mutable version of the object existing on the stack.
As expected, the memory location of the pointer changes with the tmp variable as well as when the entire object is moved into debug_print_move. It appears that using the tmp pointer works as expected (i.e., adds 500), however, the pointers which are obtained from the Unique<PtrWrapper> object seems to point to irrelevant locations in memory.
As Stargateur recommended, in order to solve this problem we need to Pin the object which needs to be self-referential. I ended up using:
pin-api = "0.2.1"
In cargo.toml instead of std::pin::pin. Next, I set this up the struct and its implementation:
#![feature(ptr_internals, pin_into_inner, optin_builtin_traits)]
// not available on rust-playground
extern crate pin_api;
use pin_api::{boxed::PinBox, marker::Unpin, mem::Pin};
///test
pub struct PtrWrapper<T>
where
T: std::fmt::Debug,
{
///tmp
pub obj: T,
/// pinned object
pub self_reference: *mut Self,
}
impl<T> !Unpin for PtrWrapper<T> where T: std::fmt::Debug {}
impl<T> PtrWrapper<T>
where
T: std::fmt::Debug,
{
///test
pub fn new(obj: T) -> Self {
Self {
obj,
self_reference: std::ptr::null_mut(),
}
}
///test
pub fn init(mut self: Pin<PtrWrapper<T>>) {
let mut this: &mut PtrWrapper<T> = unsafe { Pin::get_mut(&mut self) };
this.self_reference = this as *mut Self;
}
/// Debug print
pub fn print_obj(&self) {
println!("Obj value: {:#?}", self.obj);
}
}
Finally, the test function:
fn main2() {
unsafe {
println!("START");
let mut wrapper = PinBox::new(PtrWrapper::new(10));
wrapper.as_pin().init();
let m = wrapper.as_pin().self_reference;
(*m).obj += 30;
println!("The next print is 40");
debug_print(m);
let tmp = wrapper.as_pin().self_reference;
(*tmp).obj += 500;
println!("The next print is 540?");
debug_print(tmp);
debug_print(wrapper.self_reference);
let cpy = PinBox::get_mut(&mut wrapper);
debug_print_move(cpy);
std::mem::drop(wrapper);
println!("Works!");
assert_eq!(unsafe { (*m).obj }, 540);
}
}
fn debug_print_move<T>(mut wrapper: &mut PtrWrapper<T>)
where
T: std::fmt::Debug,
{
debug_print(&mut *wrapper as *mut PtrWrapper<T>);
}
fn debug_print<T>(ptr: *mut PtrWrapper<T>)
where
T: std::fmt::Debug,
{
println!("Address: {:p}", ptr);
unsafe { (*ptr).print_obj() };
}
On a side note, pin-api does not exist on rust playground. You could still use std::pin::Pin, however it would require further customization.

Using the type system to enforce coordinate boundaries in Rust [duplicate]

I have a function that takes an argument of type u16. Is there an elegant way to define a custom data type that behaves exactly like a u16 but only has values between 0 and 100?
As I understand it, that requires dependent types, which Rust does not have. This doesn't require dependent types (see comments) but Rust still doesn't have the support needed.
As a workaround, you could create a newtype that you verify yourself:
#[derive(Debug)]
struct Age(u16);
impl Age {
fn new(age: u16) -> Option<Age> {
if age <= 100 {
Some(Age(age))
} else {
None
}
}
}
fn main() {
let age1 = Age::new(30);
let age2 = Age::new(500);
println!("{:?}, {:?}", age1, age2);
assert_eq!(
std::mem::size_of::<Age>(),
std::mem::size_of::<u16>()
);
}
Of course, it doesn't behave exactly like a u16, but you don't want it to, either! For example, a u16 can go beyond 100... You'd have to reason out if it makes sense to add/subtract/multiply/divide etc your new type as well.
For maximum safeguarding, you should move your type and any associated functions into a module. This leverages Rust's visibility rules to prevent people from accidentally accessing the value inside the newtype and invalidating the constraints.
You may also want to implement TryFrom (from u16 to your type) or From (from your type to u16) to better integrate with generic code.
An important thing to note is that this newtype takes the same amount of space as a u16 - the wrapper type is effectively erased when the code is compiled. The type checker makes sure everything meshes before that point.
Unfortunately, there is no such a thing inside the std crate.
However, you can do it yourself in an optimized manner with the nightly generic consts, scheduled to be stabilized in Rust 1.51. Example:
// 1.51.0-nightly (2020-12-30)
pub struct BoundedI32<const LOW: i32, const HIGH: i32>(i32);
impl<const LOW: i32, const HIGH: i32> BoundedI32<{ LOW }, { HIGH }> {
pub const LOW: i32 = LOW;
pub const HIGH: i32 = HIGH;
pub fn new(n: i32) -> Self {
BoundedI32(n.min(Self::HIGH).max(Self::LOW))
}
pub fn fallible_new(n: i32) -> Result<Self, &'static str> {
match n {
n if n < Self::LOW => Err("Value too low"),
n if n > Self::HIGH => Err("Value too high"),
n => Ok(BoundedI32(n)),
}
}
pub fn set(&mut self, n: i32) {
*self = BoundedI32(n.min(Self::HIGH).max(Self::LOW))
}
}
impl<const LOW: i32, const HIGH: i32> std::ops::Deref for BoundedI32<{ LOW }, { HIGH }> {
type Target = i32;
fn deref(&self) -> &Self::Target {
&self.0
}
}
fn main() {
let dice = BoundedI32::<1, 6>::fallible_new(0);
assert!(dice.is_err());
let mut dice = BoundedI32::<1, 6>::new(0);
assert_eq!(*dice, 1);
dice.set(123);
assert_eq!(*dice, 6);
}
And then you can implement the maths, etc.
If you want to chose the bound at runtime, you don't need this feature, and you just need to do something like that:
pub struct BoundedI32 {
n: i32,
low: i32,
high: i32,
}
You can also use a crate like bounded-integer that allows to generate a bounded integer on-the-fly with a macro.
With the nightly feature generic_const_exprs, it is possible to verify this at compile time:
#![feature(generic_const_exprs)]
struct If<const COND: bool>;
trait True {}
impl True for If<true> {}
const fn in_bounds(n: usize, low: usize, high: usize) -> bool {
n > low && n < high
}
struct BoundedInteger<const LOW: usize, const HIGH: usize>(usize);
impl<const LOW: usize, const HIGH: usize> BoundedInteger<LOW, HIGH>
where
If<{ LOW < HIGH }>: True,
{
fn new<const N: usize>() -> Self
where
If<{ in_bounds(N, LOW, HIGH) }>: True,
{
Self(N)
}
}
The error messages aren't the best, but it works!
fn main() {
let a = BoundedInteger::<1, 10>::new::<5>();
let b = BoundedInteger::<10, 1>::new::<5>(); // ERROR: doesn't satisfy `If<{ LOW < HIGH }>: True`
let c = BoundedInteger::<2, 5>::new::<6>(); // ERROR: expected `false`, found `true`
}
Not exactly, to my knowledge. But you can use a trait to get close. Example, where tonnage is a unsigned 8 bit integer that is expected to be 20-100 and a multiple of 5:
pub trait Validator{
fn isvalid(&self) -> bool;
}
pub struct TotalRobotTonnage{
pub tonnage: u8,
}
impl Validator for TotalRobotTonnage{
//is in range 20-100 and a multiple of 5
fn isvalid(&self) -> bool{
if self.tonnage < 20 || self.tonnage > 100 || self.tonnage % 5 != 0{
false
}else{
true
}
}
}
fn main() {
let validtonnage = TotalRobotTonnage{tonnage: 100};
let invalidtonnage_outofrange = TotalRobotTonnage{tonnage: 10};
let invalidtonnage_notmultipleof5 = TotalRobotTonnage{tonnage: 21};
println!("value {} [{}] value {} [{}] value {} [{}]",
validtonnage.tonnage,
validtonnage.isvalid(),
invalidtonnage_outofrange.tonnage,
invalidtonnage_outofrange.isvalid(),
invalidtonnage_notmultipleof5.tonnage,
invalidtonnage_notmultipleof5.isvalid()
);
}

What is the idiomatic way in Rust to represent collections of items of different types? [duplicate]

I want to use trait objects in a Vec. In C++ I could make a base class Thing from which is derived Monster1 and Monster2. I could then create a std::vector<Thing*>. Thing objects must store some data e.g. x : int, y : int, but derived classes need to add more data.
Currently I have something like
struct Level {
// some stuff here
pub things: Vec<Box<ThingTrait + 'static>>,
}
struct ThingRecord {
x: i32,
y: i32,
}
struct Monster1 {
thing_record: ThingRecord,
num_arrows: i32,
}
struct Monster2 {
thing_record: ThingRecord,
num_fireballs: i32,
}
I define a ThingTrait with methods for get_thing_record(), attack(), make_noise() etc. and implement them for Monster1 and Monster2.
Trait objects
The most extensible way to implement a heterogeneous collection (in this case a vector) of objects is exactly what you have:
Vec<Box<dyn ThingTrait + 'static>>
Although there are times where you might want a lifetime that's not 'static, so you'd need something like:
Vec<Box<dyn ThingTrait + 'a>>
You could also have a collection of references to traits, instead of boxed traits:
Vec<&dyn ThingTrait>
An example:
trait ThingTrait {
fn attack(&self);
}
impl ThingTrait for Monster1 {
fn attack(&self) {
println!("monster 1 attacks")
}
}
impl ThingTrait for Monster2 {
fn attack(&self) {
println!("monster 2 attacks")
}
}
fn main() {
let m1 = Monster1 {
thing_record: ThingRecord { x: 42, y: 32 },
num_arrows: 2,
};
let m2 = Monster2 {
thing_record: ThingRecord { x: 42, y: 32 },
num_fireballs: 65,
};
let things: Vec<Box<dyn ThingTrait>> = vec![Box::new(m1), Box::new(m2)];
}
Box<dyn SomeTrait>, Rc<dyn SomeTrait>, &dyn SomeTrait, etc. are all trait objects. These allow implementation of the trait on an infinite number of types, but the tradeoff is that it requires some amount of indirection and dynamic dispatch.
See also:
What makes something a "trait object"?
What does "dyn" mean in a type?
Enums
As mentioned in the comments, if you have a fixed number of known alternatives, a less open-ended solution is to use an enum. This doesn't require that the values be Boxed, but it will still have a small amount of dynamic dispatch to decide which concrete enum variant is present at runtime:
enum Monster {
One(Monster1),
Two(Monster2),
}
impl Monster {
fn attack(&self) {
match *self {
Monster::One(_) => println!("monster 1 attacks"),
Monster::Two(_) => println!("monster 2 attacks"),
}
}
}
fn main() {
let m1 = Monster1 {
thing_record: ThingRecord { x: 42, y: 32 },
num_arrows: 2,
};
let m2 = Monster2 {
thing_record: ThingRecord { x: 42, y: 32 },
num_fireballs: 65,
};
let things = vec![Monster::One(m1), Monster::Two(m2)];
}
See also:
Why does an enum require extra memory size?

How do I process a range in slices in Rust?

I understand that the preferred way to iterate in Rust is through the for var in (range) syntax, but sometimes I'd like to work on more than one of the elements in that range at a time.
From a Ruby perspective, I'm trying to find a way of doing (1..100).each_slice(5) do |this_slice| in Rust.
I'm trying things like
for mut segment_start in (segment_size..max_val).step_by(segment_size) {
let this_segment = segment_start..(segment_start + segment_size).iter().take(segment_size);
}
but I keep getting errors that suggest I'm barking up the wrong type tree. The docs aren't helpful either--they just don't contain this use case.
What's the Rust way to do this?
Use chunks (or chunks_mut if you need mutability):
fn main() {
let things = [5, 4, 3, 2, 1];
for slice in things.chunks(2) {
println!("{:?}", slice);
}
}
Outputs:
[5, 4]
[3, 2]
[1]
The easiest way to combine this with a Range would be to collect the range to a Vec first (which dereferences to a slice):
fn main() {
let things: Vec<_> = (1..100).collect();
for slice in things.chunks(5) {
println!("{:?}", slice);
}
}
Another solution that is pure-iterator would be to use Itertools::chunks_lazy:
extern crate itertools;
use itertools::Itertools;
fn main() {
for chunk in &(1..100).chunks_lazy(5) {
for val in chunk {
print!("{}, ", val);
}
println!("");
}
}
Which suggests a similar solution that only requires the standard library:
fn main() {
let mut range = (1..100).peekable();
while range.peek().is_some() {
for value in range.by_ref().take(5) {
print!("{}, ", value);
}
println!("");
}
}
One trick is that Ruby and Rust have different handling here, mostly centered around efficiency.
In Ruby Enumerable can create new arrays to stuff values in without worrying about ownership and return a new array each time (check with this_slice.object_id).
In Rust, allocating a new vector each time would be pretty unusual. Additionally, you can't easily return a reference to a vector that the iterator holds due to complicated lifetime concerns.
A solution that's very similar to Ruby's is:
fn main() {
let mut range = (1..100).peekable();
while range.peek().is_some() {
let chunk: Vec<_> = range.by_ref().take(5).collect();
println!("{:?}", chunk);
}
}
Which could be wrapped up in a new iterator that hides the details:
use std::iter::Peekable;
struct InefficientChunks<I>
where I: Iterator
{
iter: Peekable<I>,
size: usize,
}
impl<I> Iterator for InefficientChunks<I>
where I: Iterator
{
type Item = Vec<I::Item>;
fn next(&mut self) -> Option<Self::Item> {
if self.iter.peek().is_some() {
Some(self.iter.by_ref().take(self.size).collect())
} else {
None
}
}
}
trait Awesome: Iterator + Sized {
fn inefficient_chunks(self, size: usize) -> InefficientChunks<Self> {
InefficientChunks {
iter: self.peekable(),
size: size,
}
}
}
impl<I> Awesome for I where I: Iterator {}
fn main() {
for chunk in (1..100).inefficient_chunks(5) {
println!("{:?}", chunk);
}
}
Collecting into a vec can easily kill your performance. An approach similar to in the question is perfectly fine.
fn chunk_range(range: Range<usize>, chunk_size: usize) -> impl Iterator<Item=Range<usize>> {
range.clone().step_by(chunk_size).map(move |block_start| {
let block_end = (block_start + chunk_size).min(range.end);
block_start..block_end
})
}

Resources