How can I mass implement Deserialize for all types that implement a specific trait?












2















I am deserializing a YAML config file with Serde. For most structs I deserialize into, things are quite simple — there's a one-to-one relationship between the fields of the structs and the properties in my YAML file.



In a few cases, things are a bit more complicated. For these, the properties in the YAML file are better viewed as parameters to the constructor. The actual struct will have different fields, calculated from those.



For these cases, I have written separate config structs that I deserialize into. For simplicity, consider this silly example:



struct Message {
text: String,
}

impl Message {
fn from_config(config: MessageConfig) -> Message {
Message {
text: format!("{} {}", config.first_half, config.second_half),
}
}
}

#[derive(Deserialize)]
struct MessageConfig {
first_half: String,
second_half: String,
}


To have Serde do the conversion from MessageConfig to Message for me, I implemented Deserialize for Message:



impl<'de> Deserialize<'de> for Message {
fn deserialize<D>(deserializer: D) -> Result<Message, D::Error>
where
D: Deserializer<'de>,
{
MessageConfig::deserialize(deserializer).map(|config| Message::from_config(config))
}
}


This works, but there would be a lot of copy pasting of the deserialization code involved if I were to do this for every struct, so I figured I should make a trait out of it:



use serde::{Deserialize, Deserializer};
use serde_json;
#[macro_use]
extern crate serde_derive;

trait Configurable {
type Config;
fn from_config(config: Self::Config) -> Self;
}

impl<'de, T, C> Deserialize<'de> for T
where
T: Configurable<Config = C>,
C: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
{
Self::Config::deserialize(deserializer).map(|config| Self::from_config(config))
}
}

struct Message {
text: String,
}

impl<'de> Configurable for Message {
type Config = MessageConfig;

fn from_config(config: MessageConfig) -> Message {
Message {
text: format!("{} {}", config.first_half, config.second_half),
}
}
}

#[derive(Deserialize)]
struct MessageConfig {
first_half: String,
second_half: String,
}


However, the compiler is not happy about this:



error[E0119]: conflicting implementations of trait `_IMPL_DESERIALIZE_FOR_MessageConfig::_serde::Deserialize<'_>` for type `std::boxed::Box<_>`:
--> src/lib.rs:11:1
|
11 | / impl<'de, T, C> Deserialize<'de> for T
12 | | where
13 | | T: Configurable<Config = C>,
14 | | C: Deserialize<'de>,
... |
21 | | }
22 | | }
| |_^
|
= note: conflicting implementation in crate `serde`:
- impl<'de, T> _IMPL_DESERIALIZE_FOR_MessageConfig::_serde::Deserialize<'de> for std::boxed::Box<T>
where T: _IMPL_DESERIALIZE_FOR_MessageConfig::_serde::Deserialize<'de>;
= note: downstream crates may implement trait `Configurable` for type `std::boxed::Box<_>`

error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g. `MyStruct<T>`)
--> src/lib.rs:11:1
|
11 | / impl<'de, T, C> Deserialize<'de> for T
12 | | where
13 | | T: Configurable<Config = C>,
14 | | C: Deserialize<'de>,
... |
21 | | }
22 | | }
| |_^ type parameter `T` must be used as the type parameter for some local type
|
= note: only traits defined in the current crate can be implemented for a type parameter


The error messages make little sense to me. What does Box have to do with anything? And is it somehow possible to make this trait work?










share|improve this question

























  • @Shepmaster I don't think it's a duplicate. The suggested dup: A struct has a field that references a trait. How do I deserialize? This question: I want to mass implement Deserialize for all types that implement a specific trait.

    – Anders
    Jan 2 at 22:38











  • If all of your structs have the same implementation for deserialization, then why not make them the same actual struct (or all contain the same struct) and implement Deserialize for that? If they aren't the same, then what's the benefit of adding extra indirection?

    – Shepmaster
    Jan 2 at 22:56











  • The error is relatively straight-forward. Serde implements Deserialize for Box<T>. Your implementation covers for T, which might be a Box<T>. A user of both crates could construct a type that could be deserialized as either your code or the one in Serde. This is disallowed.

    – Shepmaster
    Jan 2 at 23:01











  • @Shepmaster Maybe I am doing a basic mistake here. I thought by specifying where T: Configurable<Config = C> my implementation of Deserialize would only cover implementors of Configurable. Box<T> is not an implementor of Configurable, so I figured there wouldn't be a problem.

    – Anders
    Jan 2 at 23:04






  • 2





    What prevents someone from implementing Configurable for Box<MyOwnType> when MyOwnType also implements Deserialize?

    – Shepmaster
    Jan 2 at 23:06
















