Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: Implement serde::Deserialize and serde::Serialize for CreateOptions and Connect options #221

Open
Altair-Bueno opened this issue Feb 12, 2024 · 2 comments

Comments

@Altair-Bueno
Copy link

As the title says, both of these structures could benefit from Serialization/De-serialization capabilities. This can be useful on config files, for example.

@fpagliughi
Copy link
Contributor

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.

@Altair-Bueno
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants