How do I copy/clone a struct that derives neither? - rust

I'm trying to do some game programming with Piston, but i'm struggling with opengl_graphics::Texture, since it does not derive Copy or Clone.
extern crate piston_window;
extern crate piston;
extern crate graphics;
extern crate opengl_graphics;
use opengl_graphics::Texture as Tex;
use piston_window::*;
use std::path::Path;
use opengl_graphics::GlGraphics;
#[derive(PartialEq)]
enum ObjectType {
Blocking,
Passing,
}
struct Object {
sprite: Tex,
obj_type: ObjectType,
position: Position,
}
struct Game {
gl: GlGraphics,
images: Vec<Object>,
player: Player,
}
struct Player {
sprite: Tex,
position: Position,
}
struct Position {
x: i32,
y: i32,
}
impl Game {
fn render(&mut self, args: &RenderArgs) {
let iter = self.images.iter();
let player = &self.player;
self.gl.draw(args.viewport(), |c, g| {
clear([1.0, 1.0, 1.0, 1.0], g);
for img in iter {
let pos = img.get_position();
let transform = c.transform.trans(((pos.x * 64)) as f64, ((pos.y * 64)) as f64);
image(img.get_sprite(), transform, g);
}
image(player.get_sprite(),
c.transform.trans((player.get_position().x * 64) as f64,
(player.get_position().y * 64) as f64),
g);
});
}
fn update(&mut self, args: &UpdateArgs) {}
}
The main game loop:
fn main() {
let (width, height) = (64*10, 64*10);
let opengl = OpenGL::V3_2;
let mut window: PistonWindow =
WindowSettings::new("piston", (width, height))
.exit_on_esc(true)
.opengl(opengl)
.build()
.unwrap();
window.hide();
println!("Loading...");
let mut player = Player { sprite: Tex::from_path(&Path::new(
"./assets/player_n.png")).unwrap(),
position: Position { x: 3, y: 3 },
};
let mut game = Game {
gl: GlGraphics::new(opengl),
images: Vec::new(),
player: player,
};
for i in 0..10 {
for j in 0..10 {
if i == 0 || i == 9 || j == 0 || j == 9 {
let obj = Object { sprite: Tex::from_path(&Path::new(
"./assets/wall.png")).unwrap(),
obj_type: ObjectType::Blocking,
position: Position { x: i, y: j },
};
game.images.push(obj);
} else {
let obj = Object { sprite: Tex::from_path(&Path::new(
"./assets/floor.png")).unwrap(),
obj_type: ObjectType::Passing,
position: Position { x: i, y: j },
};
game.images.push(obj);
}
}
}
window.show();
while let Some(e) = window.next() {
if let Some(Button::Keyboard(key)) = e.press_args() {
let mut pos = game.player.position.clone();
let mut spr: Option<Tex> = None;
match key {
Key::Up => { pos.y -= 1; spr = Some(Tex::from_path(&Path::new(
"./assets/player_n.png")).unwrap()); },
Key::Down => { pos.y += 1; spr = Some(Tex::from_path(&Path::new(
"./assets/player_s.png")).unwrap()); },
Key::Left => { pos.x -= 1; spr = Some(Tex::from_path(&Path::new(
"./assets/player_w.png")).unwrap()); },
Key::Right => { pos.x += 1; spr = Some(Tex::from_path(&Path::new(
"./assets/player_e.png")).unwrap()); },
_ => (),
}
for elem in game.images.iter() {
if pos.x == elem.position.x && pos.y == elem.position.y && elem.obj_type == ObjectType::Passing {
game.player.position = pos;
game.player.sprite = spr.clone().unwrap();
}
}
}
if let Some(r) = e.render_args() {
game.render(&r);
}
if let Some(u) = e.update_args() {
game.update(&u);
}
}
}
Produces the error:
error: no method named `clone` found for type `std::option::Option<opengl_graphics::Texture>` in the current scope
--> src/main.rs:159:46
159 | game.player.sprite = spr.clone().unwrap();
| ^^^^^
|
= note: the method `clone` exists but the following trait bounds were not satisfied: `opengl_graphics::Texture : std::clone::Clone`
I understand why I get this error, since opengl_graphics::Texture doesn't derive Copy I can't clone Option<opengl_texture>. What workaround is there for this?
I tried messing around with references but that didn't work.

