What is the right way to initialize a struct within another struct? - struct

What is the right way to do something like this?
struct Child {
field: i32,
}
struct Parent {
child: Child,
}
...
let parent: Parent = Parent {
child { field: 0 },
};
This does work, but is more verbose than I'd like:
let child: Child = Child {
field: 0,
};
let parent: Parent = Parent {
child: child,
};

Just embed the literal:
Parent {
child: Child {
field: 0,
},
};

Related

How can I implement a smart constructor for a struct with reference fields?

Background
I am doing the wgpu tutorial.
In an early lesson, there is the following code:
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Render Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
r: 0.1,
g: 0.2,
b: 0.3,
a: 1.0,
}),
store: true,
},
})],
depth_stencil_attachment: None,
});
Since most of the RenderPassDescriptor struct is boilerplate, I would like to factor the creation of RenderPassDescriptor into another function. I tried to create the function like this:
pub fn make_render_pass_descriptor(view: &wgpu::TextureView, clear_color: wgpu::Color) -> wgpu::RenderPassDescriptor {
wgpu::RenderPassDescriptor {
label: Some("Render Pass"),
color_attachments: &[
Some(wgpu::RenderPassColorAttachment {
view: view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(clear_color),
store: true,
},
})
],
depth_stencil_attachment: None,
}
}
Which would let me replace the original code with the following:
let descriptor = make_render_pass_descriptor(view, clear_color);
let mut render_pass = encoder.begin_render_pass(&descriptor);
The Problem
Unfortunately, since color_attachments is set to a temporary constant &[...], I get the following error:
error[E0515]: cannot return value referencing temporary value
Question
Ideally, I would like to tell the compiler to extend the lifetime of the temporary constant to the calling function's lifetime.
Is this possible? If not, what is an idiomatic way to factor out the creation of the RenderPassDescriptor?
wgpu “descriptors” are basically just complex named arguments for a function. Keep them together with their function calls, and you won't have these borrowing problems:
pub fn begin_render_pass<'p>(
encoder: &'p mut wgpu::CommandEncoder,
view: &wgpu::TextureView,
clear_color: wgpu::Color,
) -> wgpu::RenderPass<'p> {
encoder.begin_render_pass(wgpu::RenderPassDescriptor {
label: Some("Render Pass"),
color_attachments: &[
Some(wgpu::RenderPassColorAttachment {
view: view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(clear_color),
store: true,
},
})
],
depth_stencil_attachment: None,
})
}

Need to access argument of enum

