How do I deserialize into trait, not a concrete type?
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
|
show 1 more comment
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
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 implementsInto
for all otherContract
implementations?
– w.brian
Feb 22 '17 at 21:45
|
show 1 more comment
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
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
serialization rust serde cbor
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 implementsInto
for all otherContract
implementations?
– w.brian
Feb 22 '17 at 21:45
|
show 1 more comment
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 implementsInto
for all otherContract
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
|
show 1 more comment
2 Answers
2
active
oldest
votes
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)
}
}
}
}
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
add a comment |
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,
}
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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)
}
}
}
}
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
add a comment |
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)
}
}
}
}
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
add a comment |
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)
}
}
}
}
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)
}
}
}
}
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
add a comment |
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
add a comment |
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,
}
add a comment |
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,
}
add a comment |
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,
}
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,
}
edited Jan 1 at 17:29
answered Jan 1 at 17:19
ShepmasterShepmaster
157k14318460
157k14318460
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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 otherContract
implementations?– w.brian
Feb 22 '17 at 21:45