I am using bindgen to generate code with the following config.
let mut builder = bindgen::Builder::default()
.clang_arg("-std=c++11")
.clang_arg("-x")
.clang_arg("c++")
.clang_arg("-Wno-pragma-once-outside-header")
.layout_tests(false)
.derive_copy(true)
.enable_cxx_namespaces()
.default_enum_style(EnumVariation::Rust {
non_exhaustive: false,
});
However I find that the generated code like
#[derive(Debug, Copy, Clone)]
pub struct RawCppPtr {
pub ptr: root::DB::RawVoidPtr,
pub type_: root::DB::RawCppPtrType,
}
I wonder if there are any ways that I can only generate #[derive(Clone)] without generating [derive(Copy)]?
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'm trying to acces a struct from the lib i'm creating to perform some unit tests.
here is a sample of the code:
src/token_deserializer.rs
use serde::Deserialize;
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Token {
pub payment_data: PaymentData,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PaymentData {
pub data: String,
pub signature: String,
pub header: String,
pub version: String,
}
src/lib.rs
use serde_json::from_str;
use token_deserializer::Token;
pub mod token_deserializer;
pub fn deserialize_token(token: &str) -> Token{
let object: Token = from_str(token).expect("JSON was not well-formatted");
return object;
}
tests/mytest.rs
#[cfg(test)]
mod tests {
use std::fs::File;
use apple_pay_token_decryptor::deserialize_token;
use apple_pay_token_decryptor::Token;
#[test]
fn test_token_deserialization(){
let mut file = File::open("text.json").unwrap();
let mut data = String::new();
let object: Token = deserialize_token(&data);
}
}
Here i can't manage to import Token for my test => error[E0603]: struct `Token` is private
Do i need to import it in lib.rs or something else ?
Inside your test, you refer to apple_pay_token_decryptor::Token. You may think it is resolved to the pub struct Token, but in fact, it is not. Instead, it refers to this use in src/lib.rs:
use token_deserializer::Token;
And while both the struct and the token_deserializer module are public - this import is private (it is not pub use, i.e. a reexport). But it's still there. And thus the compiler complains about you using a private type.
To fix, that you either have to reexport Token - i.e. make that pub use token_deserializer::Token;, or fix the test to import the struct directly from token_deserializer:
use apple_pay_token_decryptor::token_deserializer::Token;
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 defined a ProcessState structure:
#[derive(Clone, Debug, PartialEq, Default)]
pub struct ProcessState {
pub file_sample: FileSample,
pub estimate: Estimate,
pub estimate_cache: HashMap<String, Estimate>,
pub total_count: u64,
pub systems: HashMap<String, SystemState>,
pub aggregate_clock: u64,
pub aggregate_mean: f64,
pub file_samples: VecDeque<FileSample>,
}
How do I make use of the parse_from_bytes function on this? Do I need to define a proto message for my structure in order to use this method?
If I understand how this works, you can't implement this yourself: the API is designed to generate Rust code from a .proto file.
The doc says that the recommended way is to use protoc-rust to generate the code.
As for what to write in the .proto file, the doc is here.
The situation is (severely simplified) this (playpen):
mod tokentree {
pub struct TokenTree;
mod serialize {
use std::collections::BTreeMap;
use super::TokenTree;
#[derive(Debug)]
pub struct InternStr;
pub trait InternStrsExt {
fn intern_strs(&self) -> BTreeMap<&str, InternStr>;
}
impl InternStrsExt for [TokenTree] {
fn intern_strs(&self) -> BTreeMap<&str, InternStr> { BTreeMap::new() }
}
}
pub use self::serialize::{InternStrsExt, InternStr};
}
use tokentree::*;
fn main() {
println!("{:?}", [TokenTree].intern_strs());
}
I get the following error (both on nightly and beta):
<anon>:20:22: 20:47 error: source trait is inaccessible
<anon>:20 println!("{:?}", [TokenTree].intern_strs());
^~~~~~~~~~~~~~~~~~~~~~~~~
My problem is that I don't even know what this is supposed to mean.
It needs a pub declaration. Also your declarations are all over the place. Recommended form is to stick your pub mod declarations first, then, use.
Here is the working example.
mod tokentree {
pub struct TokenTree;
pub mod serialize {
use std::collections::BTreeMap;
use super::TokenTree;
#[derive(Debug)]
pub struct InternStr;
pub trait InternStrsExt {
fn intern_strs(&self) -> BTreeMap<&str, InternStr>;
}
impl InternStrsExt for [TokenTree] {
fn intern_strs(&self) -> BTreeMap<&str, InternStr> { BTreeMap::new() }
}
}
pub use self::serialize::{InternStrsExt, InternStr};
}
pub use tokentree::*;
fn main() {
println!("{:?}", [TokenTree].intern_strs());
}
(playpen)
What happened here is that you stumbled upon following glitches:
https://github.com/rust-lang/rust/issues/18241
https://github.com/rust-lang/rust/issues/16264
You can't export your traits from a private module. That's why you need to change mod serialize into pub mod serialize. For example this playpen example demonstrates that exporting struct Export works, but un-commenting the println! will make it stop compiling, because we used a trait.
Tip: One thing that helps me with the visibility rules is to generate doc files and see which doc files are visible.