Serde JSON from Struct Example Not Working - rust

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

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

BorshDeserialize gives try_from_slice error

I was exploring the "BorshDeserialize" option in Rust. and noticed the following issues when using trait bounds. Any help is appreciated
Sample code
use borsh::{BorshDeserialize, BorshSerialize};
use solana_program::pubkey::Pubkey;
use std::mem;
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)]
struct SampleData<'a> {
accounts: (&'a Pubkey, &'a Pubkey),
data: String,
timestamp: u64,
owner: &'a Pubkey,
}
fn main() {
println!(
"Size of SampleData is {} bytes",
mem::size_of::<SampleData>()
);
let _pub_key = Pubkey::default();
let _a = SampleData {
accounts: (&_pub_key, &_pub_key),
data: "ABCDE".to_string(),
timestamp: 1643116047,
owner: &_pub_key,
};
let _encoded_a = _a.try_to_vec().unwrap();
println!("{:?}", _encoded_a);
let _decoded_a = SampleData::try_from_slice(&_encoded_a).unwrap();
println!("decoded_a: {:?}", _decoded_a);
}
Error message
error[E0599]: the function or associated item try_from_slice exists
for struct SampleData<'_>, but its trait bounds were not satisfied
--> src/main.rs:27:34 | 6 | struct SampleData<'a> { | --------------------- | | | function or associated item try_from_slice not found for this | doesn't satisfy
SampleData<'_>: BorshDeserialize ... 27 | let _decoded_a =
SampleData::try_from_slice(&_encoded_a).unwrap(); |
^^^^^^^^^^^^^^ function or associated item cannot be called on
SampleData<'_> due to unsatisfied trait bounds | note: the
following trait bounds were not satisfied because of the requirements
of the implementation of BorshDeserialize for _:
(&Pubkey, &Pubkey): BorshDeserialize
&Pubkey: BorshDeserialize --> src/main.rs:5:26 | 5 | #[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] | ^^^^^^^^^^^^^^^^ 6 | struct SampleData<'a> { |
^^^^^^^^^^^^^^ = help: items from traits can only be used if the
trait is implemented and in scope = note: the following trait
defines an item try_from_slice, perhaps you need to implement it:
candidate #1: BorshDeserialize = note: this error originates in the derive macro BorshDeserialize (in Nightly builds,
run with -Z macro-backtrace for more info)
For more information about this error, try rustc --explain E0599.
error: could not compile seralize due to previous error
The problem is that SampleData contains references, which isn't supported in normal Borsh deserialization. Borsh creates a new instance of your type based on a slice, but it won't be able to create references.
If you want to stick with Borsh, you should change the type to:
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)]
struct SampleData {
accounts: (Pubkey, Pubkey),
data: String,
timestamp: u64,
owner: Pubkey,
}

How to use a custom serde deserializer for chrono timestamps?

