I have an object of a struct with one field from an external library, which is defined as: pub struct SomeId(pub i64);
Using println! to print the object shows this, for example: SomeId(123)
I created my own struct:
#[derive(Debug)]
pub struct Something {
pub id: i64,
}
And I'm trying to put value from external struct SomeId to field id in my struct Something:
let test = Something { id: ?? };
or extract value from struct SomeId:
let test: i64 = ??;
It's also possible to use struct destructuring to extract value from SomeId.
pub struct SomeId(pub i64);
#[derive(Debug)]
pub struct Something {
pub id: i64,
}
fn main() {
let some_id = SomeId(42);
let SomeId(id) = some_id;
let test = Something { id: id };
let test: i64 = id;
}
Link to more examples.
You should probably try
let test = Something { id: external_struct.0 };
or, to the second question,:
let test = external_struct.0;
These structs , of the form , struct structname(variables...) are called tuple structs and acts very similar to tuples in rust.
May be you are looking for something like the below?
pub struct SomeId(i32);
#[derive(Debug)]
pub struct Something {
pub id: i32,
}
fn main() {
let sid = SomeId(10);
let sth = Something { id: sid.0 };
println!("{:?}", sth);
}
Playground link
Related
I have the following:
struct Health {
health: f32,
}
struct Position {
position: Vec2,
}
struct Collections {
healths: Vec<Health>,
positions: Vec<Position>,
}
I would like to generate the Collections struct automatically; I am thinking using a macro?
I thought perhaps I could mark each struct I want to include with a custom attribute and then have a macro which builds the Collections struct.
How could I do this?
To be able to do something like custom attributes you need to write a proc_macro, that can do almost anything you need with your code.
For a simpler solution you may try with a normal macro_rules. For that you will need to enclose your type definitions into a macro that does the parsing, and emits back the type definition plus the extra code you need, in your case the Container class.
Something like this:
macro_rules! collectables {
(
$(
#[collection=$fname:ident]
$(#[$attr:meta])?
$vis:vis struct $name:ident $def:tt
)*
) => {
// The struct definitions
$(
$(#[$attr])?
$vis struct $name $def
)*
// The container
#[derive(Default, Debug)]
pub struct Collections {
$(
$fname: Vec<$name>,
)*
}
};
}
Now you can use the macro to build your original code (playground):
collectables!{
#[collection=healths]
#[derive(Debug)]
struct Health {
health: f32,
}
#[collection=positions]
#[derive(Debug)]
struct Position {
position: (f32, f32),
}
}
Note that as written the #[collection=xxx] attribute is mandatory and must be the first in every struct definition.
So I managed to solve this problem using a proc_macro. Each struct which is to be included in the final Storage struct is marked with the Component derive attribute. The Storage struct is then built with the storage!() macro.
use lazy_static::lazy_static;
use proc_macro::TokenStream;
use quote::quote;
use std::sync::Mutex;
use syn::{parse_macro_input, parse_str, DeriveInput, ExprType};
lazy_static! {
static ref COMPONENTS: Mutex<Vec<String>> = Mutex::new(Vec::new());
}
#[proc_macro_derive(Component)]
pub fn component(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput); ‣DeriveInput
let ident = input.ident; ‣Ident
COMPONENTS.lock().unwrap().push(ident.to_string());
let expanded = quote! { ‣TokenStream
impl component::Component for #ident {}
};
TokenStream::from(expanded)
}
#[proc_macro]
pub fn storage(_input: TokenStream) -> TokenStream {
println!("Building Storage with: {:?}", COMPONENTS.lock().unwrap());
let mut fields = Vec::new(); ‣Vec<ExprType>
for type_name in COMPONENTS.lock().unwrap().iter() { ‣&String
let field = parse_str::<ExprType>( ‣ExprType
format!("{}s: Vec<{}>", type_name.to_lowercase(), type_name).as_str(),
) ‣Result<ExprType, Error>
.expect("Could not parse component field type");
fields.push(field);
}
let expanded = quote! { ‣TokenStream
#[derive(Serialize, Deserialize, Debug, Default)]
struct Storage {
#(#fields),*
}
};
TokenStream::from(expanded)
}
#[derive(Debug, Serialize, Deserialize, Component)]
struct Health {
health: f32,
}
#[derive(Debug, Serialize, Deserialize, Component)]
pub struct Age {
pub age: u64,
}
storage!();
I am using rust rocket as the http server side. On the server side, I define a rust struct like this to receive the data from client side:
#[derive(Deserialize, Serialize)]
#[allow(non_snake_case)]
pub struct PlayRecordRequest {
pub id: i64,
pub title: String,
pub url: String,
pub mvId: i64,
pub album: MusicAlbum,
pub artist: Vec<Artist>,
}
and recieve in the http controller like this:
#[post("/user/v1/save-play-record", data = "<record>")]
pub fn save_play_record<'r>(
record: Json<PlayRecordRequest>,
) -> content::Json<String> {
info!("save play record,title:{}",record.title);
save_play_record_impl(record);
let res = ApiResponse {
result: "ok".to_string(),
..Default::default()
};
let result_json = serde_json::to_string(&res).unwrap();
return content::Json(result_json);
}
the problem is that when the client side did not have some fields, the code run into error. is it possible to auto fit the field for Deserialize, if the client have the field, Deserialize it normally, if the client did not contains some fields, just ignore it and do not run into error. I read the official document of serde and find the skip annotation. But the annotation just use to mark the field should be ignored, what I want is that the struct could auto fit all field exists or not. is it possible to do like this?
There are two ways to handle this.
First is with options. Options imply that the data may or may not exist. If the data is null or missing it convert to an Option::none value. You can preserve the lack of data on serialization if you add #[serde(skip_serializing_if = "Option::is_none")]
Second option is to apply defaults to the value if the data is missing. Although from your use case this doesn't seem to be ideal.
Here is a code snippet of the two cases that you can run on https://play.rust-lang.org/:
use::serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize, Debug)]
#[allow(non_snake_case)]
pub struct Foo {
#[serde(skip_serializing_if = "Option::is_none")]
pub bar: Option<i64>,
#[serde(default = "default_baz")]
pub baz: i64,
}
fn default_baz()-> i64{
3
}
fn main(){
let data = r#"{"bar": null, "baz": 1}"#;
let v: Foo = serde_json::from_str(data).unwrap();
println!("{:#?}", v);
let s = serde_json::to_string(&v).unwrap();
println!("Don't serialize None values: {:#?}", s);
let data = r#"{"missing_bar": null}"#;
let v: Foo = serde_json::from_str(data).unwrap();
println!("{:#?}", v)
}
I have an object of a struct with one field from an external library, which is defined as: pub struct SomeId(pub i64);
Using println! to print the object shows this, for example: SomeId(123)
I created my own struct:
#[derive(Debug)]
pub struct Something {
pub id: i64,
}
And I'm trying to put value from external struct SomeId to field id in my struct Something:
let test = Something { id: ?? };
or extract value from struct SomeId:
let test: i64 = ??;
It's also possible to use struct destructuring to extract value from SomeId.
pub struct SomeId(pub i64);
#[derive(Debug)]
pub struct Something {
pub id: i64,
}
fn main() {
let some_id = SomeId(42);
let SomeId(id) = some_id;
let test = Something { id: id };
let test: i64 = id;
}
Link to more examples.
You should probably try
let test = Something { id: external_struct.0 };
or, to the second question,:
let test = external_struct.0;
These structs , of the form , struct structname(variables...) are called tuple structs and acts very similar to tuples in rust.
May be you are looking for something like the below?
pub struct SomeId(i32);
#[derive(Debug)]
pub struct Something {
pub id: i32,
}
fn main() {
let sid = SomeId(10);
let sth = Something { id: sid.0 };
println!("{:?}", sth);
}
Playground link
I have struct from which I want to extract the data.
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RunResult {
pub runs: Vec<RunDetails>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RunDetails {
pub details: String,
pub name: String,
pub id: String,
pub type: String,
}
I am getting the data which got inserted in above struct in the variable result which I am iterating below
let my_result:RunResult = result
.runs
.into_iter()
.filter(|line| line.details.contains(&"foo"))
.collect();
I am getting the error as
value of type `RunResult` cannot be built from `std::iter::Iterator<Item=RunDetails>`
I want to get the record where type=OK, details contains foo with highest id.
How can I achieve this?
Check out the documentation for collect here.
Your struct RunResult should implement FromIterator<RunDetails>.
Try adding this (untested by me):
impl FromIterator<RunDetails> for RunResult {
fn from_iter<I: IntoIterator<Item=RunDetails>>(iter: I) -> Self {
Self {
runs: Vec::from_iter(iter);
}
}
}
I have a Rust struct like this:
pub struct SomeMapping {
pub id: String,
pub other_id: Option<String>,
pub yet_another_id: Option<String>,
pub very_different_id: Option<String>
}
What is the simplest way to check if all optional ids are not set? I know the syntax like
if let Some(x) = option_value {...}
to extract a value from an Option, but I don't get how to use this in a concise way to check multiple values for None.
You can destructure a structure in pattern matching like so:
pub struct SomeMapping {
pub id: String,
pub other_id: Option<String>,
pub yet_another_id: Option<String>,
pub very_different_id: Option<String>,
}
fn main() {
let x = SomeMapping {
id: "R".to_string(),
other_id: Some("u".to_string()),
yet_another_id: Some("s".to_string()),
very_different_id: Some("t".to_string()),
};
if let SomeMapping {
id: a,
other_id: Some(b),
yet_another_id: Some(c),
very_different_id: Some(d),
} = x {
println!("{} {} {} {}", a, b, c, d);
}
}
It is documented in the Rust book chapter 18.