2















I am deserializing a YAML config file with Serde. For most structs I deserialize into, things are quite simple — there's a one-to-one relationship between the fields of the structs and the properties in my YAML file.



In a few cases, things are a bit more complicated. For these, the properties in the YAML file are better viewed as parameters to the constructor. The actual struct will have different fields, calculated from those.



For these cases, I have written separate config structs that I deserialize into. For simplicity, consider this silly example:



struct Message {
text: String,
}

impl Message {
fn from_config(config: MessageConfig) -> Message {
Message {
text: format!("{} {}", config.first_half, config.second_half),
}
}
}

#[derive(Deserialize)]
struct MessageConfig {
first_half: String,
second_half: String,
}


To have Serde do the conversion from MessageConfig to Message for me, I implemented Deserialize for Message:



impl<'de> Deserialize<'de> for Message {
fn deserialize<D>(deserializer: D) -> Result<Message, D::Error>
where
D: Deserializer<'de>,
{
MessageConfig::deserialize(deserializer).map(|config| Message::from_config(config))
}
}


This works, but there would be a lot of copy pasting of the deserialization code involved if I were to do this for every struct, so I figured I should make a trait out of it:



use serde::{Deserialize, Deserializer};
use serde_json;
#[macro_use]
extern crate serde_derive;

trait Configurable {
type Config;
fn from_config(config: Self::Config) -> Self;
}

impl<'de, T, C> Deserialize<'de> for T
where
T: Configurable<Config = C>,
C: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
{
Self::Config::deserialize(deserializer).map(|config| Self::from_config(config))
}
}

struct Message {
text: String,
}

impl<'de> Configurable for Message {
type Config = MessageConfig;

fn from_config(config: MessageConfig) -> Message {
Message {
text: format!("{} {}", config.first_half, config.second_half),
}
}
}

#[derive(Deserialize)]
struct MessageConfig {
first_half: String,
second_half: String,
}


However, the compiler is not happy about this:



error[E0119]: conflicting implementations of trait `_IMPL_DESERIALIZE_FOR_MessageConfig::_serde::Deserialize<'_>` for type `std::boxed::Box<_>`:
--> src/lib.rs:11:1
|
11 | / impl<'de, T, C> Deserialize<'de> for T
12 | | where
13 | | T: Configurable<Config = C>,
14 | | C: Deserialize<'de>,
... |
21 | | }
22 | | }
| |_^
|
= note: conflicting implementation in crate `serde`:
- impl<'de, T> _IMPL_DESERIALIZE_FOR_MessageConfig::_serde::Deserialize<'de> for std::boxed::Box<T>
where T: _IMPL_DESERIALIZE_FOR_MessageConfig::_serde::Deserialize<'de>;
= note: downstream crates may implement trait `Configurable` for type `std::boxed::Box<_>`

error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g. `MyStruct<T>`)
--> src/lib.rs:11:1
|
11 | / impl<'de, T, C> Deserialize<'de> for T
12 | | where
13 | | T: Configurable<Config = C>,
14 | | C: Deserialize<'de>,
... |
21 | | }
22 | | }
| |_^ type parameter `T` must be used as the type parameter for some local type
|
= note: only traits defined in the current crate can be implemented for a type parameter


The error messages make little sense to me. What does Box have to do with anything? And is it somehow possible to make this trait work?










share|improve this question

























  • @Shepmaster I don't think it's a duplicate. The suggested dup: A struct has a field that references a trait. How do I deserialize? This question: I want to mass implement Deserialize for all types that implement a specific trait.

    – Anders
    Jan 2 at 22:38











  • If all of your structs have the same implementation for deserialization, then why not make them the same actual struct (or all contain the same struct) and implement Deserialize for that? If they aren't the same, then what's the benefit of adding extra indirection?

    – Shepmaster
    Jan 2 at 22:56











  • The error is relatively straight-forward. Serde implements Deserialize for Box<T>. Your implementation covers for T, which might be a Box<T>. A user of both crates could construct a type that could be deserialized as either your code or the one in Serde. This is disallowed.

    – Shepmaster
    Jan 2 at 23:01











  • @Shepmaster Maybe I am doing a basic mistake here. I thought by specifying where T: Configurable<Config = C> my implementation of Deserialize would only cover implementors of Configurable. Box<T> is not an implementor of Configurable, so I figured there wouldn't be a problem.

    – Anders
    Jan 2 at 23:04






  • 2





    What prevents someone from implementing Configurable for Box<MyOwnType> when MyOwnType also implements Deserialize?

    – Shepmaster
    Jan 2 at 23:06