I'm trying to parse JSON into a struct which has a chrono::DateTime field. The JSON has the timestamps saved in a custom format that I wrote a deserializer for.
How do I connect the two and get it working using #[serde(deserialize_with)]?
I'm using NaiveDateTime for simpler code
extern crate serde;
extern crate serde_json;
use serde::Deserialize;
extern crate chrono;
use chrono::NaiveDateTime;
fn from_timestamp(time: &String) -> NaiveDateTime {
NaiveDateTime::parse_from_str(time, "%Y-%m-%dT%H:%M:%S.%f").unwrap()
}
#[derive(Deserialize, Debug)]
struct MyJson {
name: String,
#[serde(deserialize_with = "from_timestamp")]
timestamp: NaiveDateTime,
}
fn main() {
let result: MyJson =
serde_json::from_str(r#"{"name": "asdf", "timestamp": "2019-08-15T17:41:18.106108"}"#)
.unwrap();
println!("{:?}", result);
}
I'm getting three different compile errors:
error[E0308]: mismatched types
--> src/main.rs:11:10
|
11 | #[derive(Deserialize, Debug)]
| ^^^^^^^^^^^ expected reference, found type parameter
|
= note: expected type `&std::string::String`
found type `__D`
error[E0308]: mismatched types
--> src/main.rs:11:10
|
11 | #[derive(Deserialize, Debug)]
| ^^^^^^^^^^-
| | |
| | this match expression has type `chrono::NaiveDateTime`
| expected struct `chrono::NaiveDateTime`, found enum `std::result::Result`
| in this macro invocation
|
= note: expected type `chrono::NaiveDateTime`
found type `std::result::Result<_, _>`
error[E0308]: mismatched types
--> src/main.rs:11:10
|
11 | #[derive(Deserialize, Debug)]
| ^^^^^^^^^^-
| | |
| | this match expression has type `chrono::NaiveDateTime`
| expected struct `chrono::NaiveDateTime`, found enum `std::result::Result`
| in this macro invocation
|
= note: expected type `chrono::NaiveDateTime`
found type `std::result::Result<_, _>`
I'm pretty sure the from_timestamp function is returning a DateTime struct and not a Result, so I don't know what "expected struct chrono::NaiveDateTime, found enum std::result::Result" may mean.
While #edwardw's answer is technically correct it IMHO contains too much boilerplate.
NaiveDataTime implements FromStr which means you can write a reusable generic deserializer function.
A convoluted example - did add the age field (u8) represented as string in the JSON. Just to demonstrate that you can use it for anything that implements FromStr.
use std::fmt::Display;
use std::str::FromStr;
use chrono::NaiveDateTime;
use serde::{de, Deserialize, Deserializer};
#[derive(Deserialize, Debug)]
struct MyJson {
name: String,
#[serde(deserialize_with = "deserialize_from_str")]
timestamp: NaiveDateTime,
#[serde(deserialize_with = "deserialize_from_str")]
age: u8,
}
// You can use this deserializer for any type that implements FromStr
// and the FromStr::Err implements Display
fn deserialize_from_str<'de, S, D>(deserializer: D) -> Result<S, D::Error>
where
S: FromStr, // Required for S::from_str...
S::Err: Display, // Required for .map_err(de::Error::custom)
D: Deserializer<'de>,
{
let s: String = Deserialize::deserialize(deserializer)?;
S::from_str(&s).map_err(de::Error::custom)
}
fn main() {
let result: MyJson = serde_json::from_str(
r#"{"name": "asdf", "timestamp": "2019-08-15T17:41:18.106108", "age": "11"}"#,
)
.unwrap();
println!("{:?}", result);
}
It's even easier if you want to specify format (use NaiveDateTime::parse_from_str):
use chrono::NaiveDateTime;
use serde::{de, Deserialize, Deserializer};
#[derive(Deserialize, Debug)]
struct MyJson {
name: String,
#[serde(deserialize_with = "naive_date_time_from_str")]
timestamp: NaiveDateTime,
}
fn naive_date_time_from_str<'de, D>(deserializer: D) -> Result<NaiveDateTime, D::Error>
where
D: Deserializer<'de>,
{
let s: String = Deserialize::deserialize(deserializer)?;
NaiveDateTime::parse_from_str(&s, "%Y-%m-%dT%H:%M:%S.%f").map_err(de::Error::custom)
}
fn main() {
let result: MyJson =
serde_json::from_str(r#"{"name": "asdf", "timestamp": "2019-08-15T17:41:18.106108"}"#)
.unwrap();
println!("{:?}", result);
}
#[serde(deserialize_with = "path")] documentation:
Deserialize this field using a function that is different from its implementation of Deserialize. The given function must be callable as fn<'de, D>(D) -> Result<T, D::Error> where D: Deserializer<'de>, although it may also be generic over T. Fields used with deserialize_with are not required to implement Deserialize.
This is rather involved, but the following works:
use chrono::NaiveDateTime;
use serde::de;
use serde::Deserialize;
use std::fmt;
struct NaiveDateTimeVisitor;
impl<'de> de::Visitor<'de> for NaiveDateTimeVisitor {
type Value = NaiveDateTime;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a string represents chrono::NaiveDateTime")
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
match NaiveDateTime::parse_from_str(s, "%Y-%m-%dT%H:%M:%S.%f") {
Ok(t) => Ok(t),
Err(_) => Err(de::Error::invalid_value(de::Unexpected::Str(s), &self)),
}
}
}
fn from_timestamp<'de, D>(d: D) -> Result<NaiveDateTime, D::Error>
where
D: de::Deserializer<'de>,
{
d.deserialize_str(NaiveDateTimeVisitor)
}
#[derive(Deserialize, Debug)]
struct MyJson {
name: String,
#[serde(deserialize_with = "from_timestamp")]
timestamp: NaiveDateTime,
}
fn main() {
let result: MyJson =
serde_json::from_str(r#"{"name": "asdf", "timestamp": "2019-08-15T17:41:18.106108"}"#)
.unwrap();
println!("{:?}", result);
}

How do I declare a struct that contains any kind of Deserializable/Serializable struct?

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

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