How do I copy/clone a struct that derives neither?
You don't. The only thing you can do is take some kind of reference to it.
In this case, it is a very good thing that the library has chosen to not implement Clone or Copy. If you were able to clone the structure, you'd be allocating a lot of memory frequently and needlessly. Instead, the library has forced you to think about when you allocate that memory. One of the solutions is to load all the textures at application startup and reference them:
Change your structures to hold references:
#[derive(PartialEq)]
enum ObjectType {
Blocking,
Passing,
}
struct Object<'a> {
sprite: &'a Tex,
obj_type: ObjectType,
position: Position,
}
struct Game<'a> {
gl: GlGraphics,
images: Vec<Object<'a>>,
player: Player<'a>,
}
struct Player<'a> {
sprite: &'a Tex,
position: Position,
}
#[derive(Copy, Clone, PartialEq)]
struct Position {
x: i32,
y: i32,
}
struct Textures {
player_n: Tex,
player_s: Tex,
player_e: Tex,
player_w: Tex,
wall: Tex,
floor: Tex,
}
Load the textures early on in main. Note that there's no need to use Path explicitly, as it takes AsRef<Path>:
let textures = Textures {
player_n: Tex::from_path("./assets/player_n.png").unwrap(),
player_s: Tex::from_path("./assets/player_s.png").unwrap(),
player_e: Tex::from_path("./assets/player_e.png").unwrap(),
player_w: Tex::from_path("./assets/player_w.png").unwrap(),
wall: Tex::from_path("./assets/wall.png").unwrap(),
floor: Tex::from_path("./assets/floor.png").unwrap()
};
Then pass references to those textures:
match key {
Key::Up => {
pos.y -= 1;
spr = Some(&textures.player_n)
}
Key::Down => {
pos.y += 1;
spr = Some(&textures.player_s)
}
Key::Left => {
pos.x -= 1;
spr = Some(&textures.player_w)
}
Key::Right => {
pos.x += 1;
spr = Some(&textures.player_e)
}
_ => (),
}
for elem in game.images.iter() {
if pos == elem.position && elem.obj_type == ObjectType::Passing {
game.player.position = pos;
if let Some(spr) = spr {
game.player.sprite = spr;
}
}
}
Note that this also consolidates the places that errors can occur. There's no longer an unwrap inside the guts of the loop.
I was unable to get your code to finish compiling as the code is not complete but this should help get started:
error: no method named `render` found for type `Game<'_>` in the current scope
--> src/main.rs:122:18
|
122 | game.render(&r);
| ^^^^^^
|
= help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item `render`, perhaps you need to implement it:
= help: candidate #1: `piston_window::RenderEvent`
error: no method named `update` found for type `Game<'_>` in the current scope
--> src/main.rs:125:18
|
125 | game.update(&u);
| ^^^^^^
|
= help: items from traits can only be used if the trait is implemented and in scope; the following traits define an item `update`, perhaps you need to implement one of them:
= help: candidate #1: `piston_window::UpdateEvent`
= help: candidate #2: `piston_window::<unnamed>::UpdateTexture`
= help: candidate #3: `deflate::checksum::RollingChecksum`
= help: candidate #4: `cocoa::appkit::NSOpenGLContext`
= help: candidate #5: `cocoa::appkit::NSOpenGLContext`
In some cases, you may be able to wrap your types in an Rc or Arc and clone that. Cloning a Rc/Arc only increments a reference counter, regardless of the implementation of Clone for the underlying type (or the absence of such an implementation).

Related

How to get an enum reference from a reference to a child type of the enum?