2












2








2








I am deserializing a YAML config file with Serde. For most structs I deserialize into, things are quite simple — there's a one-to-one relationship between the fields of the structs and the properties in my YAML file.



In a few cases, things are a bit more complicated. For these, the properties in the YAML file are better viewed as parameters to the constructor. The actual struct will have different fields, calculated from those.



For these cases, I have written separate config structs that I deserialize into. For simplicity, consider this silly example:



struct Message {
text: String,
}

impl Message {
fn from_config(config: MessageConfig) -> Message {
Message {
text: format!("{} {}", config.first_half, config.second_half),
}
}
}

#[derive(Deserialize)]
struct MessageConfig {
first_half: String,
second_half: String,
}


To have Serde do the conversion from MessageConfig to Message for me, I implemented Deserialize for Message:



impl<'de> Deserialize<'de> for Message {
fn deserialize<D>(deserializer: D) -> Result<Message, D::Error>
where
D: Deserializer<'de>,
{
MessageConfig::deserialize(deserializer).map(|config| Message::from_config(config))
}
}


This works, but there would be a lot of copy pasting of the deserialization code involved if I were to do this for every struct, so I figured I should make a trait out of it:



use serde::{Deserialize, Deserializer};
use serde_json;
#[macro_use]
extern crate serde_derive;

trait Configurable {
type Config;
fn from_config(config: Self::Config) -> Self;
}

impl<'de, T, C> Deserialize<'de> for T
where
T: Configurable<Config = C>,
C: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
{
Self::Config::deserialize(deserializer).map(|config| Self::from_config(config))
}
}

struct Message {
text: String,
}

impl<'de> Configurable for Message {
type Config = MessageConfig;

fn from_config(config: MessageConfig) -> Message {
Message {
text: format!("{} {}", config.first_half, config.second_half),
}
}
}

#[derive(Deserialize)]
struct MessageConfig {
first_half: String,
second_half: String,
}


However, the compiler is not happy about this:



error[E0119]: conflicting implementations of trait `_IMPL_DESERIALIZE_FOR_MessageConfig::_serde::Deserialize<'_>` for type `std::boxed::Box<_>`:
--> src/lib.rs:11:1
|
11 | / impl<'de, T, C> Deserialize<'de> for T
12 | | where
13 | | T: Configurable<Config = C>,
14 | | C: Deserialize<'de>,
... |
21 | | }
22 | | }
| |_^
|
= note: conflicting implementation in crate `serde`:
- impl<'de, T> _IMPL_DESERIALIZE_FOR_MessageConfig::_serde::Deserialize<'de> for std::boxed::Box<T>
where T: _IMPL_DESERIALIZE_FOR_MessageConfig::_serde::Deserialize<'de>;
= note: downstream crates may implement trait `Configurable` for type `std::boxed::Box<_>`

error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g. `MyStruct<T>`)
--> src/lib.rs:11:1
|
11 | / impl<'de, T, C> Deserialize<'de> for T
12 | | where
13 | | T: Configurable<Config = C>,
14 | | C: Deserialize<'de>,
... |
21 | | }
22 | | }
| |_^ type parameter `T` must be used as the type parameter for some local type
|
= note: only traits defined in the current crate can be implemented for a type parameter


The error messages make little sense to me. What does Box have to do with anything? And is it somehow possible to make this trait work?










share|improve this question
















I am deserializing a YAML config file with Serde. For most structs I deserialize into, things are quite simple — there's a one-to-one relationship between the fields of the structs and the properties in my YAML file.



In a few cases, things are a bit more complicated. For these, the properties in the YAML file are better viewed as parameters to the constructor. The actual struct will have different fields, calculated from those.



For these cases, I have written separate config structs that I deserialize into. For simplicity, consider this silly example:



struct Message {
text: String,
}

impl Message {
fn from_config(config: MessageConfig) -> Message {
Message {
text: format!("{} {}", config.first_half, config.second_half),
}
}
}

