Serializing sub properties on a struct doesn't seem to work - rust

I'm trying to serialize the following Result object, however I'm getting an error because while it workings for some of the properties, it doesn't seem to work on path, even though all of the elements involved have implementations provided by Serde.
#[macro_use]
extern crate serde;
extern crate rocket;
use rocket_contrib::json::Json;
use std::rc::Rc;
#[derive(Serialize)]
struct Result {
success: bool,
path: Vec<Rc<GraphNode>>,
visited_count: u32,
}
struct GraphNode {
value: u32,
parent: Option<Rc<GraphNode>>,
}
fn main(){}
fn index() -> Json<Result> {
Json(Result {
success: true,
path: vec![],
visited_count: 1,
})
}
Playground, although I can't get it to pull in the Rocket crate, it must not be one of the 100 most popular.
error[E0277]: the trait bound `std::rc::Rc<GraphNode>: serde::Serialize` is not satisfied
--> src/main.rs:11:5
|
11 | path: Vec<Rc<GraphNode>>,
| ^^^^ the trait `serde::Serialize` is not implemented for `std::rc::Rc<GraphNode>`
|
= note: required because of the requirements on the impl of `serde::Serialize` for `std::vec::Vec<std::rc::Rc<GraphNode>>`
= note: required by `serde::ser::SerializeStruct::serialize_field`
From my understanding, #[derive(Serialize)] should automatically create a serialize method which serde can then use. However I would expect it to work for the properties too. Do I need to create structs for all the types and then derive Serialize for all of those structs?
Do I need to do something to enable it?
The following crates are in use:
rocket = "*"
serde = { version = "1.0", features = ["derive"] }
rocket_contrib = "*"

