How to serialize and deserialize chrono::Duration? - rust

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,
}

Related

How to serialize Option<Vec<DateTime>> field to bson?

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>,
}

How to use chrono::DateTime<Utc> with schemars::JsonSchema?

I'm trying to implement JsonSchema for a struct like this:
use chrono::{DateTime, Utc};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Default, Clone, JsonSchema)]
pub struct ArticleResponse {
pub pub_time: Option<DateTime<Utc>>,
}
But this outputs an error when compiling:
error[E0277]: the trait bound `DateTime<Utc>: JsonSchema` is not satisfied
--> src/main.rs:4:50
|
4 | #[derive(Serialize, Deserialize, Default, Clone, JsonSchema)]
| ^^^^^^^^^^ the trait `JsonSchema` is not implemented for `DateTime<Utc>`
What should I do to implement JsonSchema for ArticleResponse?
To quote the docs:
For example, to implement JsonSchema on types from chrono, enable it as a feature in the schemars dependency in your Cargo.toml like so:
[dependencies]
schemars = { version = "0.8", features = ["chrono"] }

Compiler says: the trait bound `Foo: serde::de::Deserialize` is not satisfied - when it is

I endeavour to save my struct to user preferences. My code follows
use serde::{Serialize, Deserialize};
use preferences::AppInfo;
const APP_INFO: AppInfo = AppInfo{name: "some-name", author: "some-author"};
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct Foo {
bar: i32
}
fn main() {
let x = Foo{bar: 12};
// Attempt 1: cannot find a `save` function
// x.save(x, &APP_INFO, "foo/bar").unwrap();
// Attempt 2: Foo leaves Serialize & Deserialise unsatisfied
preferences::Preferences::save(&x, &APP_INFO, "foo/bar").unwrap();
}
Despite this line #[derive(Serialize, Deserialize, PartialEq, Debug)] the compiler grumbles ..
error[E0277]: the trait bound `Foo: serde::ser::Serialize` is not satisfied
--> src/main.rs:17:5
|
17 | preferences::Preferences::save(&x, &APP_INFO, "foo/bar").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `serde::ser::Serialize` is not implemented for `Foo`
|
::: /Users/martincowie/.cargo/registry/src/github.com-1ecc6299db9ec823/preferences-1.1.0/src/lib.rs:302:16
|
302 | fn save<S: AsRef<str>>(&self, app: &AppInfo, key: S) -> Result<(), PreferencesError>;
| ---------- required by this bound in `save`
|
= note: required because of the requirements on the impl of `Preferences` for `Foo`
The unsatisfied trait bound <S: AsRef<str>> relates to the parameter key, which is a string literal.
This is more or less inspired by the example at https://docs.rs/preferences/1.1.0/preferences/
What need I do to placate the compiler?
Check your cargo.lock. Most likely, your main application is pulling in a different version of serde than the preferences crate.
It appears that preferences depends on serde-0.9, but chances are you're pulling in serde-1.0. This means that your struct implements serde-1.0::Deserialize, but preferences wants serde-0.9::Deserialize.
The inability of the compiler to produce a nice message for this case is a long-standing bug.

Cannot infer type for type parameter when deriving Deserialize for a type with a generic with a Deserialize trait bound

I use a generic which is serializable and deserializable. However, there is an error on the Deserialize derive attribute telling that the type can not be inferred.
The compile error is thrown for both struct and enum. Commenting one of those will not resolve anything.
use serde::{Deserialize, Serialize}; // 1.0.104
#[derive(Serialize, Deserialize)]
struct Jhon<A>
where
A: Serialize + for<'a> Deserialize<'a>,
{
foo: Foo<A>,
}
#[derive(Serialize, Deserialize)]
enum Foo<A>
where
A: Serialize + for<'a> Deserialize<'a>,
{
A,
B(A),
}
error[E0283]: type annotations needed
--> src/lib.rs:3:21
|
3 | #[derive(Serialize, Deserialize)]
| ^^^^^^^^^^^ cannot infer type for type parameter `A`
|
= note: cannot resolve `A: _IMPL_DESERIALIZE_FOR_Jhon::_serde::Deserialize<'de>`
= note: required by `_IMPL_DESERIALIZE_FOR_Jhon::_serde::Deserialize`
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0283]: type annotations needed
--> src/lib.rs:3:21
|
3 | #[derive(Serialize, Deserialize)]
| ^^^^^^^^^^^ cannot infer type for type parameter `A`
|
= note: cannot resolve `A: _IMPL_DESERIALIZE_FOR_Jhon::_serde::Deserialize<'_>`
= note: required because of the requirements on the impl of `_IMPL_DESERIALIZE_FOR_Jhon::_serde::de::Visitor<'de>` for `_IMPL_DESERIALIZE_FOR_Jhon::<impl _IMPL_DESERIALIZE_FOR_Jhon::_serde::Deserialize<'de> for Jhon<A>>::deserialize::__Visitor<'de, A>`
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0283]: type annotations needed
--> src/lib.rs:11:21
|
11 | #[derive(Serialize, Deserialize)]
| ^^^^^^^^^^^ cannot infer type for type parameter `A`
|
= note: cannot resolve `A: _IMPL_DESERIALIZE_FOR_Jhon::_serde::Deserialize<'de>`
= note: required by `_IMPL_DESERIALIZE_FOR_Jhon::_serde::Deserialize`
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0283]: type annotations needed
--> src/lib.rs:11:21
|
11 | #[derive(Serialize, Deserialize)]
| ^^^^^^^^^^^ cannot infer type for type parameter `A`
|
= note: cannot resolve `A: _IMPL_DESERIALIZE_FOR_Jhon::_serde::Deserialize<'_>`
= note: required because of the requirements on the impl of `_IMPL_DESERIALIZE_FOR_Jhon::_serde::de::Visitor<'de>` for `_IMPL_DESERIALIZE_FOR_Foo::<impl _IMPL_DESERIALIZE_FOR_Jhon::_serde::Deserialize<'de> for Foo<A>>::deserialize::__Visitor<'de, A>`
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
Playground
You don't need the trait bounds. It is also generally unadvisable to do so on structs. This code works:
#[derive(Clone, Serialize, Deserialize)]
struct Jhon<A> {
foo: Foo<A>
}
#[derive(Clone, Serialize, Deserialize)]
enum Foo<A> {
A,
B(A)
}
Rust playground example
Serde automatically tries to determine the bounds on Deserialize and Serialize implementations when you use its derive macro implementation. To use custom bounds you need to tell Serde that you are doing this using the #[serde(bound = "...")] attribute.
#[derive(Clone, Serialize, Deserialize)]
#[serde(bound = "A: Serialize + for<'a> A: Deserialize<'a>")]
struct Jhon<A> where A: Serialize + for<'a> Deserialize<'a>{
foo: Foo<A>
}
#[derive(Clone, Serialize, Deserialize)]
#[serde(bound = "A: Serialize + for<'a> A: Deserialize<'a>")]
enum Foo<A> where A: Serialize + for<'a> Deserialize<'a>, {
A,
B(A)
}
Rust playground example
In addition to the answer given above, I should point out (since I ran into this myself today) that sometimes you already have the Deserialize bound satisfied in a supertrait the problematic type parameter, and this error represents serde trying and failing to supply its own (redundant) bound on that type parameter.
In that case you still want to use the serde(bound) attribute but with an empty bound: that is, annotate with #[serde(bound = "")].

Serde's Serialize implementation not found for Rocket's UUID

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

Resources