#[derive(Deserialize)]
struct MessageConfig {
first_half: String,
second_half: String,
}


To have Serde do the conversion from MessageConfig to Message for me, I implemented Deserialize for Message:



impl<'de> Deserialize<'de> for Message {
fn deserialize<D>(deserializer: D) -> Result<Message, D::Error>
where
D: Deserializer<'de>,
{
MessageConfig::deserialize(deserializer).map(|config| Message::from_config(config))
}
}


This works, but there would be a lot of copy pasting of the deserialization code involved if I were to do this for every struct, so I figured I should make a trait out of it:



use serde::{Deserialize, Deserializer};
use serde_json;
#[macro_use]
extern crate serde_derive;

trait Configurable {
type Config;
fn from_config(config: Self::Config) -> Self;
}

impl<'de, T, C> Deserialize<'de> for T
where
T: Configurable<Config = C>,
C: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
{
Self::Config::deserialize(deserializer).map(|config| Self::from_config(config))
}
}

struct Message {
text: String,
}

impl<'de> Configurable for Message {
type Config = MessageConfig;

fn from_config(config: MessageConfig) -> Message {
Message {
text: format!("{} {}", config.first_half, config.second_half),
}
}
}

#[derive(Deserialize)]
struct MessageConfig {
first_half: String,
second_half: String,
}


However, the compiler is not happy about this:



error[E0119]: conflicting implementations of trait `_IMPL_DESERIALIZE_FOR_MessageConfig::_serde::Deserialize<'_>` for type `std::boxed::Box<_>`:
--> src/lib.rs:11:1
|
11 | / impl<'de, T, C> Deserialize<'de> for T
12 | | where
13 | | T: Configurable<Config = C>,
14 | | C: Deserialize<'de>,
... |
21 | | }
22 | | }
| |_^
|
= note: conflicting implementation in crate `serde`:
- impl<'de, T> _IMPL_DESERIALIZE_FOR_MessageConfig::_serde::Deserialize<'de> for std::boxed::Box<T>
where T: _IMPL_DESERIALIZE_FOR_MessageConfig::_serde::Deserialize<'de>;
= note: downstream crates may implement trait `Configurable` for type `std::boxed::Box<_>`

error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g. `MyStruct<T>`)
--> src/lib.rs:11:1
|
11 | / impl<'de, T, C> Deserialize<'de> for T
12 | | where
13 | | T: Configurable<Config = C>,
14 | | C: Deserialize<'de>,
... |
21 | | }
22 | | }
| |_^ type parameter `T` must be used as the type parameter for some local type
|
= note: only traits defined in the current crate can be implemented for a type parameter


The error messages make little sense to me. What does Box have to do with anything? And is it somehow possible to make this trait work?







rust deserialization traits serde






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 2 at 22:53









Shepmaster

160k16330473




160k16330473










asked Jan 2 at 21:00









AndersAnders

5,82963255




5,82963255













  • @Shepmaster I don't think it's a duplicate. The suggested dup: A struct has a field that references a trait. How do I deserialize? This question: I want to mass implement Deserialize for all types that implement a specific trait.

    – Anders
    Jan 2 at 22:38











  • If all of your structs have the same implementation for deserialization, then why not make them the same actual struct (or all contain the same struct) and implement Deserialize for that? If they aren't the same, then what's the benefit of adding extra indirection?

    – Shepmaster
    Jan 2 at 22:56











  • The error is relatively straight-forward. Serde implements Deserialize for Box<T>. Your implementation covers for T, which might be a Box<T>. A user of both crates could construct a type that could be deserialized as either your code or the one in Serde. This is disallowed.

    – Shepmaster
    Jan 2 at 23:01











  • @Shepmaster Maybe I am doing a basic mistake here. I thought by specifying where T: Configurable<Config = C> my implementation of Deserialize would only cover implementors of Configurable. Box<T> is not an implementor of Configurable, so I figured there wouldn't be a problem.

    – Anders
    Jan 2 at 23:04






  • 2





    What prevents someone from implementing Configurable for Box<MyOwnType> when MyOwnType also implements Deserialize?

    – Shepmaster
    Jan 2 at 23:06



















  • @Shepmaster I don't think it's a duplicate. The suggested dup: A struct has a field that references a trait. How do I deserialize? This question: I want to mass implement Deserialize for all types that implement a specific trait.

    – Anders
    Jan 2 at 22:38











  • If all of your structs have the same implementation for deserialization, then why not make them the same actual struct (or all contain the same struct) and implement Deserialize for that? If they aren't the same, then what's the benefit of adding extra indirection?

    – Shepmaster
    Jan 2 at 22:56











  • The error is relatively straight-forward. Serde implements Deserialize for Box<T>. Your implementation covers for T, which might be a Box<T>. A user of both crates could construct a type that could be deserialized as either your code or the one in Serde. This is disallowed.

    – Shepmaster
    Jan 2 at 23:01











  • @Shepmaster Maybe I am doing a basic mistake here. I thought by specifying where T: Configurable<Config = C> my implementation of Deserialize would only cover implementors of Configurable. Box<T> is not an implementor of Configurable, so I figured there wouldn't be a problem.

    – Anders
    Jan 2 at 23:04






  • 2





    What prevents someone from implementing Configurable for Box<MyOwnType> when MyOwnType also implements Deserialize?

    – Shepmaster
    Jan 2 at 23:06

