I have an enum type Shape that contains two types Rect and Circle. now there is a function that can find &Rect or &Circle objects, how can I get them to return as &Shape?
#[derive(Debug)]
struct Rect {}
#[derive(Debug)]
struct Circle {}
#[derive(Debug)]
enum Shape {
R(Rect),
C(Circle),
}
struct Container {
rects: Vec<(usize, Rect)>,
circls: Vec<(usize, Circle)>,
}
impl Container {
fn find_shape(&self, id: usize) -> Option<&Shape> {
let optr = self.rects.iter().find(|x| x.0 == id);
if let Some((_, r)) = optr {
return Some(&Shape::R(r)); // expected struct `Rect`, found `&Rect`
}
let optc = self.circls.iter().find(|x| x.0 == id);
if let Some((_, c)) = optc {
return Some(c); // expected enum `Option<&Shape>` found reference `&Circle`
}
return None;
}
}
fn main() {
let cont = Container {
rects: vec![(0, Rect {}), (2, Rect {})],
circls: vec![(1, Circle {}), (3, Circle {})],
};
let s = cont.find_shape(1).unwrap();
println!("shape is {:?}", s);
}
now there is a function that can find &Rect or &Circle objects, how can I get them to return as &Shape?
It can't, in the same way you can't get e.g. an &Option<String> from an &String.
Shape is, in essence,
struct Shape {
discr: u8,
content: union { _1: Rect, _2: Circle }
}
The solution is to either modify Shape to store references, or to have a secondary type which does that (e.g. ShapeRef).
The latter is quite common.

What is an acceptable approach to dragging sprites with Bevy 0.4?

