I'm attempting to parse a simple Rust file that looks like:
use std::result::Result;
fn init() {
}
In my main function, I read the file to a string, parse it, and then create a token stream which I then pass to syn::parse2. This returns an unexpected token error and I'm not sure why.
fn main() {
if let Err(error) = try_main() {
let _ = writeln!(io::stderr(), "{}", error);
process::exit(1);
}
}
fn try_main() -> Result<(), Error> {
let filepath = PathBuf::from("./src/file-to-parse.rs");
let code = fs::read_to_string(&filepath).map_err(Error::ReadFile)?;
let syntax = syn::parse_file(&code).map_err({
|error| Error::ParseFile {
error,
filepath,
source_code: code,
}
})?;
let token_stream = syntax.to_token_stream();
let item: Result<Item, syn::Error> = syn::parse2(token_stream);
match item {
Ok(mut v) => {
println!("success!");
}
Err(error) => {
println!("{:?}", error.to_compile_error());
}
}
}
The full error it returns me is:
TokenStream [Ident { sym: compile_error, span: bytes(56..58) }, Punct { char: '!', spacing: Alone, span: bytes(56..58) }, Group { delimiter: Brace, stream: TokenStream [Literal { lit: "unexpected token", span: bytes(56..58) }], span: bytes(56..58) }]
What's even more confusing to me is that if I remove the import and keep the function, it parses fine. Also if I remove the function and keep the import it parses fine. It's only when I keep both of them that I get an error. Does this mean that it's an issue with the empty line?
The reason your program throws an error is because your input code has two items (use and fn) but you're attempting to parse the whole thing as a single Item with the syn::parse2 line. This also explains why it works if you remove either the use or the fn.
If you want all the top level items in the code, you can already get that from the File struct that syn::parse_file returns:
fn main() {
let code = "use std::result::Result;
fn init() {
}";
let file = syn::parse_file(&code).unwrap();
dbg!(file.items);
}
[src/main.rs:9] file.items = [
Use(
ItemUse {
attrs: [],
vis: Inherited,
use_token: Use,
leading_colon: None,
tree: Path(
UsePath {
ident: Ident {
sym: std,
span: bytes(5..8),
},
colon2_token: Colon2,
tree: Path(
UsePath {
ident: Ident {
sym: result,
span: bytes(10..16),
},
colon2_token: Colon2,
tree: Name(
UseName {
ident: Ident {
sym: Result,
span: bytes(18..24),
},
},
),
},
),
},
),
semi_token: Semi,
},
),
Fn(
ItemFn {
attrs: [],
vis: Inherited,
sig: Signature {
constness: None,
asyncness: None,
unsafety: None,
abi: None,
fn_token: Fn,
ident: Ident {
sym: init,
span: bytes(30..34),
},
generics: Generics {
lt_token: None,
params: [],
gt_token: None,
where_clause: None,
},
paren_token: Paren,
inputs: [],
variadic: None,
output: Default,
},
block: Block {
brace_token: Brace,
stmts: [],
},
},
),
]
Playground
Related
I'm struggling using list_append programmatically in Rust.
I have a table called Humidities:
{
"id": 177,
"Measurements": [
49
]
}
and I want to add elements. For example:
{
"id": 177,
"Measurements": [
49,
53
]
}
This is a working solution for python, which I've found here :
table = get_dynamodb_resource().Table("table_name")
result = table.update_item(
Key={
'hash_key': hash_key,
'range_key': range_key
},
UpdateExpression="SET some_attr = list_append(some_attr, :i)",
ExpressionAttributeValues={
':i': [some_value],
},
ReturnValues="UPDATED_NEW"
)
if result['ResponseMetadata']['HTTPStatusCode'] == 200 and 'Attributes' in result:
return result['Attributes']['some_attr']
Based on the python solution I've tried this:
#[tokio::main]
async fn main() -> Result<(), Error> {
let Opt { base } = Opt::from_args();
let shared_config = make_config(base).await?;
let client = Client::new(&shared_config);
client
.update_item()
.table_name("Humidities")
.key("id", AttributeValue::N(177.to_string()))
.update_expression("SET i = list_append(Measurements, :i)")
.expression_attribute_values("i", AttributeValue::N(53.to_string()))
.send()
.await?;
Ok(())
}
However, the result is:
Error: Unhandled(Error { code: Some("ValidationException"), message: Some("ExpressionAttributeValues contains invalid key: Syntax error; key: \"i\""), request_id: Some("05RSFGFJEEDPO7850LI2T91RGRVV4KQNSO5AEMVJF66Q9ASUAAJG"), extras: {} })
What am I doing wrong?
The examples only demonstrate how to add a single item: https://github.com/awslabs/aws-sdk-rust/blob/main/examples/dynamodb/src/bin/add-item.rs
I've also tried this:
#[tokio::main]
async fn main() -> Result<(), Error> {
let Opt { base } = Opt::from_args();
let shared_config = make_config(base).await?;
let client = Client::new(&shared_config);
client
.update_item()
.table_name("Humidities")
.key("id", AttributeValue::N(177.to_string()))
.update_expression("set #Measurements = list_append(#Measurements, :value)")
.expression_attribute_names("#Measurements", "Measurements")
.expression_attribute_values("value", AttributeValue::N(53.to_string()))
.return_values(aws_sdk_dynamodb::model::ReturnValue::AllNew)
.send()
.await?;
Ok(())
}
with a look at: Append a new object to a JSON Array in DynamoDB using NodeJS
Same result, value is unknown:
Error: Unhandled(Error { code: Some("ValidationException"), message: Some("ExpressionAttributeValues contains invalid key: Syntax error; key: \"value\""), request_id: Some("1A8VEOEVSB7LMAB47H12N7IKC7VV4KQNSO5AEMVJF66Q9ASUAAJG"), extras: {} })
I've found a solution. There have been two problems:
list_append expects two lists
expression_attribute_values expected :value instead of value
Running example:
async fn main() -> Result<(), Error> {
let Opt { base } = Opt::from_args();
let shared_config = make_config(base).await?;
let client = Client::new(&shared_config);
client
.update_item()
.table_name("Humidities")
.key("id", AttributeValue::N(177.to_string()))
.update_expression("set #Measurements = list_append(#Measurements, :value)")
.expression_attribute_names("#Measurements", "Measurements")
.expression_attribute_values(
":value", // changed from "value" to ":value"
AttributeValue::L(vec![AttributeValue::N(53.to_string())]), // use a vector of numbers instead of a number
)
.return_values(aws_sdk_dynamodb::model::ReturnValue::AllNew)
.send()
.await?;
Ok(())
}
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,
})
}
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.
I'm trying to implement an linked list for learning purposes. std::cell::RefCell and stc::rc::{Rc, Weak} are mainly used to store data into the list instance. Now I'm implementing fn pop, which consumes and returns a value in the first location in the list, but I don't know how to consume a value wrapped with Rc and RefCell.
Here is my code:
use std::cell::RefCell;
use std::rc::{Rc, Weak};
#[derive(Debug)]
pub struct DbNode<T> {
data: T,
next: Option<Rc<RefCell<DbNode<T>>>>,
prev: Option<Weak<RefCell<DbNode<T>>>>,
}
#[derive(Debug)]
pub struct DbList<T> {
first: Option<Rc<RefCell<DbNode<T>>>>,
last: Option<Weak<RefCell<DbNode<T>>>>,
}
pub fn push_front(&mut self, data: T) {
match self.first.take() {
Some(e) => {
let new_front = Rc::new(RefCell::new(DbNode {
data,
next: Some(e.clone()),
prev: None,
}));
let mut me = e.borrow_mut();
me.prev = Some(Rc::downgrade(&new_front));
self.first = Some(new_front);
},
None => {
let new_data = Rc::new(RefCell::new(DbNode {
data,
next: None,
prev: None,
}));
self.last = Some(Rc::downgrade(&new_data));
self.first = Some(new_data);
},
}
}
pub fn push_back(&mut self, data: T) {
match self.last.take() {
Some(l) => {
let new_back = Rc::new(RefCell::new(DbNode {
data,
next: None,
prev: Some(l.clone()),
}));
let st = Weak::upgrade(&l).unwrap();
let mut ml = st.borrow_mut();
self.last = Some(Rc::downgrade(&new_back));
ml.next = Some(new_back);
},
None => {
let new_data = Rc::new(RefCell::new(DbNode {
data,
next: None,
prev: None,
}));
self.last = Some(Rc::downgrade(&new_data));
self.first = Some(new_data);
},
}
}
pub fn pop(&mut self) -> Option<T> {
match self.first.take() {
Some(f) => {
// How can I??
// let result = Some(f.into_inner().data);
// result
},
None => None,
}
}
What I want to achieve is to return the inner 'data' value in the struct DbNode located in the 'first' in struct DbList and set None to the 'first' in which the data to be consumed located if 'next' is None, else set 'next' to 'first'.
At first, I tried to consume the inner value with using Rc::downcast, but the type of 'f' in matching block was 'RefCell', not 'Rc', then I tried to use RefCell::into_inner(), but compiler says:
cannot move out of an Rc
move occurs because value has type std::cell::RefCell<ds::dll::DbNode<T>>, which does not implement the Copy trait
I totally understand what this means, but I don't know what I should do. What is the correct way to do it??
You were close. Use Rc::try_unwrap():
Returns the inner value, if the Rc has exactly one strong reference. Otherwise, an Err is returned with the same Rc that was passed in. This will succeed even if there are outstanding weak references.
pub fn pop(&mut self) -> Option<T> {
match self.first.take() {
Some(f) => {
match Rc::try_unwrap(f) {
Ok(refcell) => {
// you can do refcell.into_inner here
Some(refcell.into_inner().data)
},
Err(_) => {
// another Rc still exists so you cannot take ownership of the value
None
}
}
},
None => None,
}
}
In Rust, how should one go about grouping related structs so that a function signature can accept multiple different types while refering to the concrete type inside the method body?
The following example is contrived for simplicity:
enum Command {
Increment {quantity: u32},
Decrement {quantity: u32},
}
fn process_command(command: Command) {
match command {
Command::Increment => increase(command),
Command::Decrement => decrease(command),
};
}
fn increase(increment: Command::Increment) {
println!("Increasing by: {}.", increment.quantity);
}
fn decrease(decrement: Command::Decrement) {
println!("Decreasing by: {}.", decrement.quantity);
}
fn main() {
let input = "Add";
let quantity = 4;
let command: Command = match input {
"Add" => Command::Increment { quantity: quantity },
"Subtract" => Command::Decrement { quantity: quantity },
_ => unreachable!(),
};
process_command(command);
}
Compiling results in the following two errors:
src/main.rs:13:24: 13:42 error: found value name used as a type: DefVariant(DefId { krate: 0, node: 4 }, DefId { krate: 0, node: 5 }, true) [E0248]
src/main.rs:13 fn increase(increment: Command::Increment) {
^~~~~~~~~~~~~~~~~~
src/main.rs:17:24: 17:42 error: found value name used as a type: DefVariant(DefId { krate: 0, node: 4 }, DefId { krate: 0, node: 8 }, true) [E0248]
src/main.rs:17 fn decrease(decrement: Command::Decrement) {
^~~~~~~~~~~~~~~~~~
error: aborting due to 2 previous errors
If I declare the structs seperately, and wrap the structs within a tuple struct (correct terminology?) each within the enum then I get the expected result, but with the verbosity and similar type names all over the place I suspect that I've misunderstood someting:
struct Increment {
quantity: u32,
}
struct Decrement {
quantity: u32,
}
enum Command {
Increment(Increment),
Decrement(Decrement),
}
fn process_command(command: Command) {
match command {
Command::Increment(increment) => increase(increment),
Command::Decrement(decrement) => decrease(decrement),
};
}
fn increase(increment: Increment) {
println!("Increasing by: {}.", increment.quantity);
}
fn decrease(decrement: Decrement) {
println!("Decreasing by: {}.", decrement.quantity);
}
fn main() {
let input = "Add";
let quantity = 4;
let command: Command = match input {
"Add" => Command::Increment(Increment { quantity: quantity }),
"Subtract" => Command::Decrement(Decrement { quantity: quantity }),
_ => unreachable!(),
};
process_command(command);
}
Running outputs:
Increasing by: 4.
Is wrapping the struct within an enum type (terminology?) sharing the same name really the best solution? Command::Increment(Increment { quantity: 7 })
Yes, this is the best you will get along this line of implementation. An enum is one type only; its variants are purely that—variants, not types.
Another alternative is to use a trait and generics:
struct Increment {
quantity: u32,
}
struct Decrement {
quantity: u32,
}
trait Command {
fn process(self);
}
impl Command for Increment {
fn process(self) {
println!("Increasing by {}", self.quantity);
}
}
impl Command for Decrement {
fn process(self) {
println!("Decreasing by {}", self.quantity);
}
}
Of course, it’s not a direct parallel; if you want to store a command of potentially differing types you’ll need to change process to take self: Box<Self> or &self, and you’ll need to work with either Box<Command> or &Command, but it’s another way of doing things that may suit your requirements. And as far as the definitions are concerned, it’s purer.
I may be misunderstanding your simple example, but remember that you can implement methods on enums directly:
enum Command {
Increment {quantity: u32},
Decrement {quantity: u32},
}
impl Command {
fn process(self) {
match self {
Command::Increment { quantity } => {
println!("Increasing by: {}.", quantity)
},
Command::Decrement { quantity } => {
println!("Decreasing by: {}.", quantity)
},
};
}
}
fn main() {
let input = "Add";
let quantity = 4;
let command: Command = match input {
"Add" => Command::Increment { quantity: quantity },
"Subtract" => Command::Decrement { quantity: quantity },
_ => unreachable!(),
};
command.process();
}
I happen to like this version because it eliminates the redundancy of process_command(command).
What about this one, I am not sure I really understood your issue
enum Command {
Increment (u32),
Decrement (u32),
}
fn process_command(command: Command) {
match command {
Command::Increment(quantity) => increase(quantity),
Command::Decrement(quantity) => decrease(quantity),
};
}
fn increase(quantity: u32) {
println!("Increasing by: {}.", quantity);
}
fn decrease(quantity: u32) {
println!("Decreasing by: {}.", quantity);
}
fn main() {
let input = "Add";
let quantity = 4;
let command: Command = match input {
"Add" => Command::Increment (quantity),
"Subtract" => Command::Decrement (quantity),
_ => unreachable!(),
};
process_command(command);
}