Expand description
ยงMQTT Typed Client
ยง๐ฆ MQTT Typed Client
A type-safe async MQTT client built on top of rumqttc
Automatic topic routing and subscription management with compile-time guarantees
ยงโจ Key Features
- Type-safe topic patterns with named parameters and automatic parsing
- Zero-cost abstractions via procedural macros with compile-time validation
- IDE-friendly experience - full autocomplete for topics, parameters, and generated client methods
- Automatic subscription management with intelligent routing and lifecycle handling
- Built-in serialization support for 8+ formats (Bincode, JSON, MessagePack, etc.)
- Efficient message routing with tree-based topic matching and internal caching
- Smart defaults with full configurability when needed
- Memory efficient design with proper resource management
- Automatic reconnection and graceful shutdown
โ ๏ธ MSRV: Rust 1.85.1 (driven by default bincode
serializer; can be lowered with alternative serializers)
ยง๐ Quick Start
Add to your Cargo.toml
:
[dependencies]
mqtt-typed-client = "0.1.0"
use mqtt_typed_client::prelude::*;
use mqtt_typed_client_macros::mqtt_topic;
use serde::{Deserialize, Serialize};
use bincode::{Encode, Decode};
#[derive(Serialize, Deserialize, Encode, Decode, Debug)]
enum SensorStatus {
Active,
Inactive,
Maintenance,
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug)]
struct SensorReading {
temperature: f64,
status: SensorStatus, // enum field
location_note: String, // string field for variety
}
// Define typed topic with automatic parameter extraction
#[mqtt_topic("sensors/{location}/{device_id}/data")]
struct SensorTopic {
location: String, // String parameter
device_id: u32, // Numeric parameter - automatic conversion!
payload: SensorReading,
}
#[tokio::main]
async fn main() -> Result<()> {
// Connect to MQTT broker
let (client, connection) = MqttClient::<BincodeSerializer>::connect(
"mqtt://broker.hivemq.com:1883"
).await?;
// Get typed client for this specific topic - method generated by macro
// Returns a typed client for publishing and subscribing to messages
// with automatic parameter handling for this topic pattern
let topic_client = client.sensor_topic();
// Subscribe to all matching topics: "sensors/+/+/data"
// Returns typed subscriber that automatically extracts and converts
// topic parameters into struct fields
let mut subscriber = topic_client.subscribe().await?;
let reading = SensorReading {
temperature: 22.5,
status: SensorStatus::Active,
location_note: "Kitchen sensor near window".to_string(),
};
// Publish with automatic type conversion to specific topic: "sensors/kitchen/42/data"
// Parameters are automatically converted to strings and inserted into topic pattern
topic_client.publish("kitchen", 42u32, &reading).await?;
// ^^^^^^^^ ^^^^^
// String u32 -> automatically converts to "42" in topic
// Receive with automatic parameter extraction and conversion
if let Some(Ok(msg)) = subscriber.receive().await {
println!("Device {} in location '{}' reported: temp={}ยฐC, status={:?}",
msg.device_id, // u32 (converted from "42" in topic)
msg.location, // String (extracted from topic)
msg.payload.temperature, msg.payload.status);
}
connection.shutdown().await?;
Ok(())
}
ยง๐ Examples
See crate::examples
- Complete usage examples with source code
000_hello_world.rs
- Basic publish/subscribe with macros001_ping_pong.rs
- Multi-client communication002_configuration.rs
- Advanced client configuration003_hello_world_lwt.rs
- Last Will & Testament004_hello_world_tls.rs
- TLS/SSL connections005_hello_world_serializers.rs
- Custom serializers006_retain_and_clear.rs
- Retained messages007_custom_patterns.rs
- Custom topic patterns008_modular_example.rs
- Modular application structure
Run examples:
cargo run --example 000_hello_world
ยง๐ฆ Serialization Support
Multiple serialization formats are supported via feature flags:
bincode
- Binary serialization (default, most efficient)json
- JSON serialization (default, human-readable)messagepack
- MessagePack binary formatcbor
- CBOR binary formatpostcard
- Embedded-friendly binary formatron
- Rusty Object Notationflexbuffers
- FlatBuffers FlexBuffersprotobuf
- Protocol Buffers (requires generated types)
Enable additional serializers:
[dependencies]
mqtt-typed-client = { version = "0.1.0", features = ["messagepack", "cbor"] }
Custom serializers can be implemented by implementing the MessageSerializer
trait.
ยง๐ฏ Topic Pattern Matching
Supports MQTT wildcard patterns with named parameters:
{param}
- Named parameter (equivalent to+
wildcard){param:#}
- Multi-level named parameter (equivalent to#
wildcard)
use mqtt_typed_client_macros::mqtt_topic;
// Traditional MQTT wildcards
#[mqtt_topic("home/+/temperature")] // matches: home/kitchen/temperature
struct SimplePattern { payload: f64 }
// Named parameters (recommended)
#[mqtt_topic("home/{room}/temperature")] // matches: home/kitchen/temperature
struct NamedPattern {
room: String, // Automatically extracted: "kitchen"
payload: f64
}
// Multi-level parameters
#[mqtt_topic("logs/{service}/{path:#}")] // matches: logs/api/v1/users/create
struct LogPattern {
service: String, // "api"
path: String, // "v1/users/create"
payload: String // Changed from Data to String
}
ยง๐ง Advanced Usage: Low-Level API
For cases where you need direct control without macros:
use mqtt_typed_client::prelude::*;
use serde::{Deserialize, Serialize};
use bincode::{Encode, Decode};
#[derive(Serialize, Deserialize, Encode, Decode, Debug)]
struct SensorData {
temperature: f64,
humidity: f64,
}
#[tokio::main]
async fn main() -> Result<()> {
let (client, connection) = MqttClient::<BincodeSerializer>::connect(
"mqtt://broker.hivemq.com:1883"
).await?;
// Direct topic operations
let publisher = client.get_publisher::<SensorData>("sensors/temperature")?;
let mut subscriber = client.subscribe::<SensorData>("sensors/+").await?;
let data = SensorData { temperature: 23.5, humidity: 45.0 };
publisher.publish(&data).await?;
if let Some((topic, result)) = subscriber.receive().await {
match result {
Ok(sensor_data) => println!("Received from {}: {:?}", topic.topic_path(), sensor_data),
Err(e) => eprintln!("Deserialization error: {:?}", e),
}
}
connection.shutdown().await?;
Ok(())
}
ยง๐ What mqtt-typed-client adds over rumqttc
Publishing:
// rumqttc - manual topic construction and serialization
let sensor_id = "sensor001";
let data = SensorData { temperature: 23.5 };
let topic = format!("sensors/{}/temperature", sensor_id);
let payload = serde_json::to_vec(&data)?;
client.publish(topic, QoS::AtLeastOnce, false, payload).await?;
// mqtt-typed-client - type-safe, automatic
topic_client.publish(&sensor_id, &data).await?;
Subscribing with routing:
// rumqttc - manual pattern matching and dispatching
// while let Ok(event) = eventloop.poll().await {
// if let Event::Incoming(Packet::Publish(publish)) = event {
// if publish.topic.starts_with("sensors/") {
// // Manual topic parsing, manual deserialization...
// } else if publish.topic.starts_with("alerts/") {
// // More manual parsing...
// }
// }
// }
// mqtt-typed-client - automatic routing to typed handlers
let mut sensor_sub = client.sensor_topic().subscribe().await?;
let mut alert_sub = client.alert_topic().subscribe().await?;
tokio::select! {
msg = sensor_sub.receive() => { /* typed sensor data ready */ }
msg = alert_sub.receive() => { /* typed alert data ready */ }
}
๐ For detailed comparison see: docs/COMPARISON_WITH_RUMQTTC.md
ยง๐ License
This project is licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
ยง๐ค Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
See CONTRIBUTING.md for detailed guidelines.
ยง๐ API Reference
For detailed API documentation, visit docs.rs/mqtt-typed-client.
ยง๐ See Also
- rumqttc - The underlying MQTT client library
- MQTT Protocol Specification - Official MQTT documentation
- Rust Async Book - Guide to async Rust programming
ยงAPI Reference
Key traits and modules:
MessageSerializer
- Custom serialization traitprelude
- Convenient imports for common use casesinfo
- Library metadata and version info
ยงSee Also
crate::comparison
- Detailed comparison with rumqttccrate::examples
- Complete usage examples with source code
Modulesยง
- _macro_
docs - Procedural Macros
- advanced
- Advanced types and utilities for complex use cases
- client
- MQTT client module
- comparison
- Detailed comparison with rumqttc
- connection
- MQTT connection management module
- errors
- Error types used throughout the library
- examples
- Complete usage examples with source code
- info
- Library metadata and version information
- message_
serializer - Message serialization traits and implementations.
- prelude
- Convenient imports for common use cases
- routing
- Message routing and subscription management module
- structured
- Structured MQTT subscribers with automatic topic parameter extraction
- topic
- Topic handling module
Structsยง
- Bincode
Serializer - Default serializer using bincode format.
- Client
Settings - Client-level performance and behavior settings for the MQTT typed client.
- Json
Serializer - JSON serializer using serde_json.
- Mqtt
Client - Type-safe MQTT client with automatic subscription management.
- Mqtt
Client Config - Configuration for MQTT client creation
- Mqtt
Connection - MQTT connection handle for lifecycle management
- Mqtt
Options - Options to configure the behaviour of MQTT connection
- Mqtt
Publisher - Typed MQTT publisher for a specific topic.
- Mqtt
Subscriber - Typed MQTT subscriber for topic patterns.
- Mqtt
Topic Subscriber - Structured MQTT subscriber with automatic topic parameter extraction.
- Subscription
Builder - Immutable builder for configuring MQTT subscriptions
- Subscription
Config - Topic
Pattern Path - Parsed MQTT topic pattern with wildcard support
- Typed
Last Will - Represents a Last Will and Testament (LWT) message for MQTT clients.
Enumsยง
- Cache
Strategy - Message
Conversion Error - Errors that occur during message conversion from MQTT topics.
- Mqtt
Client Error - Errors that can occur in MQTT client operations
- QoS
- Quality of service
- Topic
Error - Comprehensive error type for all topic-related operations
- Topic
Pattern Error - Error types for topic pattern parsing
Constantsยง
Traitsยง
- From
Mqtt Message - Trait for converting MQTT messages into structured types.
- Message
Serializer - Trait for serializing and deserializing MQTT message payloads.
Functionsยง
- extract_
topic_ parameter - Extract and parse a topic parameter by wildcard index
Type Aliasesยง
- Result
- Result type alias for operations that may fail with MqttClientError
Attribute Macrosยง
- mqtt_
topic - Generate a typed MQTT subscriber and/or publisher from a struct and topic pattern