Working with bevy_mod_picking crate.
In the callback event when you pick a mesh the example code has:
pub fn print_events(mut events: EventReader<PickingEvent>) {
for event in events.iter() {
match event {
PickingEvent::Selection(e) => info!("selection {:?}", e),
PickingEvent::Hover(e) => info!("hover event {:?}", e),
PickingEvent::Clicked(e) => info!("click {:?}", e),
}
}
}
I need to access the Entity in all cases.
Clicked(e) is already an entity so I can modify it to use an Entity method:
PickingEvent::Clicked(e) => {
info!("click {}", e.id());
},
The others are of type:
pub enum SelectionEvent {
JustSelected(Entity),
JustDeselected(Entity),
}
and
pub enum HoverEvent {
JustEntered(Entity),
JustLeft(Entity),
}
My question is two fold:
When I run the program and select a mesh "selection JustSelected(1v0)" is printed.
1 in this case is the Entity id but I don't understand the construction 1v0. What is v in this case? Is this some sort way of printing a tuple?
Most importantly how do I modify the event handler to use the e argument of Selection(e)? As with Clicked(e) I would like to print the Entity id number of the selected mesh. Eg:
PickingEvent::Selection(e) => info!("selection {}", e/magic grammar here/.id()),
EDIT - ADDED FULL CODE FOR CONTEXT
use bevy::{
prelude::*,
window::{PresentMode, RequestRedraw},
winit::WinitSettings,
};
use bevy_mod_picking::*; // raycaster
fn main() {
App::new()
.insert_resource(Msaa { samples: 4 })
.insert_resource(WinitSettings::desktop_app())
.add_plugins(DefaultPlugins)
.add_plugins(DefaultPickingPlugins)
.add_plugin(DebugCursorPickingPlugin)
.add_startup_system(setup)
.add_system_to_stage(CoreStage::PostUpdate, print_events)
.run();
}
pub fn print_events(mut events: EventReader<PickingEvent>) {
for event in events.iter() {
match event {
PickingEvent::Selection(e) => info!("selection {:?}", e),
PickingEvent::Hover(e) => info!("hover event {:?}", e),
PickingEvent::Clicked(e) => {
info!("click {}", e.id());
},
}
}
}
fn setup(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let texture_handle = asset_server.load("Topo_small.png");
let icosphere_handle = meshes.add(Mesh::from(shape::Icosphere { subdivisions: 8, radius: 2.0 }));
let icosphere_material_handle = materials.add(StandardMaterial {
base_color: Color::rgb(0.8, 0.7, 0.6),
..default()
});
// this material renders the texture normally
let material_handle = materials.add(StandardMaterial {
base_color_texture: Some(texture_handle.clone()),
..default()
});
// parent icosphere
commands
.spawn_bundle(PbrBundle {
mesh: icosphere_handle.clone(),
material: material_handle,
transform: Transform::from_xyz(0.0, 0.0, 1.0),
..default()
})
.insert_bundle(PickableBundle::default());
// light
commands.spawn_bundle(PointLightBundle {
transform: Transform::from_xyz(4.0, 5.0, -4.0),
..default()
});
// camera
commands.spawn_bundle(PerspectiveCameraBundle {
transform: Transform::from_xyz(5.0, 10.0, 10.0).looking_at(Vec3::ZERO, Vec3::Y),
..default()
})
.insert_bundle(PickingCameraBundle::default());
}
Based on the comment I was actually able to get it by modifying the Selection match to:
PickingEvent::Selection(e) => {
if let SelectionEvent::JustSelected(e) = e {
info!("selection ID {}", e.id());
}
info!("selection {:?}", e)
},
So I've run into the same problem and based on the proposed solution, I elaborated a bit more :
By using a Query, you can actually find the interactable entity (eg. hovered) and get its components from the Query:
pub fn select_and_change_color(
mut events: EventReader<PickingEvent>,
mut materials: ResMut<Assets<StandardMaterial>>,
query: Query<(Entity, &Handle<StandardMaterial>)>,
) {
for event in events.iter() {
match event {
PickingEvent::Selection(e) => {
if let SelectionEvent::JustSelected(selected_entity) = e {
// retrieve the selected entity in the query
let (entity, material_handle) = query.get(*selected_entity).unwrap();
// Now you have access to both the entity and one of its
// component: its material. You can for example change the color of it.
let material = materials.get_mut(material_handle).unwrap();
material.base_color = Color::rgb(0.9, 0.1, 0.9);
}
},
PickingEvent::Hover(e) => info!("hover event {:?}", e),
PickingEvent::Clicked(e) => {
info!("click {}", e.id());
},
}
}
}
The parameter materials is a Unique mutable borrow of a resource and gives you a way to retrieve assets from the World.

How to initialize a known array in method

In the following code, I want automatically initialize my array:
struct ColorQueue {
queue: String,
color: String,
}
impl ColorQueue {
pub fn new(queue: &str) -> Self {
Self {
queue: String::from(queue),
color: "".to_string(),
}
}
fn name_colors(&self) {
let colorqueue = [
ColorQueue {
queue: "amig".to_string(),
color: "HRED".to_string(),
},
ColorQueue {
queue: "micmac".to_string(),
color: "GRN".to_string(),
},
ColorQueue {
queue: "ssfa".to_string(),
color: "YEL".to_string(),
},
ColorQueue {
queue: "chrody".to_string(),
color: "BLU".to_string(),
},
ColorQueue {
queue: "ngs".to_string(),
color: "MAG".to_string(),
},
ColorQueue {
queue: "emc2".to_string(),
color: "CYN".to_string(),
},
ColorQueue {
queue: "cryoem".to_string(),
color: "WHT".to_string(),
},
ColorQueue {
queue: "common".to_string(),
color: "BWHT".to_string(),
},
ColorQueue {
queue: "lowprio".to_string(),
color: "RED".to_string(),
},
ColorQueue {
queue: "bim".to_string(),
color: "BCYN".to_string(),
},
ColorQueue {
queue: "runxx".to_string(),
color: "BBLU".to_string(),
},
];
}
pub fn set_queue_name(&mut self, queue: String) {
self.queue = queue;
}
pub fn get_color(&self) -> &String {
for item in 1..self.colorqueue.len() {
if self.queue == self.colorqueue[item].queue {
return &self.colorqueue[item].color;
}
}
}
pub fn get_queue_name(&self) -> &String {
return &self.queue;
}
}
fn main() {
let mut cqueue = ColorQueue::new(&"amig");
ColorQueue::set_queue_name("amig".to_string());
println!("{}", cqueue.get_queue_name());
cqueue.set_queue_name("ngs".to_string());
println!("{}", cqueue.get_queue_name())
}
For now I can assign a queue. What I want is a function get_color(queue) that returns the color field, depending on queue name.
This should return "MAG":
cqueue.set_queue_name("ngs".to_string());
cqueue.get_color();
But I must initialize my array in the object.
In essence you want to get a predefined color for a given queue ID.
First, let's make a place for the default colors.
I'd make a module for that:
pub mod queue_default_colors { ... }
and in there have a private static variable:
static default_colors: &[(&'static str, &'static str)] = &[
("amig", "HRED"),
("micmac", "GRN"),
...
];
And based on that implement your function:
pub fn get(queue_id: &str) -> Option<&'static str> {
default_colors.iter()
.find(|pair| pair.0 == queue_id)
.map(|pair| pair.1)
}
Note that it returns Option, because queue_id can be custom (unmapped).
This can be used like so:
let color = queue_default_colors::get("amig"); // Some("HRED")
It is possible to optimize this if you change default_colors to a HashMap, but then you need to initialize it. See here for the options - https://stackoverflow.com/a/32956193/1009546

