Import a library struct in tests suite - rust

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;

Related

Serialize a remote struct with private String

I need to serialize a struct from a remote crate and all of the fields in the struct are private. There are getter's implemented in the remote struct to get those values. I am following this guidance and got it to work just fine for primitive types. However, I'm struggling with how to implement this for non-primitive types (ie: String) that the remote struct contains.
Below is a small piece of what I've implemented to frame the issue. The DataWrapper struct simply wraps Data, where Data is the remote struct.
#[derive(Serialize)]
pub struct DataWrapper {
#[serde(with = "DataDef")]
pub data: Data,
}
#[derive(Serialize)]
#[serde(remote = "remote_crate::data::Data")]
pub struct DataDef {
#[serde(getter = "Data::image_id")] // This works
image_id: u16,
#[serde(getter = "Data::description")] // This does not work
description: String,
}
The error I get when compiling this is
#[derive(Serialize)]
^^^^^^^^^ expected struct `std::string::String`, found `&str`
This makes sense, since the getter Data::description returns &str rather than a String. But, I'm not seeing a way in my code to coerce this so the compiler is happy.
If I change DataDef::description to be &str instead of String, then I have to implement lifetimes. But, when I do that, the compiler then says the remote "struct takes 0 lifetime arguments".
Appreciate any tips on how I can serialize this and other non-primitive types.
One approach you could do, so that you have full control of the serialization. Is to have the data wrapper be a copy of the struct fields you need, instead of the entire remote struct. Then you can implement From<remote_crate::data::Data> for DataWrapper and use serde without trying to coerce types.
#[derive(Serialize)]
pub struct Data {
image_id: u16,
description: String,
}
impl From<remote_crate::data::Data> for Data {
fn from(val: remote_crate::data::Data) -> Self {
Self {
image_id: val.image_id,
description: val.description.to_string(),
}
}
}
// Then you could use it like this:
// let my_data: Data = data.into();
I couldn't get it to work with an &str, but if you're OK with an allocation, you can write a custom getter:
mod local {
use super::remote::RemoteData;
use serde::{Deserialize, Serialize};
fn get_owned_description(rd: &RemoteData) -> String {
rd.description().into()
}
#[derive(Serialize)]
#[serde(remote = "RemoteData")]
pub struct DataDef {
#[serde(getter = "get_owned_description")]
description: String,
}
}
mod remote {
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct RemoteData {
description: String,
}
impl RemoteData {
pub fn description(&self) -> &str {
&self.description
}
}
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e9c7c0b069d7e16b6faac2fa2b840c72

error: cannot find attribute `table_name` in this scope

I want to do a page query using rust diesel, I am using this code to do a unit test in rust:
#[cfg(test)]
mod test {
use std::env;
use diesel::{Connection, ExpressionMethods, PgConnection, QueryDsl, RunQueryDsl};
use rust_wheel::common::query::pagination::PaginateForQuerySource;
use crate::model::diesel::rhythm::rhythm_schema::favorites::dsl::favorites;
use crate::model::diesel::rhythm::rhythm_schema::favorites::like_status;
use crate::models::Favorites;
#[test]
fn page_test(){
use crate::model::diesel::rhythm::rhythm_schema::favorites::dsl::*;
use rust_wheel::common::query::pagination::{PaginateForQueryFragment, PaginateForQuerySource};
let conn = establish_music_connection();
let query = favorites
.filter(like_status.eq(1))
.paginate(1)
.per_page(10)
.load::<Favorites>(&conn)
.expect("query fav failed");
println!("{:?}", 1);
}
pub fn establish_music_connection() -> PgConnection {
let database_url = std::env::var("MUSIC_DATABASE_URL").expect("MUSIC_DATABASE_URL must be set");
PgConnection::establish(&database_url).expect(&format!("Error connecting to {}", database_url))
}
}
shows error like this:
error: cannot find attribute `table_name` in this scope
--> src/models.rs:15:3
|
15 | #[table_name = "favorites"]
| ^^^^^^^^^^
this is my models.rs define, this two models are store in different database:
use rocket::serde::Serialize;
use serde::Deserialize;
use crate::model::diesel::dolphin::dolphin_schema::dashboard;
use crate::model::diesel::rhythm::rhythm_schema::favorites;
#[derive(Insertable, Serialize, Queryable, Deserialize,Default)]
#[table_name = "dashboard"]
pub struct Dashboard {
pub id: i32,
pub app_count: i32,
pub user_count: i32
}
#[derive(Serialize, Queryable, Deserialize,Default)]
#[table_name = "favorites"]
pub struct Favorites {
pub id: i64,
pub song_id: String,
pub created_time: i64
}
why did this happen? what should I do to fix it?
Only the Insertable derive macro handles the #[table_name = ...] attribute. So it should not be included if you're not using it.

How can I only generate #[derive(Clone)] by bindgen?

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)]?