the trait bound `std::rc::Rc<GraphNode>: serde::Serialize` is not satisfied
This means that Rc does not implement Serialize. See How do I serialize or deserialize an Arc<T> in Serde?. TL;DR:
serde = { version = "1.0", features = ["derive", "rc"] }
Once adding that, the error message changes to:
error[E0277]: the trait bound `GraphNode: serde::Serialize` is not satisfied
--> src/main.rs:11:5
|
11 | path: Vec<Rc<GraphNode>>,
| ^^^^ the trait `serde::Serialize` is not implemented for `GraphNode`
|
= note: required because of the requirements on the impl of `serde::Serialize` for `std::rc::Rc<GraphNode>`
= note: required because of the requirements on the impl of `serde::Serialize` for `std::vec::Vec<std::rc::Rc<GraphNode>>`
= note: required by `serde::ser::SerializeStruct::serialize_field`
That's because every type that needs to be serialized must implement Serialize:
#[derive(Serialize)]
struct GraphNode {

Related

Error on Post Method query_builder::QueryFragment / query_builder::QueryFragment

I am relatively new to rust and have really enjoyed playing around with it. However I am stuck on an error for my CRUD application using Diesel and Rocket. I have a main.rs, model.rs and schema.rs.
I get an error with my POST method that uses the User struct i created.
I am using a postgres DB i have running in the background on docker, Diesel and rocket for routing.
My models.rs
use super::schema::users;
use diesel::{prelude::*, table, Queryable, Insertable, RunQueryDsl};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Queryable, Debug, Insertable)]
#[table_name= "users"]
pub struct User {
pub id: i32,
pub first_name: String,
pub last_name: String,
pub user_name: String,
pub email_address: String,
}
My main.rs (included everything for detail but really question is about the Post method - create_user
#[macro_use] extern crate rocket;
mod models;
mod schema;
use rocket_sync_db_pools::{database};
use models::{User};
use rocket::{serde::json::Json};
use diesel::{RunQueryDsl};
use schema::users;
#[database("my_db")]
pub struct Db(rocket_sync_db_pools::diesel::PgConnection);
#[get("/")]
fn index() -> &'static str {
"Hello World"
}
#[get("/<id>")]
fn get_user(id: i32) -> Json<User> {
Json(User {
id: id,
first_name: "A Fist Name".to_string(),
last_name: "A Last Name".to_string(),
user_name: "A User Name".to_string(),
email_address: "AnEmail#email.com".to_string(),
})
}
#[post("/", data = "<user>")]
async fn create_user(connection: Db, user: Json<User>) -> Json<User> {
connection.run(move |c| {
diesel::insert_into(users::table)
.values(&user.into_inner())
.get_result(c)
})
.await
.map(Json)
.expect("There was an error saving the user")
}
#[launch]
fn rocket() -> _ {
let rocket = rocket::build();
rocket
.attach(Db::fairing())
.mount("/", routes![index])
.mount("/users", routes![get_user, create_user])
}
Dependencies from Cargo.toml
[dependencies]
diesel = "2.0.2"
diesel_cli = { version = "1.4.1", default-features = false, features = ["postgres"] }
rocket = { version = "0.5.0-rc.2", features = ["json"] }
rocket_sync_db_pools = { version = "0.1.0-rc.2", features = ["diesel_postgres_pool"] }
serde = "1.0.140"
The error message
--> src/main.rs:66:6
|
66 | .get_result(c)
| ^^^^^^^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`with_auth_rust_rocket_diesel_binary`)
= note: required because of the requirements on the impl of `diesel::query_builder::QueryFragment<_>` for `DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, &i32>>>`
= note: 123 redundant requirements hidden
= note: required because of the requirements on the impl of `diesel::query_builder::QueryFragment<_>` for `DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, &i32>>>`
= note: required because of the requirements on the impl of `diesel::insertable::InsertValues<table, _>` for `DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, &i32>>>`
= note: 3 redundant requirements hidden
= note: required because of the requirements on the impl of `diesel::query_builder::QueryFragment<_>` for `diesel::query_builder::InsertStatement<table, diesel::query_builder::insert_statement::ValuesClause<(DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, &i32>>>, DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::first_name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>, DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::last_name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>, DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::user_name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>, DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::email_address, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>), table>, diesel::query_builder::insert_statement::private::Insert, diesel::query_builder::returning_clause::ReturningClause<(columns::id, columns::first_name, columns::last_name, columns::user_name, columns::email_address)>>`
= note: required because of the requirements on the impl of `diesel::query_dsl::LoadQuery<'_, _, _>` for `diesel::query_builder::InsertStatement<table, diesel::query_builder::insert_statement::ValuesClause<(DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, &i32>>>, DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::first_name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>, DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::last_name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>, DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::user_name, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>, DefaultableColumnInsertValue<diesel::insertable::ColumnInsertValue<columns::email_address, diesel::expression::bound::Bound<diesel::sql_types::Text, &std::string::String>>>), table>>`
note: required by a bound in `diesel::RunQueryDsl::get_result`
--> /Users/me/.cargo/registry/src/github.com-1ecc6299db9ec823/diesel-2.0.2/src/query_dsl/mod.rs:1679:15
|
1679 | Self: LoadQuery<'query, Conn, U>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `diesel::RunQueryDsl::get_result`
I have reviewed both Diesel, Rocket and Rust documentation and worked worked through other examples for what I can find online however still do not quite get what i am doing incorrectly. Thanks in advance for any help.
I tried to create a post method that uses Diesel to take a Json version of my User object and insert it into my database.
This is a mismatch between the diesel version used by your project (2.0.2) and the diesel version provided by rocket_sync_db_pools (1.4.8). This means the c in connection.run(move |c| { is just a completely different type than expected by get_result, even if the types share the same name.

How to implement Default but only for tests?

I want to provide default values for structs to be used only within tests (and not accidentally in production). I thought that I could make the defaults opt-in by defining my own trait TestDefault and implement Default for any type that implements it. Then, one could access all the features of the standard Default trait using something like this
use TestDefault; // TestStruct (defined in my crate) implements TestDefault, thus also Default
let test_struct = TestStruct::default();
To clarify, I want to implement a foreign trait on local type, which should be allowed, but with an artificial layer of indirection to make it opt-in.
I've tried
pub trait TestDefault {
fn test_default() -> Self;
}
impl Default for TestDefault {
fn default() -> Self {
Self::test_default()
}
}
where the compiler complains that error[E0782]: trait objects must include the 'dyn' keyword, inserting it instead causes it to fail because error[E0038]: the trait 'TestDefault' cannot be made into an object.
Then I tried
impl<T> Default for T
where
T: TestDefault,
{
fn default() -> T {
T::test_default()
}
}
and got
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
--> src/lib.rs:158:14
|
158 | impl<T> Default for T
| ^ type parameter `T` must be used as the type parameter for some local type
|
= note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
= note: only traits defined in the current crate can be implemented for a type parameter
which probably hints at the actual error, but I don't entirely understand it. Is there any way to do this? Or get opt-in default some other way?
You can use the #[cfg(test)] annotation to only enable the Default implementation when testing:
struct MyStruct {
data: u32,
}
#[cfg(test)]
impl Default for MyStruct {
fn default() -> Self {
Self { data: 42 }
}
}
fn main() {
let s = MyStruct::default(); // FAILS
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let s = MyStruct::default(); // WORKS
assert_eq!(s.data, 42);
}
}
> cargo test
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
> cargo run
error[E0599]: no function or associated item named `default` found for struct `MyStruct` in the current scope
--> src/main.rs:13:23
|
1 | struct MyStruct {
| --------------- function or associated item `default` not found for this
...
13 | let s = MyStruct::default(); // FAILS
| ^^^^^^^ function or associated item not found in `MyStruct`
|
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `default`, perhaps you need to implement it:
candidate #1: `Default`

how to using rust diesel to do the group by query

I am using rust diesel diesel = { version = "1.4.8", features = ["postgres","64-column-tables","chrono","serde_json"] } to do the group by query follow the docs like this:
fpub fn get_bill_book_account_sum(){
use crate::diesel::GroupByDsl;
use diesel::dsl::max;
use crate::model::diesel::dict::dict_schema::test as bill_record_table;
let source_query = bill_record_table::table
.group_by(bill_record_table::id)
.select((max(bill_record_table::tags),bill_record_table::id))
.filter(bill_record_table::dsl::tags.eq(9));
}
then compile this code, shows error like this:
error[E0277]: the trait bound `aggregate_ordering::max::max<BigInt, columns::tags>: NonAggregate` is not satisfied
--> src/main.rs:19:17
|
19 | .select((max(bill_record_table::tags),bill_record_table::id))
| ------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonAggregate` is not implemented for `aggregate_ordering::max::max<BigInt, columns::tags>`
| |
| required by a bound introduced by this call
|
= note: required because of the requirements on the impl of `diesel::Expression` for `(aggregate_ordering::max::max<BigInt, columns::tags>, columns::id)`
note: required by a bound in `diesel::QueryDsl::select`
--> /Users/xiaoqiangjiang/.cargo/registry/src/mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd/diesel-1.4.8/src/query_dsl/mod.rs:291:20
|
291 | Selection: Expression,
| ^^^^^^^^^^ required by this bound in `diesel::QueryDsl::select`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `rust-learn` due to previous error
where am I doing wrong? what should I do to fixed this problem? this is the schema define(I have removed all the columns just using 2 columns to make a minimal reproduce example):
table! {
test (id) {
id -> Int8,
tags -> Int8,
}
}
and this is the model define:
// Generated by diesel_ext
#![allow(unused)]
#![allow(clippy::all)]
use std::io::Write;
use diesel::deserialize::FromSql;
use diesel::pg::Pg;
use diesel::serialize::{Output, ToSql};
use diesel::sql_types::Jsonb;
use rocket::serde::Serialize;
use serde::Deserialize;
use crate::model::diesel::dict::dict_schema::*;
#[derive(Queryable,Debug,Serialize,Deserialize,Default)]
pub struct Test {
pub id: i64,
pub tags: i64,
}
this is the minimal main.rs entrypoint:
#[macro_use]
extern crate diesel;
mod model;
use diesel::{ ExpressionMethods, QueryDsl};
fn main() {
get_bill_book_account_sum();
}
pub fn get_bill_book_account_sum(){
use crate::diesel::GroupByDsl;
use diesel::dsl::max;
use crate::model::diesel::dict::dict_schema::test as bill_record_table;
let source_query = bill_record_table::table
.group_by(bill_record_table::id)
.select((max(bill_record_table::tags),bill_record_table::id))
.filter(bill_record_table::dsl::tags.eq(9));
}
change the aggregate query like this fixed this problem:
pub fn get_bill_book_account_sum(request: &BillAccountRequest) -> Result<Vec<(i64, i32)>, diesel::result::Error>{
use crate::diesel::GroupByDsl;
use crate::model::diesel::fortune::fortune_schema::bill_record as bill_record_table;
let source_query = bill_record_table::table
.group_by(bill_record_table::account_id)
.select((diesel::dsl::sql::<diesel::sql_types::BigInt>("SUM(CAST(amount AS Integer))"),bill_record_table::account_id))
.filter(bill_record_table::dsl::bill_book_id.eq(request.bill_book_id));
let result = source_query.load::<(i64,i32)>(&get_connection());
return result;
}
the solution come from this issue. This is the answer come from the maintainer that shows diesel 1.x did not support group by official.

resolving cyclic dependency between traits that need references to each other in rust

I have two structs that need references to each other. Due to other reasons these structs need to bypass borrow checker at the same time. So I have a wrapper around *mut T to bypass the checker. Now I am trying to have each struct have a generic type of the second struct.
This is a toy example:
use d2simrs::util::internalref::InternalRef;
pub trait Layer3Trait {
fn foo() {
println!("TraitA::foo()");
}
}
pub trait Layer2Trait {
fn bar() {
println!("TraitB::foo()");
}
}
pub struct SimpleLayer2<Layer3T>
where Layer3T: Layer3Trait
{
pub layer3: InternalRef<Layer3T>,
}
pub struct SimpleLayer3<Layer2T>
where Layer2T: Layer2Trait
{
pub layer2: InternalRef<Layer2T>,
}
pub type Layer2 = SimpleLayer2<Layer3>;
pub type Layer2Ref = InternalRef<Layer2>;
pub type Layer3 = SimpleLayer3<SimpleLayer2<Layer3>>;
pub type Layer3Ref = InternalRef<Layer3>;
Code for InternalRef is here
For which I get
|
30 | pub type Layer3 = SimpleLayer3<SimpleLayer2<Layer3>>;
| ^^^^^^
|
= note: ...which again requires computing type of `example2::Layer3`, completing the cycle
note: cycle used when computing type of `example2::Layer2`
--> examples/network/bypass_borrow/example2.rs:27:32
|
27 | pub type Layer2 = SimpleLayer2<Layer3>;
| ^^^^^^
Can I somehow re-define something, so that SimpleLayer2 and SimpleLayer3 can have references to one another.
Rust does not support cyclic generic types. If you have:
pub type Layer2 = SimpleLayer2<Layer3>;
pub type Layer3 = SimpleLayer3<Layer2>;
Then the concrete type of Layer3 would be:
SimpleLayer3<SimpleLayer2<SimpleLayer3<SimpleLayer2<SimpleLayer3<SimpleLayer2<SimpleLayer3<SimpleLayer2<SimpleLayer3<SimpleLayer2<SimpleLayer3<...>>>>>>>
Which is not allowed.
As nudged at in the comments, it would ideal if your design were heirachial with no cyclic dependencies since it would obviously avoid such problems. But if that is not appropriate, the standard way to solve this would be with Rc/Arcs and trait objects, which would also avoid your internal *mut T wrapper (with RefCell/RwLock if you need mutability):
use std::rc::{Rc, Weak};
pub struct SimpleLayer2 {
pub layer3: Weak<RefCell<dyn Layer3>>,
}
pub struct SimpleLayer3 {
pub layer2: Rc<RefCell<dyn Layer2>>,
}
See these other questions for other potential ideas:
Is there a way to build a structure with cyclic links without runtime overhead?
How do I express mutually recursive data structures in safe Rust?
Implement graph-like data structure in Rust

Why does a lazy-static value claim to not implement a trait that it clearly implements?

With the following code (an attempt to make an HTTP request using the reqwest crate), the compiler says that my value SID_URI does not implement the trait PolyfillTryInto. What's going on here? reqwest::Url clearly implements the private trait reqwest::into_url::PolyfillTryInto.
#[macro_use]
extern crate lazy_static;
extern crate reqwest;
static R_EMAIL: &str = "example#example.com";
static R_PASS: &str = "password";
static API_PUBKEY: &str = "99754106633f94d350db34d548d6091a";
static API_URI: &str = "https://example.com";
static AUTH_PATH: &str = "/api/v1";
lazy_static! {
static ref SID_URI: reqwest::Url = reqwest::Url::parse(&(API_URI.to_owned() + AUTH_PATH)).unwrap();
}
fn get_sid() -> Result<reqwest::Response, reqwest::Error> {
let client = reqwest::Client::new();
let params = [("ID", R_EMAIL), ("PW", R_PASS), ("KY", API_PUBKEY)];
let q = client.post(SID_URI).form(&params).send()?;
Ok(q)
}
fn main() {
assert!(get_sid().is_ok());
}
error[E0277]: the trait bound `SID_URI: reqwest::into_url::PolyfillTryInto` is not satisfied
--> src/main.rs:19:20
|
19 | let q = client.post(SID_URI).form(&params).send()?;
| ^^^^ the trait `reqwest::into_url::PolyfillTryInto` is not implemented for `SID_URI`
|
= note: required because of the requirements on the impl of `reqwest::IntoUrl` for `SID_URI`
The compiler isn't lying to you, you are just skipping over a relevant detail of the error message. Here's a self-contained example:
#[macro_use]
extern crate lazy_static;
struct Example;
trait ExampleTrait {}
impl ExampleTrait for Example {}
lazy_static! {
static ref EXAMPLE: Example = Example;
}
fn must_have_trait<T>(_: T)
where
T: ExampleTrait,
{
}
fn main() {
must_have_trait(EXAMPLE);
must_have_trait(42i32);
}
error[E0277]: the trait bound `EXAMPLE: ExampleTrait` is not satisfied
--> src/main.rs:19:5
|
19 | must_have_trait(EXAMPLE);
| ^^^^^^^^^^^^^^^ the trait `ExampleTrait` is not implemented for `EXAMPLE`
|
= note: required by `must_have_trait`
error[E0277]: the trait bound `i32: ExampleTrait` is not satisfied
--> src/main.rs:20:9
|
20 | must_have_trait(42i32);
| ^^^^^^^^^^^^^^^ the trait `ExampleTrait` is not implemented for `i32`
|
= note: required by `must_have_trait`
Compare the two error messages:
the trait bound `EXAMPLE: ExampleTrait` is not satisfied
the trait bound `i32: ExampleTrait` is not satisfied
The second error message doesn't say that 42 does not implement ExampleTrait, it says that i32 lacks the implementation. This error message shows the type that fails, not the name of the value! That means that EXAMPLE in the same context is referring to a type.
Lazy-static works by creating one-off types that wrap your value and provide thread-safe single initialization guarantees:
For a given static ref NAME: TYPE = EXPR;, the macro generates a unique type that implements Deref<TYPE> and stores it in a static with name NAME.
This wrapper type does not implement your trait, only the wrapped type does. You will need to invoke Deref and then probably re-reference it to get to a &Url, assuming that a reference to a Url implements your trait:
must_have_trait(&*EXAMPLE);
Additionally, using the bare static variable would attempt to move it out of the static location (which would be a Very Bad Thing), so you always need to use it by reference.

Resources