How to correctly iterate all records of a multi-level depth structure in Rust?

I would like to know how to iterate correctly in Rust all results contained in a data structure arranged like this:
struct Node {
id: i64,
nodes: Vec<Node>
}
Where the records inserted in this structure have several levels of depth. Something like:
{id: 1, nodes: [
{id: 2, nodes: [
{id: 3, nodes: []},
{id: 4, nodes: []},
{id: 5, nodes: [
{id: 6, nodes: []},
{id: 7, nodes: [
{id: 8, nodes: []},
{id: 9, nodes: []}
]}
]}
]}
]};
I created a simple recursive function to handle the problem and everything is fine now. I do not know what was my mistake yesterday when I created this topic. The real problem is little different from what I asked for, but the essence is the same:
use std::vec::Vec;
struct Node {
id: i64,
nodes: Vec<Node>,
focused: bool,
}
struct Controller {
focused: i32,
}
impl Controller {
fn get_focused(&mut self) -> i32 {
let nodes: Node = ....; // code skipped. represented with JSON object above, but with 'focused' member
for node in nodes.iter() {
self.focused = self.node_iterator(node);
}
self.focused
}
fn node_iterator(&self, node: Node) -> i32 {
let mut focused: i32 = 0;
if node.nodes.len() > 0 {
for n in node.nodes.iter() {
if n.nodes.len() > 0 {
focused = self.node_iterator(n);
if focused > 0 {
return focused;
}
} else {
if n.focused == true {
focused = n.id as i32;
return focused;
}
}
}
}
return 0;
}
}
fn main() {
let mut controller = Controller { focused: 0 };
controller.get_focused();
println!("{}", controller.focused);
}

"thread '<main>' has overflowed its stack" when constructing a large tree

I implemented a tree struct:
use std::collections::VecDeque;
use std::rc::{Rc, Weak};
use std::cell::RefCell;
struct A {
children: Option<VecDeque<Rc<RefCell<A>>>>
}
// I got thread '<main>' has overflowed its stack
fn main(){
let mut tree_stack: VecDeque<Rc<RefCell<A>>> = VecDeque::new();
// when num is 1000, everything works
for i in 0..100000 {
tree_stack.push_back(Rc::new(RefCell::new(A {children: None})));
}
println!("{:?}", "reach here means we are not out of mem");
loop {
if tree_stack.len() == 1 {break;}
let mut new_tree_node = Rc::new(RefCell::new(A {children: None}));
let mut tree_node_children: VecDeque<Rc<RefCell<A>>> = VecDeque::new();
// combine last two nodes to one new node
match tree_stack.pop_back() {
Some(x) => {
tree_node_children.push_front(x);
},
None => {}
}
match tree_stack.pop_back() {
Some(x) => {
tree_node_children.push_front(x);
},
None => {}
}
new_tree_node.borrow_mut().children = Some(tree_node_children);
tree_stack.push_back(new_tree_node);
}
}
Playpen link
But it crashes with
thread '<main>' has overflowed its stack
How do I fix that?
The problem that you are experiencing is because you have a giant linked-list of nodes. When that list is dropped, the first element tries to free all the members of the struct first. That means that the second element does the same, and so on, until the end of the list. This means that you will have a call stack that is proportional to the number of elements in your list!
Here's a small reproduction:
struct A {
children: Option<Box<A>>
}
fn main() {
let mut list = A { children: None };
for _ in 0..1_000_000 {
list = A { children: Some(Box::new(list)) };
}
}
And here's how you would fix it:
impl Drop for A {
fn drop(&mut self) {
if let Some(mut child) = self.children.take() {
while let Some(next) = child.children.take() {
child = next;
}
}
}
}
This code overrides the default recursive drop implementation with an iterative one. It rips the children out of the node, replacing it with a terminal item (None). It then allows the node to drop normally, but there will be no recursive calls.
The code is complicated a bit because we can't drop ourselves, so we need to do a little two-step dance to ignore the first item and then eat up all the children.
See also:
How can I swap in a new value for a field in a mutable reference to a structure?
How do I move out of a struct field that is an Option?

Resources