While trying out Bevy, I had the need for dragging and dropping sprites.
Unfortunately, this does not seem to come ready made or I did not find it in the documentation.
What would be the most idiomatic way to achieve this goal?
What I have tried so far is in my answer, but I'll gladly accept another solution that is better/faster/more idiomatic.
I'm not experienced enough to know what's idiomatic unfortunately, however, here's an overview of how I've implemented sprite dragging in my application, and it feels like a good way to me:
I have a "cursor location" entity with a transform component (and a Cursor component for identification) that I update in a system each frame to the location of the cursor.
Every draggable object has a Hoverable and Draggable component. I iterate over those objects in one system each where I add/remove a Hovered and Dragged component to the entities to indicate if they are hovered or dragged.
I have a system that checks if an object is getting dropped, and if so gives it a Dropped component.
I have a system that runs when an entity gets the 'Dragged' component (using the Added<C> filter), which sets the objects parent to the "cursor location" entity.
And another system for when an entity gets the 'Dropped' component, which clears the parent.
To me, having many systems with small areas of responsibility feels good. I would be interested to hear opposing views as I lack experience.
There are of course many things I've left out in this overview, so here's my code for reference. There are some oddities and unnecessary code for a minimal example since this is adapted from my actual code:
#![allow(clippy::type_complexity)]
use bevy::{prelude::*, render::camera::Camera};
fn main() {
App::build()
.init_resource::<State>()
.add_resource(WindowDescriptor {
title: "Bevy".to_string(),
width: 1024.0,
height: 768.0,
vsync: true,
..Default::default()
})
.add_plugins(DefaultPlugins)
.add_plugin(MyPlugin)
.run();
}
pub struct MyPlugin;
impl Plugin for MyPlugin {
fn build(&self, app: &mut AppBuilder) {
app.add_startup_system(setup.system())
.add_system_to_stage(stage::PRE_UPDATE, cursor_state.system())
.add_system_to_stage(stage::UPDATE, cursor_transform.system())
.add_system_to_stage(stage::UPDATE, draggable.system())
.add_system_to_stage(stage::UPDATE, hoverable.system())
.add_system_to_stage(stage::POST_UPDATE, drag.system())
.add_system_to_stage(stage::POST_UPDATE, drop.system())
.add_system_to_stage(stage::POST_UPDATE, material.system());
}
}
const SPRITE_SIZE: f32 = 55.0;
fn setup(
commands: &mut Commands,
asset_server: Res<AssetServer>,
mut materials: ResMut<Assets<ColorMaterial>>,
) {
let bevy_texture = asset_server.load("sprites/bevy-icon.png");
commands
.spawn(Camera2dBundle::default())
.spawn(())
.with(CursorState::default())
.spawn((Transform::default(), GlobalTransform::default(), Cursor));
for _ in 0..4 {
commands
.spawn(SpriteBundle {
material: materials.add(bevy_texture.clone().into()),
sprite: Sprite::new(Vec2::new(SPRITE_SIZE, SPRITE_SIZE)),
..Default::default()
})
.with(Hoverable)
.with(Draggable);
}
}
#[derive(Default)]
struct CursorState {
cursor_world: Vec2,
cursor_moved: bool,
}
struct Cursor;
struct Draggable;
struct Dragged;
struct Dropped;
struct Hoverable;
struct Hovered;
fn cursor_state(
mut state: ResMut<State>,
e_cursor_moved: Res<Events<CursorMoved>>,
windows: Res<Windows>,
mut q_cursor_state: Query<&mut CursorState>,
q_camera: Query<&Transform, With<Camera>>,
) {
let event_cursor_screen = state.er_cursor_moved.latest(&e_cursor_moved);
for mut cursor_state in q_cursor_state.iter_mut() {
if let Some(event_cursor_screen) = event_cursor_screen {
let window = windows.get_primary().unwrap();
let cam_transform = q_camera.iter().last().unwrap();
cursor_state.cursor_world =
cursor_to_world(window, cam_transform, event_cursor_screen.position);
cursor_state.cursor_moved = true;
} else {
cursor_state.cursor_moved = false;
}
}
}
fn cursor_transform(
commands: &mut Commands,
q_cursor_state: Query<&CursorState>,
mut q_cursor: Query<(Entity, &mut Transform), With<Cursor>>,
) {
let cursor_state = q_cursor_state.iter().next().unwrap();
for (cursor_e, mut transform) in q_cursor.iter_mut() {
transform.translation.x = cursor_state.cursor_world.x;
transform.translation.y = cursor_state.cursor_world.y;
commands.remove_one::<Parent>(cursor_e);
}
}
fn hoverable(
commands: &mut Commands,
q_cursor_state: Query<&CursorState>,
q_hoverable: Query<(Entity, &Transform, &Sprite), (With<Hoverable>, Without<Dragged>)>,
) {
let cursor_state = q_cursor_state.iter().next().unwrap();
if cursor_state.cursor_moved {
for (entity, transform, sprite) in q_hoverable.iter() {
let half_width = sprite.size.x / 2.0;
let half_height = sprite.size.y / 2.0;
if transform.translation.x - half_width < cursor_state.cursor_world.x
&& transform.translation.x + half_width > cursor_state.cursor_world.x
&& transform.translation.y - half_height < cursor_state.cursor_world.y
&& transform.translation.y + half_height > cursor_state.cursor_world.y
{
commands.insert_one(entity, Hovered);
} else {
commands.remove_one::<Hovered>(entity);
}
}
}
}
fn material(
mut materials: ResMut<Assets<ColorMaterial>>,
q_hoverable: Query<
(&Handle<ColorMaterial>, Option<&Hovered>, Option<&Dragged>),
With<Hoverable>,
>,
) {
let mut first = true;
for (material, hovered, dragged) in q_hoverable.iter() {
let (red, green, alpha) = if dragged.is_some() {
(0.0, 1.0, 1.0)
} else if first && hovered.is_some() {
first = false;
(1.0, 0.0, 1.0)
} else if hovered.is_some() {
(1.0, 1.0, 0.5)
} else {
(1.0, 1.0, 1.0)
};
materials.get_mut(material).unwrap().color.set_r(red);
materials.get_mut(material).unwrap().color.set_g(green);
materials.get_mut(material).unwrap().color.set_a(alpha);
}
}
fn cursor_to_world(window: &Window, cam_transform: &Transform, cursor_pos: Vec2) -> Vec2 {
// get the size of the window
let size = Vec2::new(window.width() as f32, window.height() as f32);
// the default orthographic projection is in pixels from the center;
// just undo the translation
let screen_pos = cursor_pos - size / 2.0;
// apply the camera transform
let out = cam_transform.compute_matrix() * screen_pos.extend(0.0).extend(1.0);
Vec2::new(out.x, out.y)
}
fn draggable(
commands: &mut Commands,
i_mouse_button: Res<Input<MouseButton>>,
q_pressed: Query<Entity, (With<Hovered>, With<Draggable>)>,
q_released: Query<Entity, With<Dragged>>,
) {
if i_mouse_button.just_pressed(MouseButton::Left) {
if let Some(entity) = q_pressed.iter().next() {
commands.insert_one(entity, Dragged);
}
} else if i_mouse_button.just_released(MouseButton::Left) {
for entity in q_released.iter() {
commands.remove_one::<Dragged>(entity);
commands.insert_one(entity, Dropped);
}
}
}
fn drag(
commands: &mut Commands,
mut q_dragged: Query<(Entity, &mut Transform, &GlobalTransform), Added<Dragged>>,
q_cursor: Query<(Entity, &GlobalTransform), With<Cursor>>,
) {
if let Some((cursor_e, cursor_transform)) = q_cursor.iter().next() {
for (entity, mut transform, global_transform) in q_dragged.iter_mut() {
let global_pos = global_transform.translation - cursor_transform.translation;
commands.insert_one(entity, Parent(cursor_e));
transform.translation.x = global_pos.x;
transform.translation.y = global_pos.y;
}
}
}
fn drop(
commands: &mut Commands,
mut q_dropped: Query<(Entity, &mut Transform, &GlobalTransform), Added<Dropped>>,
) {
for (entity, mut transform, global_transform) in q_dropped.iter_mut() {
let global_pos = global_transform.translation;
transform.translation.x = global_pos.x;
transform.translation.y = global_pos.y;
commands.remove_one::<Parent>(entity);
commands.remove_one::<Dropped>(entity);
}
}
#[derive(Default)]
struct State {
er_cursor_moved: EventReader<CursorMoved>,
}
This code is for bevy 0.4.
This is the solution I came up with. Complete example
main.rs
use bevy::prelude::*;
use bevy::render::pass::ClearColor;
use bevy::window::CursorMoved;
const SPRITE_SIZE: f32 = 55.0;
fn main() {
App::build()
.add_resource(WindowDescriptor {
width: 1000.0,
height: 1000.0,
resizable: false,
title: "Bevy: drag sprite".to_string(),
..Default::default()
})
.add_resource(Msaa { samples: 4 })
.add_resource(ClearColor(Color::rgb(0.9, 0.9, 0.9)))
.add_plugins(DefaultPlugins)
.add_startup_system(setup.system())
.add_system(sprite_system.system())
.add_system(bevy::input::system::exit_on_esc_system.system())
.run();
}
fn setup(
commands: &mut Commands,
asset_server: Res<AssetServer>,
mut materials: ResMut<Assets<ColorMaterial>>,
) {
commands.spawn(Camera2dBundle::default());
// show sprite in the middle of the screen
let bevy_texture = asset_server.load("sprites/bevy-icon.png");
commands.spawn(SpriteBundle {
sprite: Sprite::new(Vec2::new(SPRITE_SIZE, SPRITE_SIZE)),
material: materials.add(bevy_texture.clone().into()),
..Default::default()
});
}
#[derive(Default)]
struct State {
cursor_moved_event_reader: EventReader<CursorMoved>,
// store current cursor/mouse position
cursor_pos: Vec2,
// store entity ID and the difference between sprite center and mouse click location
sprite: Option<(Entity, Vec3)>,
}
fn sprite_system(
mut state: Local<State>,
windows: Res<Windows>,
mouse_button_input: Res<Input<MouseButton>>,
cursor_moved_events: Res<Events<CursorMoved>>,
mut sprites: Query<(Entity, &Sprite)>,
mut transforms: Query<&mut Transform>,
) {
let window = windows.get_primary().unwrap();
let half_window = Vec2::new(window.width() / 2.0, window.height() / 2.0);
// if cursor has moved, transform to graphics coordinates and store in state.curser_pos
if let Some(cursor_event) = state.cursor_moved_event_reader.latest(&cursor_moved_events) {
state.cursor_pos = cursor_event.position - half_window;
state.cursor_pos.x = state.cursor_pos.x;
};
// stop dragging if mouse button was released
if mouse_button_input.just_released(MouseButton::Left) {
state.sprite = None;
return;
}
// set new sprite position, if mouse button is pressed and a sprite was clicked on
// take previous click difference into account, to avoid sprite jumps on first move
if mouse_button_input.pressed(MouseButton::Left) && state.sprite.is_some() {
let sprite = state.sprite.unwrap();
let mut sprite_pos = transforms.get_mut(sprite.0).unwrap();
trace!("Sprite position old: {:?}", sprite_pos.translation);
sprite_pos.translation.x = state.cursor_pos.x + sprite.1.x;
sprite_pos.translation.y = state.cursor_pos.y + sprite.1.y;
trace!("Sprite position new: {:?}", sprite_pos.translation);
// position clamping was left out intentionally
}
// store sprite ID and mouse distance from sprite center, if sprite was clicked
if mouse_button_input.just_pressed(MouseButton::Left) {
for (entity, sprite) in sprites.iter_mut() {
let sprite_pos = transforms.get_mut(entity).unwrap().translation;
let diff = cursor_to_sprite_diff(&state.cursor_pos, &sprite_pos);
// sprite is a circle, so check distance from center < sprite radius
if diff.length() < (sprite.size.x / 2.0) {
state.sprite = Some((entity, diff));
}
}
}
}
fn cursor_to_sprite_diff(cursor_pos: &Vec2, sprite_pos: &Vec3) -> Vec3 {
Vec3::new(
sprite_pos.x - cursor_pos.x,
sprite_pos.y - cursor_pos.y,
0.0,
)
}
Cargo.toml
[package]
name = "bevy-drag-sprite"
version = "0.1.0"
authors = ["Me"]
edition = "2018"
[dependencies]
bevy = "0.4"

