Open Altair-Bueno opened 8 months ago
That sounds like a great idea. I think the best thing would be to put them behind a Cargo build feature like "serde".
The only problem is that the internals of those structs contain a lot of FFI components which may not serialize nicely. But I was rethinking how I implemented all of the options and figure it would be better to make them completely "Rusty" and then create the FFI only when needed. That would also be a good first step as we slowly move the library to 100% Rust.
Yes indeed, se/de should be gated behind a feature flag.
My current workaround looks as it follows (only for deserialization), just in case someone has the same needs as I do and stumbles on this issue.
#[derive(Debug, Default)]
pub struct MqttConfig {
pub create_options: CreateOptions,
pub connections: Vec<ConnectOptions>,
pub buffer_size: Option<usize>,
}
#[derive(Debug, Default, serde::Deserialize)]
pub struct RawMqttConfig {
create_options: RawCreateOptions,
connections: Vec<RawConnectOptions>,
buffer_size: Option<usize>,
}
#[derive(Debug, Default, serde::Deserialize)]
pub struct RawCreateOptions {
#[serde(default)]
version: Option<u32>,
#[serde(default)]
client_id: Option<String>,
#[serde(default)]
persistence: Option<PathBuf>,
#[serde(default)]
max_buffered_messages: Option<i32>,
#[serde(default)]
send_while_disconnected: Option<bool>,
#[serde(default)]
allow_disconnected_send_at_anytime: Option<bool>,
#[serde(default)]
delete_oldest_messages: Option<bool>,
#[serde(default)]
restore_messages: Option<bool>,
#[serde(default)]
persist_qos0: Option<bool>,
}
#[derive(Debug, Default, serde::Deserialize)]
pub struct RawConnectOptions {
server_uris: Vec<String>,
}
impl<'de> Deserialize<'de> for MqttConfig {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let RawMqttConfig {
create_options: raw_create_options,
connections: raw_connections,
buffer_size,
} = RawMqttConfig::deserialize(deserializer)?;
let mut create_options = CreateOptionsBuilder::default();
if let Some(version) = raw_create_options.version {
create_options = create_options.mqtt_version(version);
}
if let Some(client_id) = raw_create_options.client_id {
create_options = create_options.client_id(client_id);
}
if let Some(persistence) = raw_create_options.persistence {
create_options = create_options.persistence(PersistenceType::FilePath(persistence));
}
if let Some(max_buffered_messages) = raw_create_options.max_buffered_messages {
create_options = create_options.max_buffered_messages(max_buffered_messages);
}
if let Some(send_while_disconnected) = raw_create_options.send_while_disconnected {
create_options = create_options.send_while_disconnected(send_while_disconnected);
}
if let Some(allow_disconnected_send_at_anytime) =
raw_create_options.allow_disconnected_send_at_anytime
{
create_options = create_options
.allow_disconnected_send_at_anytime(allow_disconnected_send_at_anytime);
}
if let Some(delete_oldest_messages) = raw_create_options.delete_oldest_messages {
create_options = create_options.delete_oldest_messages(delete_oldest_messages);
}
if let Some(restore_messages) = raw_create_options.restore_messages {
create_options = create_options.restore_messages(restore_messages);
}
if let Some(persist_qos0) = raw_create_options.persist_qos0 {
create_options = create_options.persist_qos0(persist_qos0);
}
let create_options = create_options.finalize();
let connections = raw_connections
.into_iter()
.map(|raw_connection| {
let mut connection = ConnectOptionsBuilder::default();
connection.server_uris(&raw_connection.server_uris);
connection.finalize()
})
.collect();
Ok(MqttConfig {
create_options,
connections,
buffer_size,
})
}
}
Definitely ugly and error prone but it gets the job done.
As the title says, both of these structures could benefit from Serialization/De-serialization capabilities. This can be useful on config files, for example.