I have a similar use-case to the one described here, but it's slightly different in that my solution can't replace the generic method with a non-generic method. Here's the code that I have (Rust Playground):
use serde::{de::DeserializeOwned, Serialize};
use serde_json;
trait Serializer {
fn serialize_data<V>(&self, data: &V) -> Result<String, String> where V: Serialize;
fn deserialize_data<V>(&self, ser_data: &str) -> Option<V> where V: DeserializeOwned;
}
struct JsonSerializer {
x: i32 // some member I need to store
}
impl JsonSerializer {
fn new() -> JsonSerializer {
JsonSerializer { x: 1 }
}
}
impl Serializer for JsonSerializer {
fn serialize_data<V>(&self, data: &V) -> Result<String, String> where V: Serialize {
match serde_json::to_string(data) {
Ok(ser_data) => Ok(ser_data),
Err(err) => Err(err.to_string())
}
}
fn deserialize_data<V>(&self, ser_data: &str) -> Option<V> where V: DeserializeOwned {
match serde_json::from_str(ser_data).unwrap() {
Ok(val) => Some(val),
Err(_) => None
}
}
}
// I may want to have more serializer objects like
// YamlSerizlier, BincodeSerializer and so on...
// ...
struct MyMainObject {
serializer: Box<Serializer>
}
impl MyMainObject {
fn new() -> MyMainObject {
MyMainObject { serializer: Box::new(JsonSerializer::new()) }
}
fn do_something(&self) {
println!("{}", self.serializer.serialize_data(&1));
println!("{}", self.serializer.serialize_data(&String::from("MY STRING")));
}
}
fn main() {
let my_main_object = MyMainObject::new();
my_main_object.do_something();
}
As described in the previous question, when compiling this code I get an error the trait `Serializer` cannot be made into an object
because it has generic methods:
Compiling playground v0.0.1 (/playground)
error[E0038]: the trait `Serializer` cannot be made into an object
--> src/main.rs:42:5
|
42 | serializer: Box<Serializer>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Serializer` cannot be made into an object
|
= note: method `serialize_data` has generic type parameters
= note: method `deserialize_data` has generic type parameters
But in my case I want these methods to stay generic so I can serialize/deserialize any type of data.
So my question is how to keep the dynamic dispatch pattern and still make it work, meaning I want to a Serializer
trait member in MyMainObject
that I can initialize with any type of serializer object (Json, Yaml, etc.), and then call serializer.serialize_data()
or serializer.deserialize_data()
inside of MyMainObject
.
If this is not possible, what is the best alternative you can suggest?
EDIT:
I need a solution that would work for different kind of serializers, at list those ones: