I am using newtypes like struct GuildId(i64); for the columns in my diesel model structs. Currently I am implementing these traits:
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize)]
pub struct $name(pub i64);
impl AsExpression<BigInt> for $name { /* delegate to <i64 as AsExpression<BigInt> */ */ }
impl<ST, DB: Backend> Queryable<ST, DB> for $name
where i64: FromSql<ST, DB> { /* also delegate to i64 */
However, when I try to use this type in the following model structs:
#[derive(Associations, Identifiable, Queryable)]
#[belongs_to(Guild)]
struct Channel {
guild_id: GuildId,
// other fields
}
#[derive(Identifiable, Queryable)]
struct Guild {
id: GuildId,
// other fields
}
Channel still does not implement BelongingToDsl. When I try to cast it to the trait, it fails to compile with the following message:
error[E0277]: the trait bound `diesel::query_builder::select_statement::SelectStatement<webcord_schema::schema::channels::table>: diesel::query_dsl::filter_dsl::FilterDsl<diesel::expression::operators::Eq<webcord_schema::schema::channels::columns::guild_id, &webcord_schema::models::GuildId>>` is not satisfied
--> src/index/guild.rs:23:32
|
23 | let channels = <models::Channel as BelongingToDsl<&models::Guild>>::belonging_to(&guild)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `diesel::query_dsl::filter_dsl::FilterDsl<diesel::expression::operators::Eq<webcord_schema::schema::channels::columns::guild_id, &webcord_schema::models::GuildId>>` is not implemented for `diesel::query_builder::select_statement::SelectStatement<webcord_schema::schema::channels::table>`
|
= help: the following implementations were found:
<diesel::query_builder::select_statement::SelectStatement<F, S, D, W, O, L, Of, G, LC> as diesel::query_dsl::filter_dsl::FilterDsl<Predicate>>
= note: required because of the requirements on the impl of `diesel::query_dsl::filter_dsl::FilterDsl<diesel::expression::operators::Eq<webcord_schema::schema::channels::columns::guild_id, &webcord_schema::models::GuildId>>` for `webcord_schema::schema::channels::table`
error[E0277]: the trait bound `webcord_schema::models::GuildId: diesel::expression::Expression` is not satisfied
--> src/index/guild.rs:23:32
|
23 | let channels = <models::Channel as BelongingToDsl<&models::Guild>>::belonging_to(&guild)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `diesel::expression::Expression` is not implemented for `webcord_schema::models::GuildId`
|
= note: required because of the requirements on the impl of `diesel::expression::Expression` for `&webcord_schema::models::GuildId`
= note: required because of the requirements on the impl of `diesel::expression::AsExpression<diesel::sql_types::BigInt>` for `&webcord_schema::models::GuildId`
= note: required because of the requirements on the impl of `diesel::query_dsl::belonging_to_dsl::BelongingToDsl<&webcord_schema::models::Guild>` for `webcord_schema::models::Channel`
What traits am I missing?
That error is not related to BelongingToDsl, but to the incomplete implementation of the custom new type wrapper.
As the error message indicates you are missing a trait impl for your new type wrapper:
error[E0277]: the trait bound `webcord_schema::models::GuildId: diesel::expression::Expression` is not satisfied
--> src/index/guild.rs:23:32
|
23 | let channels = <models::Channel as BelongingToDsl<&models::Guild>>::belonging_to(&guild)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `diesel::expression::Expression` is not implemented for `webcord_schema::models::GuildId`
|
= note: required because of the requirements on the impl of `diesel::expression::Expression` for `&webcord_schema::models::GuildId`
= note: required because of the requirements on the impl of `diesel::expression::AsExpression<diesel::sql_types::BigInt>` for `&webcord_schema::models::GuildId`
= note: required because of the requirements on the impl of `diesel::query_dsl::belonging_to_dsl::BelongingToDsl<&webcord_schema::models::Guild>` for `webcord_schema::models::Channel`
The interesting line is the second line in = note: required because of the requirements on the impl of diesel::expression::AsExpression<diesel::sql_types::BigInt> for '&webcord_schema::models::GuildId. This means you need to add at least an AsExpression<_> impl for a reference to your new type wrapper.
So now general speaking: There is this test case showing how to implement custom types in general. You will see that the custom type on rust side uses two custom derives (AsExpression and FromSqlRow) that are basically implementing the traits you've already implemented manually and additionally the missing ones. Additionally a ToSql/FromSql impl is required to describe how the type should be translated into/from a sql type.
Summing that up your type definition should probably look like:
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, AsExpression, FromSqlRow)]
#[sql_type = "diesel::sql_types::BigInt")]
pub struct $name(pub i64);
impl<DB> ToSql<diesel::sql_types::BigInt, DB> for $name
where DB: Backend,
i64: ToSql<diesel::sql_types::BigInt, DB>,
{
fn to_sql<W: Write>(&self, out: &mut Output<W, DB>) -> serialize::Result {
<i64 as ToSql<diesel::sql_types::BigInt, DB>>::to_sql(&self.0, out)
}
}
impl<DB> FromSql<diesel::sql_types::BigInt, DB> for $name
where DB: Backend,
i64: FromSql<diesel::sql_types::BigInt, DB>
{
fn from_sql(bytes: Option<&DB::RawValue>) -> deserialize::Result<Self> {
<i64 as FromSql<diesel::sql_types::BigInt, DB>>::from_sql(bytes).map($name)
}
}
Related
Here's a minimal example representing the type of problem I'm running into.
use core::fmt::Debug;
pub trait Config {
type A: Debug;
}
#[derive(Debug)]
pub struct Info<T: Config> {
pub field: T::A,
}
pub struct Conf;
impl Config for Conf {
type A = i128;
}
fn main() {
let s = Info::<Conf> {
field: 123
};
dbg!(s);
}
The framework that I'm using (Substrate) uses this concept of a Config trait that aggregates all generic types for a module (pallet).
The problem is that trying to #[derive(Debug)] for a struct that only uses the associated types of the object T implementing Config still requires that T implements Debug itself.
error[E0277]: `Conf` doesn't implement `Debug`
--> src/main.rs:22:5
|
22 | dbg!(s);
| ^^^^^^^ `Conf` cannot be formatted using `{:?}`
|
= help: the trait `Debug` is not implemented for `Conf`
= note: add `#[derive(Debug)]` to `Conf` or manually `impl Debug for Conf`
Moreover, I don't have control of the implementation of the Conf object. Regardless, I'm not trying to print anything about the Conf object itself.
Is there a way to make #[derive(Debug)] for Info ignore T?
Unfortunately, not as of today. You have to impl Debug manually:
impl<T: Config> fmt::Debug for Info<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Info").field("field", &self.field).finish()
}
}
There is an intent to make it possible to create what is called "perfect derive": derive bounds based on what needed and not the generic parameters. See for example this lang team design meeting proposal. But for now there is nothing.
I'm using SQLx to define a trait that is to be implemented on PgPool, MySqlPool, etc. and looks something like this:
#[async_trait]
trait MyTrait {
const QUERY: &'static str;
fn fetch(&self) -> Option<Self> {
sqlx::query(Self::QUERY)
.fetch_one(self)
.await
.map(|row| row.get(0))
.ok()
}
}
#[async_trait]
impl MyTrait for sqlx::PgPool {
const QUERY: &'static str = "SELECT value FROM table WHERE id = 10";
}
This does not compile with:
error[E0277]: the trait bound `&Self: sqlx::Executor<'_>` is not satisfied
--> service/src/lib.rs:265:24
|
265 | .fetch_one(self)
| --------- ^^^^ the trait `sqlx::Executor<'_>` is not implemented for `&Self`
| |
| required by a bound introduced by this call
|
note: required by a bound in `sqlx::query::Query::<'q, DB, A>::fetch_one`
I've tried adding where Self: sqlx::Executor<'..., Datbase = DB> and numerous variations of it but to no avail unfortunately.
I'm currently trying something like MyTrait<'p, DB: sqlx::Database> where &'p Self: sqlx::Executor<'p, Database = DB>, Self: 'p with implementation impl MyTrait<'_, sqlx::Postgres> for PgPool but this gives the error type mismatch resolving `<&Self as sqlx::Executor<'_>>::Database == Postgres`
If anybody could tell me how I need to modify my code in order for it to compile I would really appreciate it, thank you.
I'm trying to export the following struct:
#[wasm_bindgen]
#[derive(Eq, PartialEq, Debug, Clone)]
pub enum TokenType {
KeywordLiteral,
NumberLiteral,
Operator,
Separator,
StringLiteral,
}
#[wasm_bindgen]
#[derive(Eq, PartialEq, Debug, Clone)]
pub struct Token {
pub typ: TokenType,
pub val: String,
}
but I'm getting:
error[E0277]: the trait bound `token::TokenType: std::marker::Copy` is not satisfied
--> src\tokenizer\token.rs:17:14
|
14 | #[wasm_bindgen]
| --------------- required by this bound in `__wbg_get_token_typ::assert_copy`
...
17 | pub typ: TokenType,
| ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `token::TokenType`
as well as:
error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied
--> src\tokenizer\token.rs:18:14
|
14 | #[wasm_bindgen]
| --------------- required by this bound in `__wbg_get_token_val::assert_copy`
...
18 | pub val: String,
I can add #[derive(Copy)] to TokenType but not to String.
I'm new to rust so help is really appreciated.
According to wasm-bindgen#1985, public fields of structs are required to be Copy in order for the automatically generated accessors to function.
You can either make the fields private, or annotate them with #[wasm_bindgen(skip)], and then implement a getter and setter directly.
There is an example provided in wasm-bindgen's docs describing how to write these:
#[wasm_bindgen]
pub struct Baz {
field: i32,
}
#[wasm_bindgen]
impl Baz {
#[wasm_bindgen(constructor)]
pub fn new(field: i32) -> Baz {
Baz { field }
}
#[wasm_bindgen(getter)]
pub fn field(&self) -> i32 {
self.field
}
#[wasm_bindgen(setter)]
pub fn set_field(&mut self, field: i32) {
self.field = field;
}
}
When objects are shared between wasm and js, the js object only contains the pointer to the struct inside the wasm runtime's memory. When you access fields from JS, it goes through a defined property which makes a function call to the wasm code asking it for the property value (you can think of the wasm memory as a bit UInt8Array).
Requiring the objects to be Copy is probably done to avoid surprises when auto-generating these getters and setters. If you implement them manually, you can have the same behaviour in JS and be able to control what's being set on the rust side.
My type A, which can contain anything that implements trait Trait, is serialisable, although the type implementing the trait Trait might not be. In my case, it cannot be - it's a private asymmetric key:
extern crate serde;
#[macro_use]
extern crate serde_derive;
use serde::de::DeserializeOwned;
use serde::Serialize;
trait Trait {
type SerialisableType: Clone + Serialize + DeserializeOwned;
fn inner(&self) -> &Self::SerialisableType;
}
#[derive(Serialize, Deserialize)]
enum A<T: Trait> {
Variant0(B<T>), // *** NOTE: Compiles if this is commented ***
Variant1(T::SerialisableType),
}
#[derive(Serialize, Deserialize)]
struct B<T: Trait> {
inner: T::SerialisableType,
}
// ==============================================
struct NonSerialisable {
serialisable: Serialisable,
}
impl Trait for NonSerialisable {
type SerialisableType = Serialisable;
fn inner(&self) -> &Self::SerialisableType {
&self.serialisable
}
}
#[derive(Clone, Serialize, Deserialize)]
struct Serialisable(Vec<u8>);
#[derive(Serialize, Deserialize)]
enum E {
Variant0(A<NonSerialisable>),
Variant1(B<NonSerialisable>),
}
fn main() {}
playground
This errors out with:
error[E0277]: the trait bound `NonSerialisable: serde::Serialize` is not satisfied
--> src/main.rs:43:10
|
43 | #[derive(Serialize, Deserialize)]
| ^^^^^^^^^ the trait `serde::Serialize` is not implemented for `NonSerialisable`
|
= note: required because of the requirements on the impl of `serde::Serialize` for `A<NonSerialisable>`
= note: required by `serde::Serializer::serialize_newtype_variant`
error[E0277]: the trait bound `NonSerialisable: serde::Deserialize<'_>` is not satisfied
--> src/main.rs:43:21
|
43 | #[derive(Serialize, Deserialize)]
| ^^^^^^^^^^^ the trait `serde::Deserialize<'_>` is not implemented for `NonSerialisable`
|
= note: required because of the requirements on the impl of `serde::Deserialize<'_>` for `A<NonSerialisable>`
= note: required by `serde::de::VariantAccess::newtype_variant`
If I comment out A::Variant0, as mentioned in the inline comment in the code, then it compiles fine. This makes me think that the compiler is unable to deduce that B<T> is serialisable, but then it actually is able to deduce that because it can figure out E is serialisable which would require B to be serialisable as well.
Where is the problem?
During macro expansion the compiler has not yet determined which B is being referred to inside Variant0 or how that B may use its type parameters. As such, macro expansion infers trait bounds that would work for the most common cases of what B might be, like if B were Box or Vec. In those cases serializing B<T> would require T: Serialize and deserializing B<T> would require T: Deserialize<'de>.
You can provide handwritten generic type bounds to replace the inferred bounds.
#[derive(Serialize, Deserialize)]
#[serde(bound = "")]
enum A<T: Trait> {
Variant0(B<T>),
Variant1(T::SerialisableType),
}
I have two structs, A and B, and I want to use a HashMap<A, B>. I have a piece of code like this:
use std::collections::HashMap;
pub struct A {
x: i32,
y: i32,
title: String,
}
pub struct B {
a: u32,
b: u32,
}
fn main() {
let map = HashMap::new();
map.insert(
A {
x: 10,
y: 20,
title: "test".to_string(),
},
B { a: 1, b: 2 },
);
}
But the compiler gives me these errors:
error[E0277]: the trait bound `A: std::cmp::Eq` is not satisfied
--> src/main.rs:16:9
|
16 | map.insert(
| ^^^^^^ the trait `std::cmp::Eq` is not implemented for `A`
error[E0277]: the trait bound `A: std::hash::Hash` is not satisfied
--> src/main.rs:16:9
|
16 | map.insert(
| ^^^^^^ the trait `std::hash::Hash` is not implemented for `A`
I know that I must implement these traits, but after hours of searching the web, I have found nothing about implementing them.
My actual code is more complicated, and my structs contain other structs (I've edited the code).
I've implemented the Hash trait:
impl std::hash::Hash for A {
fn hash<H>(&self, state: &mut H)
where
H: std::hash::Hasher,
{
state.write_i32(self.x);
state.finish();
}
}
I made an implementation for PartialEq also:
impl PartialEq for A {
fn eq(&self, other: &A) -> bool {
self.x == other.x
}
}
But the compiler continues to complain, this time about Eq:
error[E0277]: the trait bound `A: std::cmp::Eq` is not satisfied
--> src/main.rs:16:9
|
16 | map.insert(
| ^^^^^^ the trait `std::cmp::Eq` is not implemented for `A`
How can I implement Eq? Why is there no implementation in the docs?
Eq is what we call a marker trait: it has no method on its own, it is just a way for the programmer to express that the struct verifies a certain property. You can implement it like this:
impl Eq for Application {}
Or alternatively, use #[derive(Eq)] on top of the Application declaration
Eq is a trait bound by PartialEq. This means that you can implement it only on structs that also implement PartialEq (which is the case here). By implementing Eq, you make the promise that your implementation of PartialEq is reflexive (see the docs for what it means).
You can have the compiler derive these instances for you by inserting the following before your struct declaration:
#[derive(PartialEq, Eq, Hash)]
pub struct A {
// ...
}
You could also implement them manually instead. If you want to do that, you should read the documentation on traits, Eq and Hash.
This is how the Rust documentation says you write your own implementation of Hash:
use std::hash::{Hash, Hasher};
struct Person {
id: u32,
name: String,
phone: u64,
}
impl Hash for Person {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
self.phone.hash(state);
}
}
Source: https://doc.rust-lang.org/std/hash/trait.Hash.html