@Shepmaster I don't think it's a duplicate. The suggested dup: A struct has a field that references a trait. How do I deserialize? This question: I want to mass implement Deserialize for all types that implement a specific trait.

– Anders
Jan 2 at 22:38





@Shepmaster I don't think it's a duplicate. The suggested dup: A struct has a field that references a trait. How do I deserialize? This question: I want to mass implement Deserialize for all types that implement a specific trait.

– Anders
Jan 2 at 22:38













If all of your structs have the same implementation for deserialization, then why not make them the same actual struct (or all contain the same struct) and implement Deserialize for that? If they aren't the same, then what's the benefit of adding extra indirection?

– Shepmaster
Jan 2 at 22:56





If all of your structs have the same implementation for deserialization, then why not make them the same actual struct (or all contain the same struct) and implement Deserialize for that? If they aren't the same, then what's the benefit of adding extra indirection?

– Shepmaster
Jan 2 at 22:56













The error is relatively straight-forward. Serde implements Deserialize for Box<T>. Your implementation covers for T, which might be a Box<T>. A user of both crates could construct a type that could be deserialized as either your code or the one in Serde. This is disallowed.

– Shepmaster
Jan 2 at 23:01





The error is relatively straight-forward. Serde implements Deserialize for Box<T>. Your implementation covers for T, which might be a Box<T>. A user of both crates could construct a type that could be deserialized as either your code or the one in Serde. This is disallowed.

– Shepmaster
Jan 2 at 23:01













@Shepmaster Maybe I am doing a basic mistake here. I thought by specifying where T: Configurable<Config = C> my implementation of Deserialize would only cover implementors of Configurable. Box<T> is not an implementor of Configurable, so I figured there wouldn't be a problem.

– Anders
Jan 2 at 23:04





@Shepmaster Maybe I am doing a basic mistake here. I thought by specifying where T: Configurable<Config = C> my implementation of Deserialize would only cover implementors of Configurable. Box<T> is not an implementor of Configurable, so I figured there wouldn't be a problem.

– Anders
Jan 2 at 23:04




2




2





What prevents someone from implementing Configurable for Box<MyOwnType> when MyOwnType also implements Deserialize?

– Shepmaster
Jan 2 at 23:06





What prevents someone from implementing Configurable for Box<MyOwnType> when MyOwnType also implements Deserialize?

– Shepmaster
Jan 2 at 23:06












1 Answer
1






active

oldest

votes


















1














I am not sure if there's a way to define such a broad trait without causing conflicting implementations. What you could do is use a macro to avoid repetition:



use serde::{Deserialize, Deserializer};
use serde_json;

use serde_json::Error;

#[macro_use]
extern crate serde_derive;

struct Message {
text: String,
}

#[derive(Deserialize)]
struct MessageConfig {
first_half: String,
second_half: String,
}

impl Message {
fn from_config(config: MessageConfig) -> Message {
Message {
text: format!("{} {}", config.first_half, config.second_half),
}
}
}

macro_rules! derive_configurable_serializer {
( $t:ident, $c:ident ) => {
impl<'de> Deserialize<'de> for $t {
fn deserialize<D>(deserializer: D) -> Result<$t, D::Error>
where
D: Deserializer<'de>,
{
$c::deserialize(deserializer).map(|config| $t::from_config(config))
}
}
};
}

derive_configurable_serializer!(Message, MessageConfig);