Share memory data by REST parameters in Rust

my "main" file
mod router;
mod student;
use std::sync::Arc;
use crate::router::init_router;
use crate::router::Memory;
use actix_web::{App, HttpServer};
#[actix_web::main]
async fn main() -> std::io::Result<()> {
dotenv::dotenv().ok();
let repo = Arc::new(Memory::repository());
let host = std::env::var("SERVER.HOST").unwrap_or("127.0.0.1".to_string());
let port = std::env::var("SERVER.PORT").unwrap_or("8080".to_string());
let url = format!("{}:{}", host, port);
println!("url: {}", &url);
HttpServer::new(move || {
App::new()
.data(repo.clone()) // shared
.configure(init_router)
})
.bind(&url)?
.run()
.await
}
my file: "router.rs"
use std::sync::Arc;
use crate::student::Student;
use actix_web::{get, web, HttpResponse, Responder};
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
pub struct Memory {
pub students: Vec<Student>,
}
impl Memory {
fn new() -> Self {
Memory {
students: Vec::new(),
}
}
pub fn repository() -> Self{
Self {
students: vec![
{Student::new("1".to_string(), "Daniel".to_string(), 19)},
{Student::new("2".to_string(), "Lucia".to_string(), 17)},
{Student::new("3".to_string(), "Juan".to_string(), 14)}
]
}
}
}
#[get("/studen/list/all")]
async fn list_all(repo: web::Data<Arc<Memory>>) -> impl Responder {
HttpResponse::Ok().json(repo)
}
pub fn init_router(config: &mut web::ServiceConfig) {
config.service(list_all);
}
and my file: "student.rs"
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
pub struct Student{
pub id: String,
pub nombre: String,
pub calificacion: u32,
}
impl Student{
pub fn new(id: String, nombre: String, calificacion: u32) -> Self{
Self{id, nombre, calificacion}
}
}
so I want to show all students in a json via the following path: 127.0.0.1:3000/student/list/all
but i have the following error
| HttpResponse::Ok().json(repo)
| ^^^^ the trait Serialize is not implemented for Data<Arc<Memory>>
I still can't pass this data by parameter of a GET method, I need a little help please to display it in json. It is necessary because later I will need this data by parameter to add or remove.
(Note that you typed #[get("/studen/list/all")] instead of #[get("/student/list/all")] in your original code.)
You don't want to serialize the Data<Arc<Memory>> to JSON, you only want to serialize the Memory. To do so, you can dereference the Data<Arc<Memory>> to get an Arc<Arc<Memory>>, then dereference the Arcs twice to get a Memory. Then, you add a reference as to not require cloning the resulting Memory. So, you replace
HttpResponse::Ok().json(repo)
with
HttpResponse::Ok().json(&***repo)
However, Data is already a wrapper around an Arc, so no Arc<Memory> in the is required. If you want to edit the Memory eventually, you'll have to add a Mutex inside. So, you'll have to obtain a lock on repo before serializing it.

How to access JS object properties in Wasm (Rust)?

I'm using wasm bindgen and I have following function :
#[wasm_bindgen]
pub fn obj(o: &JsValue){
console::log_1(o);
}
and in js I call this function obj({name: "john"});
and it works fine, but when i try to console::log_1(o.name);
it gives error unknown field pointing at name
JsValue does not have a field name. To get this field you have to declare the JS object.
Variant 1
Add serde to your dependencies:
serde = "^1.0.101"
serde_derive = "^1.0.101"
Rust code:
extern crate serde;
#[derive(Serialize, Deserialize)]
pub struct User {
pub name: String,
}
#[wasm_bindgen]
pub fn obj(o: &JsValue){
let user: User = o.into_serde().unwrap();
console::log_1(user.name);
}
Variant 2
Another way is to use wasm-bindgen directly but I never used it. It should work like this I think:
#[wasm_bindgen]
pub struct User {
pub name: String,
}
#[wasm_bindgen]
pub fn obj(o: User){
console::log_1(o.name);
}

Resources