How do I deserialize into trait, not a concrete type?












9















I'm trying to do struct serialization, in which the bytes would eventually be sent down a pipe, reconstructed and methods be called on them.



I created a trait these structs would implement as appropriate and I'm using serde and serde-cbor for serialization:



extern crate serde_cbor;
#[macro_use]
extern crate serde_derive;
extern crate serde;

use serde_cbor::ser::*;
use serde_cbor::de::*;

trait Contract {
fn do_something(&self);
}

#[derive(Debug, Serialize, Deserialize)]
struct Foo {
x: u32,
y: u32,
}

#[derive(Debug, Serialize, Deserialize)]
struct Bar {
data: Vec<Foo>,
}

#[derive(Debug, Serialize, Deserialize)]
struct Baz {
data: Vec<Foo>,
tag: String,
}

impl Contract for Bar {
fn do_something(&self) {
println!("I'm a Bar and this is my data {:?}", self.data);
}
}

impl Contract for Baz {
fn do_something(&self) {
println!("I'm Baz {} and this is my data {:?}", self.tag, self.data);
}
}

fn main() {
let data = Bar { data: vec![Foo { x: 1, y: 2 }, Foo { x: 3, y: 4 }, Foo { x: 7, y: 8 }] };
data.do_something();

let value = to_vec(&data).unwrap();
let res: Result<Contract, _> = from_reader(&value[..]);
let res = res.unwrap();
println!("{:?}", res);
res.do_something();
}