Why does wasm-opt fail in wasm-pack builds when generating a function returning a string?

I'm working through the Rust WASM tutorial for Conway's game of life.
One of the simplest functions in the file is called Universe.render (it's the one for rendering a string representing game state). It's causing an error when I run wasm-pack build:
Fatal: error in validating input
Error: failed to execute `wasm-opt`: exited with exit code: 1
full command: "/home/vaer/.cache/.wasm-pack/wasm-opt-4d7a65327e9363b7/wasm-opt" "/home/vaer/src/learn-rust/wasm-game-of-life/pkg/wasm_game_of_life_bg.wasm" "-o" "/home/vaer/src/learn-rust/wasm-game-of-life/pkg/wasm_game_of_life_bg.wasm-opt.wasm" "-O"
To disable `wasm-opt`, add `wasm-opt = false` to your package metadata in your `Cargo.toml`.
If I remove that function, the code builds without errors. If I replace it with the following function, the build fails with the same error:
pub fn wtf() -> String {
String::from("wtf")
}
It seems like any function that returns a String causes this error. Why?
Following is the entirety of my code:
mod utils;
use wasm_bindgen::prelude::*;
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
// Begin game of life impl
use std::fmt;
#[wasm_bindgen]
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Cell {
Dead = 0,
Alive = 1,
}
#[wasm_bindgen]
pub struct Universe {
width: u32,
height: u32,
cells: Vec<Cell>,
}
impl fmt::Display for Universe {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for line in self.cells.as_slice().chunks(self.width as usize) {
for &cell in line {
let symbol = if cell == Cell::Dead { '◻' } else { '◼' };
write!(f, "{}", symbol)?;
}
write!(f, "\n")?;
}
Ok(())
}
}
impl Universe {
fn get_index(&self, row: u32, column: u32) -> usize {
(row * self.width + column) as usize
}
fn live_neighbor_count(&self, row: u32, column: u32) -> u8 {
let mut count = 0;
for delta_row in [self.height - 1, 0, 1].iter().cloned() {
for delta_col in [self.width - 1, 0, 1].iter().cloned() {
if delta_row == 0 && delta_col == 0 {
continue;
}
let neighbor_row = (row + delta_row) % self.height;
let neighbor_col = (column + delta_col) % self.width;
let idx = self.get_index(neighbor_row, neighbor_col);
count += self.cells[idx] as u8;
}
}
count
}
}
/// Public methods, exported to JavaScript.
#[wasm_bindgen]
impl Universe {
pub fn tick(&mut self) {
let mut next = self.cells.clone();
for row in 0..self.height {
for col in 0..self.width {
let idx = self.get_index(row, col);
let cell = self.cells[idx];
let live_neighbors = self.live_neighbor_count(row, col);
let next_cell = match (cell, live_neighbors) {
// Rule 1: Any live cell with fewer than two live neighbours
// dies, as if caused by underpopulation.
(Cell::Alive, x) if x < 2 => Cell::Dead,
// Rule 2: Any live cell with two or three live neighbours
// lives on to the next generation.
(Cell::Alive, 2) | (Cell::Alive, 3) => Cell::Alive,
// Rule 3: Any live cell with more than three live
// neighbours dies, as if by overpopulation.
(Cell::Alive, x) if x > 3 => Cell::Dead,
// Rule 4: Any dead cell with exactly three live neighbours
// becomes a live cell, as if by reproduction.
(Cell::Dead, 3) => Cell::Alive,
// All other cells remain in the same state.
(otherwise, _) => otherwise,
};
next[idx] = next_cell;
}
}
self.cells = next;
}
pub fn new() -> Universe {
let width = 64;
let height = 64;
let cells = (0..width * height)
.map(|i| {
if i % 2 == 0 || i % 7 == 0 {
Cell::Alive
} else {
Cell::Dead
}
})
.collect();
Universe {
width,
height,
cells,
}
}
pub fn render(&self) -> String {
self.to_string()
}
}
Simply removing the render function at the bottom of this file causes the build to succeed. Replacing the render function with any function returning a String causes the build to fail. Why?
It turns out that this is not expected behavior; instead it is a bug with wasm-pack.
The issue can be resolved for now by adding the following to the project's cargo.toml:
[package.metadata.wasm-pack.profile.release]
wasm-opt = ["-Oz", "--enable-mutable-globals"]

