I'm trying to create a custom struct using the UUID struct from Rocket as a field type. I want it to be serialized using Serde in order to convert it to JSON easily.
When trying to do this, I get an error:
error[E0277]: the trait bound `rocket_contrib::UUID:
model::event::_IMPL_DESERIALIZE_FOR_Event::_serde::Serialize` is not
satisfied
--> src/service/document.rs:4:10
|
4 | #[derive(Serialize, Deserialize)]
| ^^^^^^^^^ the trait
`model::event::_IMPL_DESERIALIZE_FOR_Event::_serde::Serialize` is not
implemented for `rocket_contrib::UUID`
|
= note: required by `model::event::_IMPL_DESERIALIZE_FOR_Event::_serde::ser::SerializeStruct::serialize_field`
error[E0277]: the trait bound `rocket_contrib::UUID:
model::event::_IMPL_DESERIALIZE_FOR_Event::_serde::Deserialize<'_>` is not satisfied
--> src/service/document.rs:4:21
|
4 | #[derive(Serialize, Deserialize)]
| ^^^^^^^^^^^ the trait
`model::event::_IMPL_DESERIALIZE_FOR_Event::_serde::Deserialize<'_>` is not implemented for `rocket_contrib::UUID`
|
= note: required by `model::event::_IMPL_DESERIALIZE_FOR_Event::_serde::de::SeqAccess::next_element`
error[E0277]: the trait bound `rocket_contrib::UUID: model::event::_IMPL_DESERIALIZE_FOR_Event::_serde::Deserialize<'_>` is not satisfied
--> src/service/document.rs:4:21
|
4 | #[derive(Serialize, Deserialize)]
| ^^^^^^^^^^^ the trait `model::event::_IMPL_DESERIALIZE_FOR_Event::_serde::Deserialize<'_>` is not implemented for `rocket_contrib::UUID`
|
= note: required by `model::event::_IMPL_DESERIALIZE_FOR_Event::_serde::de::MapAccess::next_value`
My struct:
#[derive(Serialize, Deserialize)]
pub struct Document {
id: UUID,
user_id: UUID,
created: i64,
updated: i64,
text: String
}
My imports:
[dependencies]
rocket = "0.3.17"
rocket_codegen = "0.3.17"
serde_derive = "1.0.80"
serde = "1.0.80"
chrono = "0.4"
[dependencies.rocket_contrib]
version = "0.3.17"
default-features = false
features = ["json", "uuid", "serde"]
Endpoint where I use the struct:
#[get("/document/<id>")]
pub fn get_document(id: UUID) -> status::Accepted<Json<Document>> {
status::Accepted(Some(Json(document::get_document(id))))
}
I've checked all dependencies, and I have the serde feature enabled in rocket_contrib. I've run out of ideas what to check next.
rocket_contrib::UUID does not implement Serialize:
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct UUID(uuid_ext::Uuid);
If the type doesn't implement Serialize, you can't make it.
As mcarton points out:
you still can implement Serialize for your type, you simply can't derive it and will have to implement it by hand.
That could look something like:
#[derive(Serialize, Deserialize)]
pub struct Document {
#[serde(with = "my_uuid")]
id: UUID,
#[serde(with = "my_uuid")]
user_id: UUID,
created: i64,
updated: i64,
text: String,
}
mod my_uuid {
use rocket_contrib::UUID;
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
use std::str::FromStr;
pub fn serialize<S>(val: &UUID, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
val.to_string().serialize(serializer)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<UUID, D::Error>
where
D: Deserializer<'de>,
{
let val: &str = Deserialize::deserialize(deserializer)?;
UUID::from_str(val).map_err(D::Error::custom)
}
}
See also:
How to transform fields during serialization using Serde?
How to transform fields during deserialization using Serde?
Is there a way for me to use #[derive] on a struct or enum from a library without editing the actual library's source code?
How do I implement a trait I don't own for a type I don't own?
Add Serialize attribute to type from third-party lib
Related
I have a struct defined like the following (other fields removed for brevity):
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Test {
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(with = "bson::serde_helpers::chrono_datetime_as_bson_datetime")]
pub time_period: Option<Vec<DateTime<Utc>>>
}
And I'm using the following in my Cargo.toml:
[dependencies]
bson = { version = "^2.4", default-features = false, features = [ "chrono-0_4" ] }
chrono = "^0.4"
serde = { version = "^1.0", default-features = false, features = [ "derive" ] }
But the serde derivations throw error because it expects a DateTime object:
error[E0308]: mismatched types
--> src/main.rs:4:39
|
4 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
| ^^^^^^^^^
| |
| expected struct `chrono::DateTime`, found enum `std::option::Option`
| arguments to this function are incorrect
|
= note: expected reference `&chrono::DateTime<Utc>`
found reference `&'__a std::option::Option<Vec<chrono::DateTime<Utc>>>`
note: function defined here
--> /home/kmdreko/.cargo/registry/src/github.com-1ecc6299db9ec823/bson-2.4.0/src/serde_helpers.rs:296:12
|
296 | pub fn serialize<S: Serializer>(
| ^^^^^^^^^
= note: this error originates in the derive macro `Serialize` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0308]: mismatched types
--> src/main.rs:4:50
|
4 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
| ^^^^^^^^^^^ expected enum `std::option::Option`, found struct `chrono::DateTime`
|
= note: expected enum `std::option::Option<Vec<chrono::DateTime<Utc>>>`
found struct `chrono::DateTime<Utc>`
= note: this error originates in the macro `try` (in Nightly builds, run with -Z macro-backtrace for more info)
Any ideas how to serialize optional vector of DateTime objects?
Serde's with attribute can only be used if your function/module expects the exact type of the field. That is not possible to change and sometimes you see *_opt functions/modules to provide support for Options, but never for arbitrary nesting.
The bson crate has a feature to use serde_with to work around that. You need to enable the serde_with feature of bson and import serde_with v1 into your code. Note the extra default attribute to serde. That is unnecessary for v2 of serde_with, but bson is still on v1.
#[serde_with::serde_as]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Test {
#[serde(skip_serializing_if = "Option::is_none", default)]
#[serde_as(as = "Option<Vec<bson::DateTime>>")]
pub time_period: Option<Vec<DateTime<Utc>>>
}
[dependencies]
bson = { version = "^2.4", default-features = false, features = [ "chrono-0_4", "serde_with" ] }
chrono = "^0.4"
serde = { version = "^1.0", default-features = false, features = [ "derive" ] }
serde_with = "1"
Run on Rustexplorer
Why doesn't the OP's code work
The bson::serde_helpers::chrono_datetime_as_bson_datetime module contains helper functions that (de)serializes a single chrono::DateTime object, so it doesn't work with the field of type Option<Vec<DateTime<Utc>>>.
Solution using nested struct
To (de)serialize such data, you can define a struct TestInner that contains the inner DateTime<Utc> object, along with the #[serde(transparent)] container attribute so that it's (de)serialized in the same way as a single DateTime<Utc> object. For example, the struct Test in the question can be changed into something like this.
#[derive(Debug, Serialize, Deserialize)]
pub struct Test {
#[serde(skip_serializing_if = "Option::is_none")]
pub time_period: Option<Vec<TestInner>>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(transparent)]
pub struct TestInner {
#[serde(with = "bson::serde_helpers::chrono_datetime_as_bson_datetime")]
datetime: DateTime<Utc>,
}
In my current project I'm trying to store a chrono::Duration in a configuration struct, which will be serialized and deserialized occasionally using serde_json.
Unfortunately, it appears that Serialize and Deserialize aren't implemented for chrono::Duration. That said, chrono says it has support for serde via one of its optional features. I tried using this method, but now the compiler is complaining about return methods:
error[E0308]: mismatched types
--> src/config.rs:6:10
|
6 | #[derive(Serialize, Deserialize, Debug, Clone)]
| ^^^^^^^^^ expected struct `DateTime`, found struct `chrono::Duration`
|
= note: expected reference `&DateTime<Utc>`
found reference `&'__a chrono::Duration`
= note: this error originates in the derive macro `Serialize` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0308]: mismatched types
--> src/config.rs:6:21
|
6 | #[derive(Serialize, Deserialize, Debug, Clone)]
| ^^^^^^^^^^^ expected struct `chrono::Duration`, found struct `DateTime`
|
= note: expected struct `chrono::Duration`
found struct `DateTime<Utc>`
= note: this error originates in the macro `try` (in Nightly builds, run with -Z macro-backtrace for more info)
Why is this happening? What can I do to fix it?
Here's the code in question:
use serde::{Serialize, Deserialize};
use chrono::{DateTime, Duration, Utc};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Config {
pub dest_ip: String,
#[serde(borrow)]
pub include_paths: Vec<&'static std::path::Path>,
pub exclude_paths: Vec<&'static std::path::Path>,
#[serde(with = "chrono::serde::ts_seconds")]
pub time_between_checks: Duration,
}
Also, here's the relevant bits of Cargo.toml:
serde_json = "1.0.72"
serde = { version = "1.0.130", features = ["derive"] }
chrono = { version = "0.4.19", features = ["serde"]}
You can use serde_with::DurationSeconds for serialization. It works identical to ts_seconds but supports more types and serialization forms.
#[serde_with::serde_as]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Config {
// ...
#[serde_as(as = "serde_with::DurationSeconds<i64>")]
pub time_between_checks: Duration,
}
I can't seem to get the provided example of serializing a struct with serde to work. I'm implementing the trait Serialize for my Address struct, but I get a compile error that this trait is not implemented. What am I doing wrong?
[dependencies]
serde = "1.0.118"
serde_json = "1.0.60"
use serde::{Deserialize, Serialize};
use serde_json::Result;
#[derive(Serialize, Deserialize)]
struct Address {
street: String,
city: String,
}
fn main(){
print_an_address();
}
fn print_an_address() -> Result<()> {
// Some data structure.
let address = Address {
street: "10 Downing Street".to_owned(),
city: "London".to_owned(),
};
// Serialize it to a JSON string.
let j = serde_json::to_string(&address)?;
// Print, write to a file, or send to an HTTP server.
println!("{}", j);
Ok(())
}
error[E0277]: the trait bound `Address: Serialize` is not satisfied
--> src\main.rs:21:35
|
21 | let j = serde_json::to_string(&address)?;
| ^^^^^^^^ the trait `Serialize` is not implemented for `Address`
|
::: C:\Users\Primary User\.cargo\registry\src\github.com-1ecc6299db9ec823\serde_json-1.0.60\src\ser.rs:2221:17
|
2221 | T: ?Sized + Serialize,
| --------- required by this bound in `serde_json::to_string`
You need to specify the derive feature for serde in Cargo.toml.
serde = { version = "1.0.118", features = ["derive"] }
See this for more info: https://serde.rs/derive.html
We're trying to return structure in RPC, but as far as I understand it should be serializable:
error[E0277]: the trait bound `pallet_spaces::Space<T>: serde::de::Deserialize<'_>` is not satisfied
--> pallets/spaces/rpc/src/lib.rs:15:1
|
15 | #[rpc]
| ^^^^^^ the trait `serde::de::Deserialize<'_>` is not implemented for `pallet_spaces::Space<T>`
|
= note: required because of the requirements on the impl of `for<'de> serde::de::Deserialize<'de>` for `std::vec::Vec<pallet_spaces::Space<T>>`
= note: required because of the requirements on the impl of `serde::de::DeserializeOwned` for `std::vec::Vec<pallet_spaces::Space<T>>`
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
The problem is that we use T::Moment from pallet_timestamp and it's not serializable, so we stuck at this point:
error[E0277]: the trait bound `<T as pallet_timestamp::Trait>::Moment: _::_serde::Serialize` is not satisfied
--> pallets/spaces/src/lib.rs:25:5
|
25 | pub created: WhoAndWhen<T>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `_::_serde::Serialize` is not implemented for `<T as pallet_timestamp::Trait>::Moment`
|
= note: required because of the requirements on the impl of `_::_serde::Serialize` for `pallet_utils::WhoAndWhen<T>`
= note: required by `_::_serde::ser::SerializeStruct::serialize_field`
What can you suggest to easily return a structure like this?
#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, Serialize, Deserialize)]
pub struct Space<T: Trait> {
pub id: SpaceId,
pub created: WhoAndWhen<T>,
pub updated: Option<WhoAndWhen<T>>,
pub owner: T::AccountId,
// Can be updated by the owner:
pub parent_id: Option<SpaceId>,
pub handle: Option<Vec<u8>>,
pub content: Content,
pub hidden: bool,
pub posts_count: u32,
pub hidden_posts_count: u32,
pub followers_count: u32,
pub score: i32,
/// Allows to override the default permissions for this space.
pub permissions: Option<SpacePermissions>,
}
#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, Serialize, Deserialize)]
pub struct WhoAndWhen<T: Trait> {
pub account: T::AccountId,
pub block: T::BlockNumber,
pub time: T::Moment,
}
Your main problem is that you are mixing std and no-std here. Substrate only depends on serde in std mode, as you can learn about in literally any Cargo.toml file in the project.
Start by fixing this: You only derive serde::* when you are in std mode.
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug)]
pub struct Space<T: Trait> {
// snip..
}
I am trying to declare a struct that contains another struct of any given type that can be Deserialize and Serialize.
#[derive(Debug, Serialize, Deserialize)]
pub struct Foo<T: Deserialize + Serialize> {
pub data: T,
}
Rust playground.
For that, I have tried to use trait bounds, using traits such as DeserializeOwned or Deserialize. Both have failed at compilation time with the following errors:
error[E0283]: type annotations required: cannot resolve `T: serde::Deserialize<'de>`
--> src/main.rs:9:28
|
9 | #[derive(Debug, Serialize, Deserialize)]
| ^^^^^^^^^^^
|
= note: required by `serde::Deserialize`
error[E0637]: `&` without an explicit lifetime name cannot be used here
--> src/main.rs:10:19
|
10 | pub struct Foo<T: Deserialize + Serialize> {
| ^^^^^^^^^^^ explicit lifetime name needed here
I faced errors trying to add a lifetime since I am not using storing a reference but a value.
What is the most idiomatic way of declaring this type of struct?
Just don't place the bounds on the type:
use serde::{Deserialize, Serialize}; // 1.0.91
#[derive(Debug, Serialize, Deserialize)]
pub struct Foo<T> {
pub data: T,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Boo {
pub a: i64,
}
fn main() {
let data = Boo { a: 1 };
let wrap = Foo { data };
println!("{:?}", wrap);
}
Then, place the bounds on methods where you need that behavior:
fn use_it<T>(foo: Foo<T>)
where
Foo<T>: Serialize,
{
// ...
}
I found a solution thanks to a member of the Rust Discord who referred me to the following Github issue. The trick is not to use trait bounds but attribute bounds.
#[derive(Debug, Serialize, Deserialize)]
pub struct Foo<T> {
#[serde(bound(
serialize = "T: Serialize",
deserialize = "T: Deserialize<'de>",
))]
pub data: T,
}