fn main() -> Result<(), Error> {
let data = r#"{ "first_half": "John", "second_half": "Doe" }"#;

let p: Message = serde_json::from_str(data)?;

println!("Hello, {}!", p.text);

Ok(())
}





share|improve this answer


























  • Nice idea with a macro, and thanks for showing how to do it! I don't understand what's up with the conflicting implementations, though. There is no type that implements both Configurable and Deserialize from some other source.

    – Anders
    Jan 2 at 22:42






  • 1





    @Anders honestly - I don't know. I tried finding a solution with the trait, got various error messages. Maybe someone with a deeper understanding of Rust traits can explain how to do it / why it isn't possible.

    – Ramon Snir
    Jan 2 at 22:44












Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54013125%2fhow-can-i-mass-implement-deserialize-for-all-types-that-implement-a-specific-tra%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














I am not sure if there's a way to define such a broad trait without causing conflicting implementations. What you could do is use a macro to avoid repetition:



use serde::{Deserialize, Deserializer};
use serde_json;

use serde_json::Error;

#[macro_use]
extern crate serde_derive;

struct Message {
text: String,
}

#[derive(Deserialize)]
struct MessageConfig {
first_half: String,
second_half: String,
}

impl Message {
fn from_config(config: MessageConfig) -> Message {
Message {
text: format!("{} {}", config.first_half, config.second_half),
}
}
}

macro_rules! derive_configurable_serializer {
( $t:ident, $c:ident ) => {
impl<'de> Deserialize<'de> for $t {
fn deserialize<D>(deserializer: D) -> Result<$t, D::Error>
where
D: Deserializer<'de>,
{
$c::deserialize(deserializer).map(|config| $t::from_config(config))
}
}
};
}

derive_configurable_serializer!(Message, MessageConfig);

fn main() -> Result<(), Error> {
let data = r#"{ "first_half": "John", "second_half": "Doe" }"#;

let p: Message = serde_json::from_str(data)?;

println!("Hello, {}!", p.text);

Ok(())
}





share|improve this answer


























  • Nice idea with a macro, and thanks for showing how to do it! I don't understand what's up with the conflicting implementations, though. There is no type that implements both Configurable and Deserialize from some other source.

    – Anders
    Jan 2 at 22:42






  • 1





    @Anders honestly - I don't know. I tried finding a solution with the trait, got various error messages. Maybe someone with a deeper understanding of Rust traits can explain how to do it / why it isn't possible.

    – Ramon Snir
    Jan 2 at 22:44
















1














I am not sure if there's a way to define such a broad trait without causing conflicting implementations. What you could do is use a macro to avoid repetition:



use serde::{Deserialize, Deserializer};
use serde_json;

use serde_json::Error;

#[macro_use]
extern crate serde_derive;

struct Message {
text: String,
}

#[derive(Deserialize)]
struct MessageConfig {
first_half: String,
second_half: String,
}

impl Message {
fn from_config(config: MessageConfig) -> Message {
Message {
text: format!("{} {}", config.first_half, config.second_half),
}
}
}

macro_rules! derive_configurable_serializer {
( $t:ident, $c:ident ) => {
impl<'de> Deserialize<'de> for $t {
fn deserialize<D>(deserializer: D) -> Result<$t, D::Error>
where
D: Deserializer<'de>,
{
$c::deserialize(deserializer).map(|config| $t::from_config(config))
}
}
};
}

derive_configurable_serializer!(Message, MessageConfig);

fn main() -> Result<(), Error> {
let data = r#"{ "first_half": "John", "second_half": "Doe" }"#;

let p: Message = serde_json::from_str(data)?;

println!("Hello, {}!", p.text);

Ok(())
}





share|improve this answer


























  • Nice idea with a macro, and thanks for showing how to do it! I don't understand what's up with the conflicting implementations, though. There is no type that implements both Configurable and Deserialize from some other source.

    – Anders
    Jan 2 at 22:42






  • 1





    @Anders honestly - I don't know. I tried finding a solution with the trait, got various error messages. Maybe someone with a deeper understanding of Rust traits can explain how to do it / why it isn't possible.

    – Ramon Snir
    Jan 2 at 22:44














1












1








1







I am not sure if there's a way to define such a broad trait without causing conflicting implementations. What you could do is use a macro to avoid repetition:



use serde::{Deserialize, Deserializer};
use serde_json;

use serde_json::Error;

#[macro_use]
extern crate serde_derive;

struct Message {
text: String,
}