When I try to reconstruct the bytes using the trait as the type (given that I wouldn't know which underlying object is being sent), the compiler complains that the trait does not implement the Sized trait:




error[E0277]: the trait bound `Contract: std::marker::Sized` is not satisfied
--> src/main.rs:52:15
|
52 | let res: Result<Contract, _> = from_reader(&value[..]);
| ^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Sized` is not implemented for `Contract`
|
= note: `Contract` does not have a constant size known at compile-time
= note: required by `std::result::Result`



I guess it makes sense since the compiler doesn't know how big the struct is supposed to be and doesn't know how to line up the bytes for it. If I change the line where I deserialize the object to specify the actual struct type, it works:



let res: Result<Bar, _> = from_reader(&value[..]);


Is there a better pattern to achieve this serialization + polymorphism behavior?










share|improve this question




















  • 2





    I... don't think you can do that. You can't recover the struct unless you know its concrete type, and you can't call methods on it unless you have a pointer to its vtable -- which you can't figure out unless you have access to its concrete type. Can you serialize a vtable?

    – trentcl
    Feb 22 '17 at 14:00











  • Seems to be the case, but I was hoping someone would point out something I'm missing. I have a non-idiomatic solution for this but adds coupling to the code... so I'm looking for something better.

    – Dash83
    Feb 22 '17 at 14:09






  • 3





    Are you sure you want polymorphism and not simply an enum? Do you need your code to work with user supplied types?

    – oli_obk
    Feb 22 '17 at 16:12











  • I.... you know... but....no. You are correct, @ker. The "non-idiomatic" solution I had becomes far more natural when using enums with data associated to them. I keep trying to use enums as standard C enums, but I can change my design to use enums. If you post your suggestions as an answer, I'll accept it.

    – Dash83
    Feb 22 '17 at 17:42








  • 1





    What about deserializing into an implementation that also implements Into for all other Contract implementations?

    – w.brian
    Feb 22 '17 at 21:45
















9















I'm trying to do struct serialization, in which the bytes would eventually be sent down a pipe, reconstructed and methods be called on them.



I created a trait these structs would implement as appropriate and I'm using serde and serde-cbor for serialization:



extern crate serde_cbor;
#[macro_use]
extern crate serde_derive;
extern crate serde;

use serde_cbor::ser::*;
use serde_cbor::de::*;

trait Contract {
fn do_something(&self);
}

#[derive(Debug, Serialize, Deserialize)]
struct Foo {
x: u32,
y: u32,
}

#[derive(Debug, Serialize, Deserialize)]
struct Bar {
data: Vec<Foo>,
}

#[derive(Debug, Serialize, Deserialize)]
struct Baz {
data: Vec<Foo>,
tag: String,
}

impl Contract for Bar {
fn do_something(&self) {
println!("I'm a Bar and this is my data {:?}", self.data);
}
}

impl Contract for Baz {
fn do_something(&self) {
println!("I'm Baz {} and this is my data {:?}", self.tag, self.data);
}
}

fn main() {
let data = Bar { data: vec![Foo { x: 1, y: 2 }, Foo { x: 3, y: 4 }, Foo { x: 7, y: 8 }] };
data.do_something();

let value = to_vec(&data).unwrap();
let res: Result<Contract, _> = from_reader(&value[..]);
let res = res.unwrap();
println!("{:?}", res);
res.do_something();
}


When I try to reconstruct the bytes using the trait as the type (given that I wouldn't know which underlying object is being sent), the compiler complains that the trait does not implement the Sized trait:




error[E0277]: the trait bound `Contract: std::marker::Sized` is not satisfied
--> src/main.rs:52:15
|
52 | let res: Result<Contract, _> = from_reader(&value[..]);
| ^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Sized` is not implemented for `Contract`
|
= note: `Contract` does not have a constant size known at compile-time
= note: required by `std::result::Result`



I guess it makes sense since the compiler doesn't know how big the struct is supposed to be and doesn't know how to line up the bytes for it. If I change the line where I deserialize the object to specify the actual struct type, it works:



let res: Result<Bar, _> = from_reader(&value[..]);


Is there a better pattern to achieve this serialization + polymorphism behavior?










share|improve this question




















  • 2





    I... don't think you can do that. You can't recover the struct unless you know its concrete type, and you can't call methods on it unless you have a pointer to its vtable -- which you can't figure out unless you have access to its concrete type. Can you serialize a vtable?

    – trentcl
    Feb 22 '17 at 14:00











  • Seems to be the case, but I was hoping someone would point out something I'm missing. I have a non-idiomatic solution for this but adds coupling to the code... so I'm looking for something better.

    – Dash83
    Feb 22 '17 at 14:09






  • 3





    Are you sure you want polymorphism and not simply an enum? Do you need your code to work with user supplied types?

    – oli_obk
    Feb 22 '17 at 16:12











  • I.... you know... but....no. You are correct, @ker. The "non-idiomatic" solution I had becomes far more natural when using enums with data associated to them. I keep trying to use enums as standard C enums, but I can change my design to use enums. If you post your suggestions as an answer, I'll accept it.

    – Dash83
    Feb 22 '17 at 17:42








  • 1





    What about deserializing into an implementation that also implements Into for all other Contract implementations?

    – w.brian
    Feb 22 '17 at 21:45














9












9








9


1






I'm trying to do struct serialization, in which the bytes would eventually be sent down a pipe, reconstructed and methods be called on them.



I created a trait these structs would implement as appropriate and I'm using serde and serde-cbor for serialization:



extern crate serde_cbor;
#[macro_use]
extern crate serde_derive;
extern crate serde;

use serde_cbor::ser::*;
use serde_cbor::de::*;

trait Contract {
fn do_something(&self);
}

#[derive(Debug, Serialize, Deserialize)]
struct Foo {
x: u32,
y: u32,
}

#[derive(Debug, Serialize, Deserialize)]
struct Bar {
data: Vec<Foo>,
}

#[derive(Debug, Serialize, Deserialize)]
struct Baz {
data: Vec<Foo>,
tag: String,
}

impl Contract for Bar {
fn do_something(&self) {
println!("I'm a Bar and this is my data {:?}", self.data);
}
}

impl Contract for Baz {
fn do_something(&self) {
println!("I'm Baz {} and this is my data {:?}", self.tag, self.data);
}
}

fn main() {
let data = Bar { data: vec![Foo { x: 1, y: 2 }, Foo { x: 3, y: 4 }, Foo { x: 7, y: 8 }] };
data.do_something();

let value = to_vec(&data).unwrap();
let res: Result<Contract, _> = from_reader(&value[..]);
let res = res.unwrap();
println!("{:?}", res);
res.do_something();
}


When I try to reconstruct the bytes using the trait as the type (given that I wouldn't know which underlying object is being sent), the compiler complains that the trait does not implement the Sized trait:




error[E0277]: the trait bound `Contract: std::marker::Sized` is not satisfied
--> src/main.rs:52:15
|
52 | let res: Result<Contract, _> = from_reader(&value[..]);
| ^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Sized` is not implemented for `Contract`
|
= note: `Contract` does not have a constant size known at compile-time
= note: required by `std::result::Result`



I guess it makes sense since the compiler doesn't know how big the struct is supposed to be and doesn't know how to line up the bytes for it. If I change the line where I deserialize the object to specify the actual struct type, it works:



let res: Result<Bar, _> = from_reader(&value[..]);


Is there a better pattern to achieve this serialization + polymorphism behavior?










share|improve this question
















I'm trying to do struct serialization, in which the bytes would eventually be sent down a pipe, reconstructed and methods be called on them.



I created a trait these structs would implement as appropriate and I'm using serde and serde-cbor for serialization:



extern crate serde_cbor;
#[macro_use]
extern crate serde_derive;
extern crate serde;

use serde_cbor::ser::*;
use serde_cbor::de::*;

trait Contract {
fn do_something(&self);
}

#[derive(Debug, Serialize, Deserialize)]
struct Foo {
x: u32,
y: u32,
}

#[derive(Debug, Serialize, Deserialize)]
struct Bar {
data: Vec<Foo>,
}

#[derive(Debug, Serialize, Deserialize)]
struct Baz {
data: Vec<Foo>,
tag: String,
}

impl Contract for Bar {
fn do_something(&self) {
println!("I'm a Bar and this is my data {:?}", self.data);
}
}

impl Contract for Baz {
fn do_something(&self) {
println!("I'm Baz {} and this is my data {:?}", self.tag, self.data);
}
}

fn main() {
let data = Bar { data: vec![Foo { x: 1, y: 2 }, Foo { x: 3, y: 4 }, Foo { x: 7, y: 8 }] };
data.do_something();

let value = to_vec(&data).unwrap();
let res: Result<Contract, _> = from_reader(&value[..]);
let res = res.unwrap();
println!("{:?}", res);
res.do_something();
}


When I try to reconstruct the bytes using the trait as the type (given that I wouldn't know which underlying object is being sent), the compiler complains that the trait does not implement the Sized trait:




error[E0277]: the trait bound `Contract: std::marker::Sized` is not satisfied
--> src/main.rs:52:15
|
52 | let res: Result<Contract, _> = from_reader(&value[..]);
| ^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Sized` is not implemented for `Contract`
|
= note: `Contract` does not have a constant size known at compile-time
= note: required by `std::result::Result`



I guess it makes sense since the compiler doesn't know how big the struct is supposed to be and doesn't know how to line up the bytes for it. If I change the line where I deserialize the object to specify the actual struct type, it works:



let res: Result<Bar, _> = from_reader(&value[..]);


Is there a better pattern to achieve this serialization + polymorphism behavior?







serialization rust serde cbor






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Feb 22 '17 at 15:55









Shepmaster

157k14318460




157k14318460










asked Feb 22 '17 at 13:32









Dash83Dash83

331315




331315








  • 2





    I... don't think you can do that. You can't recover the struct unless you know its concrete type, and you can't call methods on it unless you have a pointer to its vtable -- which you can't figure out unless you have access to its concrete type. Can you serialize a vtable?

    – trentcl
    Feb 22 '17 at 14:00











  • Seems to be the case, but I was hoping someone would point out something I'm missing. I have a non-idiomatic solution for this but adds coupling to the code... so I'm looking for something better.

    – Dash83
    Feb 22 '17 at 14:09






  • 3





    Are you sure you want polymorphism and not simply an enum? Do you need your code to work with user supplied types?

    – oli_obk
    Feb 22 '17 at 16:12











  • I.... you know... but....no. You are correct, @ker. The "non-idiomatic" solution I had becomes far more natural when using enums with data associated to them. I keep trying to use enums as standard C enums, but I can change my design to use enums. If you post your suggestions as an answer, I'll accept it.

    – Dash83
    Feb 22 '17 at 17:42








  • 1





    What about deserializing into an implementation that also implements Into for all other Contract implementations?

    – w.brian
    Feb 22 '17 at 21:45














  • 2





    I... don't think you can do that. You can't recover the struct unless you know its concrete type, and you can't call methods on it unless you have a pointer to its vtable -- which you can't figure out unless you have access to its concrete type. Can you serialize a vtable?

    – trentcl
    Feb 22 '17 at 14:00











  • Seems to be the case, but I was hoping someone would point out something I'm missing. I have a non-idiomatic solution for this but adds coupling to the code... so I'm looking for something better.

    – Dash83
    Feb 22 '17 at 14:09






  • 3





    Are you sure you want polymorphism and not simply an enum? Do you need your code to work with user supplied types?

    – oli_obk
    Feb 22 '17 at 16:12











  • I.... you know... but....no. You are correct, @ker. The "non-idiomatic" solution I had becomes far more natural when using enums with data associated to them. I keep trying to use enums as standard C enums, but I can change my design to use enums. If you post your suggestions as an answer, I'll accept it.

    – Dash83
    Feb 22 '17 at 17:42








  • 1





    What about deserializing into an implementation that also implements Into for all other Contract implementations?

    – w.brian
    Feb 22 '17 at 21:45








2




2





I... don't think you can do that. You can't recover the struct unless you know its concrete type, and you can't call methods on it unless you have a pointer to its vtable -- which you can't figure out unless you have access to its concrete type. Can you serialize a vtable?

– trentcl
Feb 22 '17 at 14:00





I... don't think you can do that. You can't recover the struct unless you know its concrete type, and you can't call methods on it unless you have a pointer to its vtable -- which you can't figure out unless you have access to its concrete type. Can you serialize a vtable?

– trentcl
Feb 22 '17 at 14:00













Seems to be the case, but I was hoping someone would point out something I'm missing. I have a non-idiomatic solution for this but adds coupling to the code... so I'm looking for something better.

– Dash83
Feb 22 '17 at 14:09





Seems to be the case, but I was hoping someone would point out something I'm missing. I have a non-idiomatic solution for this but adds coupling to the code... so I'm looking for something better.

– Dash83
Feb 22 '17 at 14:09




3




3





Are you sure you want polymorphism and not simply an enum? Do you need your code to work with user supplied types?

– oli_obk
Feb 22 '17 at 16:12





Are you sure you want polymorphism and not simply an enum? Do you need your code to work with user supplied types?

– oli_obk
Feb 22 '17 at 16:12













I.... you know... but....no. You are correct, @ker. The "non-idiomatic" solution I had becomes far more natural when using enums with data associated to them. I keep trying to use enums as standard C enums, but I can change my design to use enums. If you post your suggestions as an answer, I'll accept it.

– Dash83
Feb 22 '17 at 17:42







I.... you know... but....no. You are correct, @ker. The "non-idiomatic" solution I had becomes far more natural when using enums with data associated to them. I keep trying to use enums as standard C enums, but I can change my design to use enums. If you post your suggestions as an answer, I'll accept it.

– Dash83
Feb 22 '17 at 17:42






1




1





What about deserializing into an implementation that also implements Into for all other Contract implementations?

– w.brian
Feb 22 '17 at 21:45





What about deserializing into an implementation that also implements Into for all other Contract implementations?

– w.brian
Feb 22 '17 at 21:45












2 Answers
2






active

oldest

votes


















7














It looks like you fell into the same trap that I fell into when I moved from C++ to Rust. Trying to use polymorphism to model a fixed set of variants of a type. Rust's enums (similar to Haskell's enums, and equivalent to Ada's variant record types) are different from classical enums in other languages, because the enum variants can have fields of their own.



I suggest you change your code to



#[derive(Debug, Serialize, Deserialize)]
enum Contract {
Bar { data: Vec<Foo> },
Baz { data: Vec<Foo>, tag: String },
}

#[derive(Debug, Serialize, Deserialize)]
struct Foo {
x: u32,
y: u32,
}

impl Contract {
fn do_something(&self) {
match *self {
Contract::Bar { ref data } => println!("I'm a Bar and this is my data {:?}", data),
Contract::Baz { ref data, ref tag } => {
println!("I'm Baz {} and this is my data {:?}", tag, data)
}
}
}
}





share|improve this answer


























  • Used the structures Bar and Baz as the associated data for the enum, but went pretty much with this design otherwise. Thanks!

    – Dash83
    Feb 24 '17 at 12:31











  • What about if there is arbitrary set of type from a trait with type parameters?

    – Shisoft
    Nov 2 '17 at 14:16











  • @Shisoft not sure I understand. Why don't you open a new question?

    – oli_obk
    Nov 3 '17 at 15:08



















3














Adding on to oli_obk's answer, you can use Serde's enum representation to distinguish between the types.



Here, I use the internally-tagged representation to deserialize these two similar objects into the appropriate variant:



{
"driver": "file",
"path": "/var/log/foo"
}


{
"driver": "http",
"port": 8080,
"endpoint": "/api/bar"
}




use serde; // 1.0.82
use serde_derive::*; // 1.0.82
use serde_json; // 1.0.33

#[derive(Debug, Deserialize, PartialEq)]
#[serde(tag = "driver")]
enum Driver {
#[serde(rename = "file")]
File { path: String },
#[serde(rename = "http")]
Http { port: u16, endpoint: String }
}

fn main() {
let f = r#"
{
"driver": "file",
"path": "/var/log/foo"
}
"#;

let h = r#"
{
"driver": "http",
"port": 8080,
"endpoint": "/api/bar"
}
"#;

let f: Driver = serde_json::from_str(f).unwrap();
assert_eq!(f, Driver::File { path: "/var/log/foo".into() });

let h: Driver = serde_json::from_str(h).unwrap();
assert_eq!(h, Driver::Http { port: 8080, endpoint: "/api/bar".into() });
}


You don't have to squash it all into one enum, you can create separate types as well:



#[derive(Debug, Deserialize, PartialEq)]
#[serde(tag = "driver")]
enum Driver {
#[serde(rename = "file")]
File(File),
#[serde(rename = "http")]
Http(Http),
}

#[derive(Debug, Deserialize, PartialEq)]
struct File {
path: String,
}

#[derive(Debug, Deserialize, PartialEq)]
struct Http {
port: u16,
endpoint: String,
}





share|improve this answer

























    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%2f42392935%2fhow-do-i-deserialize-into-trait-not-a-concrete-type%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    7














    It looks like you fell into the same trap that I fell into when I moved from C++ to Rust. Trying to use polymorphism to model a fixed set of variants of a type. Rust's enums (similar to Haskell's enums, and equivalent to Ada's variant record types) are different from classical enums in other languages, because the enum variants can have fields of their own.



    I suggest you change your code to



    #[derive(Debug, Serialize, Deserialize)]
    enum Contract {
    Bar { data: Vec<Foo> },
    Baz { data: Vec<Foo>, tag: String },
    }

    #[derive(Debug, Serialize, Deserialize)]
    struct Foo {
    x: u32,
    y: u32,
    }

    impl Contract {
    fn do_something(&self) {
    match *self {
    Contract::Bar { ref data } => println!("I'm a Bar and this is my data {:?}", data),
    Contract::Baz { ref data, ref tag } => {
    println!("I'm Baz {} and this is my data {:?}", tag, data)
    }
    }
    }
    }





    share|improve this answer


























    • Used the structures Bar and Baz as the associated data for the enum, but went pretty much with this design otherwise. Thanks!

      – Dash83
      Feb 24 '17 at 12:31











    • What about if there is arbitrary set of type from a trait with type parameters?

      – Shisoft
      Nov 2 '17 at 14:16











    • @Shisoft not sure I understand. Why don't you open a new question?

      – oli_obk
      Nov 3 '17 at 15:08
















    7














    It looks like you fell into the same trap that I fell into when I moved from C++ to Rust. Trying to use polymorphism to model a fixed set of variants of a type. Rust's enums (similar to Haskell's enums, and equivalent to Ada's variant record types) are different from classical enums in other languages, because the enum variants can have fields of their own.



    I suggest you change your code to



    #[derive(Debug, Serialize, Deserialize)]
    enum Contract {
    Bar { data: Vec<Foo> },
    Baz { data: Vec<Foo>, tag: String },
    }

    #[derive(Debug, Serialize, Deserialize)]
    struct Foo {
    x: u32,
    y: u32,
    }

    impl Contract {
    fn do_something(&self) {
    match *self {
    Contract::Bar { ref data } => println!("I'm a Bar and this is my data {:?}", data),
    Contract::Baz { ref data, ref tag } => {
    println!("I'm Baz {} and this is my data {:?}", tag, data)
    }
    }
    }
    }





    share|improve this answer


























    • Used the structures Bar and Baz as the associated data for the enum, but went pretty much with this design otherwise. Thanks!

      – Dash83
      Feb 24 '17 at 12:31











    • What about if there is arbitrary set of type from a trait with type parameters?

      – Shisoft
      Nov 2 '17 at 14:16











    • @Shisoft not sure I understand. Why don't you open a new question?

      – oli_obk
      Nov 3 '17 at 15:08














    7












    7








    7







    It looks like you fell into the same trap that I fell into when I moved from C++ to Rust. Trying to use polymorphism to model a fixed set of variants of a type. Rust's enums (similar to Haskell's enums, and equivalent to Ada's variant record types) are different from classical enums in other languages, because the enum variants can have fields of their own.



    I suggest you change your code to



    #[derive(Debug, Serialize, Deserialize)]
    enum Contract {
    Bar { data: Vec<Foo> },
    Baz { data: Vec<Foo>, tag: String },
    }

    #[derive(Debug, Serialize, Deserialize)]
    struct Foo {
    x: u32,
    y: u32,
    }

    impl Contract {
    fn do_something(&self) {
    match *self {
    Contract::Bar { ref data } => println!("I'm a Bar and this is my data {:?}", data),
    Contract::Baz { ref data, ref tag } => {
    println!("I'm Baz {} and this is my data {:?}", tag, data)
    }
    }
    }
    }





    share|improve this answer















    It looks like you fell into the same trap that I fell into when I moved from C++ to Rust. Trying to use polymorphism to model a fixed set of variants of a type. Rust's enums (similar to Haskell's enums, and equivalent to Ada's variant record types) are different from classical enums in other languages, because the enum variants can have fields of their own.



    I suggest you change your code to



    #[derive(Debug, Serialize, Deserialize)]
    enum Contract {
    Bar { data: Vec<Foo> },
    Baz { data: Vec<Foo>, tag: String },
    }

    #[derive(Debug, Serialize, Deserialize)]
    struct Foo {
    x: u32,
    y: u32,
    }

    impl Contract {
    fn do_something(&self) {
    match *self {
    Contract::Bar { ref data } => println!("I'm a Bar and this is my data {:?}", data),
    Contract::Baz { ref data, ref tag } => {
    println!("I'm Baz {} and this is my data {:?}", tag, data)
    }
    }
    }
    }






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Feb 24 '17 at 11:47

























    answered Feb 24 '17 at 9:06









    oli_obkoli_obk

    16.7k14567




    16.7k14567













    • Used the structures Bar and Baz as the associated data for the enum, but went pretty much with this design otherwise. Thanks!

      – Dash83
      Feb 24 '17 at 12:31











    • What about if there is arbitrary set of type from a trait with type parameters?

      – Shisoft
      Nov 2 '17 at 14:16











    • @Shisoft not sure I understand. Why don't you open a new question?

      – oli_obk
      Nov 3 '17 at 15:08



















    • Used the structures Bar and Baz as the associated data for the enum, but went pretty much with this design otherwise. Thanks!

      – Dash83
      Feb 24 '17 at 12:31











    • What about if there is arbitrary set of type from a trait with type parameters?

      – Shisoft
      Nov 2 '17 at 14:16











    • @Shisoft not sure I understand. Why don't you open a new question?

      – oli_obk
      Nov 3 '17 at 15:08

















    Used the structures Bar and Baz as the associated data for the enum, but went pretty much with this design otherwise. Thanks!

    – Dash83
    Feb 24 '17 at 12:31





    Used the structures Bar and Baz as the associated data for the enum, but went pretty much with this design otherwise. Thanks!

    – Dash83
    Feb 24 '17 at 12:31













    What about if there is arbitrary set of type from a trait with type parameters?

    – Shisoft
    Nov 2 '17 at 14:16





    What about if there is arbitrary set of type from a trait with type parameters?

    – Shisoft
    Nov 2 '17 at 14:16













    @Shisoft not sure I understand. Why don't you open a new question?

    – oli_obk
    Nov 3 '17 at 15:08





    @Shisoft not sure I understand. Why don't you open a new question?

    – oli_obk
    Nov 3 '17 at 15:08













    3














    Adding on to oli_obk's answer, you can use Serde's enum representation to distinguish between the types.



    Here, I use the internally-tagged representation to deserialize these two similar objects into the appropriate variant:



    {
    "driver": "file",
    "path": "/var/log/foo"
    }


    {
    "driver": "http",
    "port": 8080,
    "endpoint": "/api/bar"
    }




    use serde; // 1.0.82
    use serde_derive::*; // 1.0.82
    use serde_json; // 1.0.33

    #[derive(Debug, Deserialize, PartialEq)]
    #[serde(tag = "driver")]
    enum Driver {
    #[serde(rename = "file")]
    File { path: String },
    #[serde(rename = "http")]
    Http { port: u16, endpoint: String }
    }

    fn main() {
    let f = r#"
    {
    "driver": "file",
    "path": "/var/log/foo"
    }
    "#;

    let h = r#"
    {
    "driver": "http",
    "port": 8080,
    "endpoint": "/api/bar"
    }
    "#;

    let f: Driver = serde_json::from_str(f).unwrap();
    assert_eq!(f, Driver::File { path: "/var/log/foo".into() });

    let h: Driver = serde_json::from_str(h).unwrap();
    assert_eq!(h, Driver::Http { port: 8080, endpoint: "/api/bar".into() });
    }


    You don't have to squash it all into one enum, you can create separate types as well:



    #[derive(Debug, Deserialize, PartialEq)]
    #[serde(tag = "driver")]
    enum Driver {
    #[serde(rename = "file")]
    File(File),
    #[serde(rename = "http")]
    Http(Http),
    }

    #[derive(Debug, Deserialize, PartialEq)]
    struct File {
    path: String,
    }

    #[derive(Debug, Deserialize, PartialEq)]
    struct Http {
    port: u16,
    endpoint: String,
    }





    share|improve this answer






























      3














      Adding on to oli_obk's answer, you can use Serde's enum representation to distinguish between the types.



      Here, I use the internally-tagged representation to deserialize these two similar objects into the appropriate variant:



      {
      "driver": "file",
      "path": "/var/log/foo"
      }


      {
      "driver": "http",
      "port": 8080,
      "endpoint": "/api/bar"
      }




      use serde; // 1.0.82
      use serde_derive::*; // 1.0.82
      use serde_json; // 1.0.33

      #[derive(Debug, Deserialize, PartialEq)]
      #[serde(tag = "driver")]
      enum Driver {
      #[serde(rename = "file")]
      File { path: String },
      #[serde(rename = "http")]
      Http { port: u16, endpoint: String }
      }

      fn main() {
      let f = r#"
      {
      "driver": "file",
      "path": "/var/log/foo"
      }
      "#;

      let h = r#"
      {
      "driver": "http",
      "port": 8080,
      "endpoint": "/api/bar"
      }
      "#;

      let f: Driver = serde_json::from_str(f).unwrap();
      assert_eq!(f, Driver::File { path: "/var/log/foo".into() });

      let h: Driver = serde_json::from_str(h).unwrap();
      assert_eq!(h, Driver::Http { port: 8080, endpoint: "/api/bar".into() });
      }


      You don't have to squash it all into one enum, you can create separate types as well:



      #[derive(Debug, Deserialize, PartialEq)]
      #[serde(tag = "driver")]
      enum Driver {
      #[serde(rename = "file")]
      File(File),
      #[serde(rename = "http")]
      Http(Http),
      }

      #[derive(Debug, Deserialize, PartialEq)]
      struct File {
      path: String,
      }

      #[derive(Debug, Deserialize, PartialEq)]
      struct Http {
      port: u16,
      endpoint: String,
      }





      share|improve this answer




























        3












        3








        3







        Adding on to oli_obk's answer, you can use Serde's enum representation to distinguish between the types.



        Here, I use the internally-tagged representation to deserialize these two similar objects into the appropriate variant:



        {
        "driver": "file",
        "path": "/var/log/foo"
        }


        {
        "driver": "http",
        "port": 8080,
        "endpoint": "/api/bar"
        }




        use serde; // 1.0.82
        use serde_derive::*; // 1.0.82
        use serde_json; // 1.0.33

        #[derive(Debug, Deserialize, PartialEq)]
        #[serde(tag = "driver")]
        enum Driver {
        #[serde(rename = "file")]
        File { path: String },
        #[serde(rename = "http")]
        Http { port: u16, endpoint: String }
        }

        fn main() {
        let f = r#"
        {
        "driver": "file",
        "path": "/var/log/foo"
        }
        "#;

        let h = r#"
        {
        "driver": "http",
        "port": 8080,
        "endpoint": "/api/bar"
        }
        "#;

        let f: Driver = serde_json::from_str(f).unwrap();
        assert_eq!(f, Driver::File { path: "/var/log/foo".into() });

        let h: Driver = serde_json::from_str(h).unwrap();
        assert_eq!(h, Driver::Http { port: 8080, endpoint: "/api/bar".into() });
        }


        You don't have to squash it all into one enum, you can create separate types as well:



        #[derive(Debug, Deserialize, PartialEq)]
        #[serde(tag = "driver")]
        enum Driver {
        #[serde(rename = "file")]
        File(File),
        #[serde(rename = "http")]
        Http(Http),
        }

        #[derive(Debug, Deserialize, PartialEq)]
        struct File {
        path: String,
        }

        #[derive(Debug, Deserialize, PartialEq)]
        struct Http {
        port: u16,
        endpoint: String,
        }





        share|improve this answer















        Adding on to oli_obk's answer, you can use Serde's enum representation to distinguish between the types.



        Here, I use the internally-tagged representation to deserialize these two similar objects into the appropriate variant:



        {
        "driver": "file",
        "path": "/var/log/foo"
        }


        {
        "driver": "http",
        "port": 8080,
        "endpoint": "/api/bar"
        }




        use serde; // 1.0.82
        use serde_derive::*; // 1.0.82
        use serde_json; // 1.0.33

        #[derive(Debug, Deserialize, PartialEq)]
        #[serde(tag = "driver")]
        enum Driver {
        #[serde(rename = "file")]
        File { path: String },
        #[serde(rename = "http")]
        Http { port: u16, endpoint: String }
        }

        fn main() {
        let f = r#"
        {
        "driver": "file",
        "path": "/var/log/foo"
        }
        "#;

        let h = r#"
        {
        "driver": "http",
        "port": 8080,
        "endpoint": "/api/bar"
        }
        "#;

        let f: Driver = serde_json::from_str(f).unwrap();
        assert_eq!(f, Driver::File { path: "/var/log/foo".into() });

        let h: Driver = serde_json::from_str(h).unwrap();
        assert_eq!(h, Driver::Http { port: 8080, endpoint: "/api/bar".into() });
        }


        You don't have to squash it all into one enum, you can create separate types as well:



        #[derive(Debug, Deserialize, PartialEq)]
        #[serde(tag = "driver")]
        enum Driver {
        #[serde(rename = "file")]
        File(File),
        #[serde(rename = "http")]
        Http(Http),
        }

        #[derive(Debug, Deserialize, PartialEq)]
        struct File {
        path: String,
        }

        #[derive(Debug, Deserialize, PartialEq)]
        struct Http {
        port: u16,
        endpoint: String,
        }






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Jan 1 at 17:29

























        answered Jan 1 at 17:19









        ShepmasterShepmaster

        157k14318460




        157k14318460






























            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%2f42392935%2fhow-do-i-deserialize-into-trait-not-a-concrete-type%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

            MongoDB - Not Authorized To Execute Command

            in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith

            Npm cannot find a required file even through it is in the searched directory