Union-Find implementation does not update parent tags

I'm trying to create some sets of Strings and then merge some of these sets so that they have the same tag (of type usize). Once I initialize the map, I start adding strings:
self.clusters.make_set("a");
self.clusters.make_set("b");
When I call self.clusters.find("a") and self.clusters.find("b"), different values are returned, which is fine because I haven't merged the sets yet. Then I call the following method to merge two sets
let _ = self.clusters.union("a", "b");
If I call self.clusters.find("a") and self.clusters.find("b") now, I get the same value. However, when I call the finalize() method and try to iterate through the map, the original tags are returned, as if I never merged the sets.
self.clusters.finalize();
for (address, tag) in &self.clusters.map {
self.clusterizer_writer.write_all(format!("{};{}\n", address,
self.clusters.parent[*tag]).as_bytes()).unwrap();
}
// to output all keys with the same tag as a list.
let a: Vec<(usize, Vec<String>)> = {
let mut x = HashMap::new();
for (k, v) in self.clusters.map.clone() {
x.entry(v).or_insert_with(Vec::new).push(k)
}
x.into_iter().collect()
};
I can't figure out why this is the case, but I'm relatively new to Rust; maybe its an issue with pointers?
Instead of "a" and "b", I'm actually using something like utils::arr_to_hex(&input.outpoint.txid) of type String.
This is the Rust implementation of the Union-Find algorithm that I am using:
/// Tarjan's Union-Find data structure.
#[derive(RustcDecodable, RustcEncodable)]
pub struct DisjointSet<T: Clone + Hash + Eq> {
set_size: usize,
parent: Vec<usize>,
rank: Vec<usize>,
map: HashMap<T, usize>, // Each T entry is mapped onto a usize tag.
}
impl<T> DisjointSet<T>
where
T: Clone + Hash + Eq,
{
pub fn new() -> Self {
const CAPACITY: usize = 1000000;
DisjointSet {
set_size: 0,
parent: Vec::with_capacity(CAPACITY),
rank: Vec::with_capacity(CAPACITY),
map: HashMap::with_capacity(CAPACITY),
}
}
pub fn make_set(&mut self, x: T) {
if self.map.contains_key(&x) {
return;
}
let len = &mut self.set_size;
self.map.insert(x, *len);
self.parent.push(*len);
self.rank.push(0);
*len += 1;
}
/// Returns Some(num), num is the tag of subset in which x is.
/// If x is not in the data structure, it returns None.
pub fn find(&mut self, x: T) -> Option<usize> {
let pos: usize;
match self.map.get(&x) {
Some(p) => {
pos = *p;
}
None => return None,
}
let ret = DisjointSet::<T>::find_internal(&mut self.parent, pos);
Some(ret)
}
/// Implements path compression.
fn find_internal(p: &mut Vec<usize>, n: usize) -> usize {
if p[n] != n {
let parent = p[n];
p[n] = DisjointSet::<T>::find_internal(p, parent);
p[n]
} else {
n
}
}
/// Union the subsets to which x and y belong.
/// If it returns Ok<u32>, it is the tag for unified subset.
/// If it returns Err(), at least one of x and y is not in the disjoint-set.
pub fn union(&mut self, x: T, y: T) -> Result<usize, ()> {
let x_root;
let y_root;
let x_rank;
let y_rank;
match self.find(x) {
Some(x_r) => {
x_root = x_r;
x_rank = self.rank[x_root];
}
None => {
return Err(());
}
}
match self.find(y) {
Some(y_r) => {
y_root = y_r;
y_rank = self.rank[y_root];
}
None => {
return Err(());
}
}
// Implements union-by-rank optimization.
if x_root == y_root {
return Ok(x_root);
}
if x_rank > y_rank {
self.parent[y_root] = x_root;
return Ok(x_root);
} else {
self.parent[x_root] = y_root;
if x_rank == y_rank {
self.rank[y_root] += 1;
}
return Ok(y_root);
}
}
/// Forces all laziness, updating every tag.
pub fn finalize(&mut self) {
for i in 0..self.set_size {
DisjointSet::<T>::find_internal(&mut self.parent, i);
}
}
}
I think you're just not extracting the information out of your DisjointSet struct correctly.
I got sniped by this and implemented union find. First, with a basic usize implemention:
pub struct UnionFinderImpl {
parent: Vec<usize>,
}
Then with a wrapper for more generic types:
pub struct UnionFinder<T: Hash> {
rev: Vec<Rc<T>>,
fwd: HashMap<Rc<T>, usize>,
uf: UnionFinderImpl,
}
Both structs implement a groups() method that returns a Vec<Vec<>> of groups. Clone isn't required because I used Rc.
Playground

What is the best implementation of a recursive struct?

I want to implement a Treep by rust. The node struct of Treep is
#[derive(Clone)]
struct TreepNode {
data: i32,
left: Option<Box<TreepNode>>,
right: Option<Box<TreepNode>>,
}
Then I define a function to implement the right rotate operation.
fn rightRotate(&self) -> Box<TreepNode> {
match self.clone().left {
None => return Box::new(self.clone()),
Some(ref mut leftTree) => {
let mut selfTree = self.clone();
selfTree.left = leftTree.right.clone();
leftTree.right = Some(Box::new(selfTree));
return leftTree.clone()
}
}
}
This code can be compiled. However, the code is ugly because there are lot of clone() and Some in it. Is there any better way to optimize the code?
You can avoid clone() if you consume Self:
fn right_rotate(mut self) -> Box<TreepNode> {
match self.left.take() {
None => Box::new(self),
Some(mut left) => {
self.left = left.right.take();
left.right = Some(Box::new(self));
left
}
}
}

Resources