#[derive(Deserialize)]
struct MessageConfig {
first_half: String,
second_half: String,
}

impl Message {
fn from_config(config: MessageConfig) -> Message {
Message {
text: format!("{} {}", config.first_half, config.second_half),
}
}
}

macro_rules! derive_configurable_serializer {
( $t:ident, $c:ident ) => {
impl<'de> Deserialize<'de> for $t {
fn deserialize<D>(deserializer: D) -> Result<$t, D::Error>
where
D: Deserializer<'de>,
{
$c::deserialize(deserializer).map(|config| $t::from_config(config))
}
}
};
}

derive_configurable_serializer!(Message, MessageConfig);

fn main() -> Result<(), Error> {
let data = r#"{ "first_half": "John", "second_half": "Doe" }"#;

let p: Message = serde_json::from_str(data)?;

println!("Hello, {}!", p.text);

Ok(())
}





share|improve this answer















I am not sure if there's a way to define such a broad trait without causing conflicting implementations. What you could do is use a macro to avoid repetition:



use serde::{Deserialize, Deserializer};
use serde_json;

use serde_json::Error;

#[macro_use]
extern crate serde_derive;

struct Message {
text: String,
}

#[derive(Deserialize)]
struct MessageConfig {
first_half: String,
second_half: String,
}

impl Message {
fn from_config(config: MessageConfig) -> Message {
Message {
text: format!("{} {}", config.first_half, config.second_half),
}
}
}

macro_rules! derive_configurable_serializer {
( $t:ident, $c:ident ) => {
impl<'de> Deserialize<'de> for $t {
fn deserialize<D>(deserializer: D) -> Result<$t, D::Error>
where
D: Deserializer<'de>,
{
$c::deserialize(deserializer).map(|config| $t::from_config(config))
}
}
};
}

derive_configurable_serializer!(Message, MessageConfig);

fn main() -> Result<(), Error> {
let data = r#"{ "first_half": "John", "second_half": "Doe" }"#;

let p: Message = serde_json::from_str(data)?;

println!("Hello, {}!", p.text);

Ok(())
}






share|improve this answer














share|improve this answer



share|improve this answer








edited Jan 2 at 22:54









Shepmaster

160k16330473




160k16330473










answered Jan 2 at 22:20









Ramon SnirRamon Snir

6,24033356




6,24033356













  • Nice idea with a macro, and thanks for showing how to do it! I don't understand what's up with the conflicting implementations, though. There is no type that implements both Configurable and Deserialize from some other source.

    – Anders
    Jan 2 at 22:42






  • 1





    @Anders honestly - I don't know. I tried finding a solution with the trait, got various error messages. Maybe someone with a deeper understanding of Rust traits can explain how to do it / why it isn't possible.

    – Ramon Snir
    Jan 2 at 22:44



















  • Nice idea with a macro, and thanks for showing how to do it! I don't understand what's up with the conflicting implementations, though. There is no type that implements both Configurable and Deserialize from some other source.

    – Anders
    Jan 2 at 22:42






  • 1





    @Anders honestly - I don't know. I tried finding a solution with the trait, got various error messages. Maybe someone with a deeper understanding of Rust traits can explain how to do it / why it isn't possible.

    – Ramon Snir
    Jan 2 at 22:44

















Nice idea with a macro, and thanks for showing how to do it! I don't understand what's up with the conflicting implementations, though. There is no type that implements both Configurable and Deserialize from some other source.

– Anders
Jan 2 at 22:42





Nice idea with a macro, and thanks for showing how to do it! I don't understand what's up with the conflicting implementations, though. There is no type that implements both Configurable and Deserialize from some other source.

– Anders
Jan 2 at 22:42




1




1





@Anders honestly - I don't know. I tried finding a solution with the trait, got various error messages. Maybe someone with a deeper understanding of Rust traits can explain how to do it / why it isn't possible.

– Ramon Snir
Jan 2 at 22:44





@Anders honestly - I don't know. I tried finding a solution with the trait, got various error messages. Maybe someone with a deeper understanding of Rust traits can explain how to do it / why it isn't possible.

– Ramon Snir
Jan 2 at 22:44




















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54013125%2fhow-can-i-mass-implement-deserialize-for-all-types-that-implement-a-specific-tra%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

Does disintegrating a polymorphed enemy still kill it after the 2018 errata?

A Topological Invariant for $pi_3(U(n))$